github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/boot/kernel_os_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2014-2019 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 boot_test 21 22 import ( 23 "errors" 24 "io/ioutil" 25 "os" 26 "path/filepath" 27 28 . "gopkg.in/check.v1" 29 30 "github.com/snapcore/snapd/boot" 31 "github.com/snapcore/snapd/boot/boottest" 32 "github.com/snapcore/snapd/bootloader" 33 "github.com/snapcore/snapd/dirs" 34 "github.com/snapcore/snapd/osutil" 35 "github.com/snapcore/snapd/snap" 36 "github.com/snapcore/snapd/snap/snapfile" 37 "github.com/snapcore/snapd/snap/snaptest" 38 "github.com/snapcore/snapd/testutil" 39 ) 40 41 const packageKernel = ` 42 name: ubuntu-kernel 43 version: 4.0-1 44 type: kernel 45 vendor: Someone 46 ` 47 48 func (s *bootenvSuite) TestExtractKernelAssetsError(c *C) { 49 bootloader.ForceError(errors.New("brkn")) 50 err := boot.NewCoreKernel(&snap.Info{}, boottest.MockDevice("")).ExtractKernelAssets(nil) 51 c.Check(err, ErrorMatches, `cannot extract kernel assets: brkn`) 52 } 53 54 func (s *bootenvSuite) TestRemoveKernelAssetsError(c *C) { 55 bootloader.ForceError(errors.New("brkn")) 56 err := boot.NewCoreKernel(&snap.Info{}, boottest.MockDevice("")).RemoveKernelAssets() 57 c.Check(err, ErrorMatches, `cannot remove kernel assets: brkn`) 58 } 59 60 func (s *bootenvSuite) TestSetNextBootError(c *C) { 61 coreDev := boottest.MockDevice("some-snap") 62 63 s.bootloader.GetErr = errors.New("zap") 64 _, err := boot.NewCoreBootParticipant(&snap.Info{}, snap.TypeKernel, coreDev).SetNextBoot() 65 c.Check(err, ErrorMatches, `cannot set next boot: zap`) 66 67 bootloader.ForceError(errors.New("brkn")) 68 _, err = boot.NewCoreBootParticipant(&snap.Info{}, snap.TypeKernel, coreDev).SetNextBoot() 69 c.Check(err, ErrorMatches, `cannot set next boot: brkn`) 70 } 71 72 func (s *bootenvSuite) TestSetNextBootForCore(c *C) { 73 coreDev := boottest.MockDevice("core") 74 75 info := &snap.Info{} 76 info.SnapType = snap.TypeOS 77 info.RealName = "core" 78 info.Revision = snap.R(100) 79 80 bs := boot.NewCoreBootParticipant(info, info.Type(), coreDev) 81 reboot, err := bs.SetNextBoot() 82 c.Assert(err, IsNil) 83 84 v, err := s.bootloader.GetBootVars("snap_try_core", "snap_mode") 85 c.Assert(err, IsNil) 86 c.Assert(v, DeepEquals, map[string]string{ 87 "snap_try_core": "core_100.snap", 88 "snap_mode": boot.TryStatus, 89 }) 90 91 c.Check(reboot, Equals, true) 92 } 93 94 func (s *bootenvSuite) TestSetNextBootWithBaseForCore(c *C) { 95 coreDev := boottest.MockDevice("core18") 96 97 info := &snap.Info{} 98 info.SnapType = snap.TypeBase 99 info.RealName = "core18" 100 info.Revision = snap.R(1818) 101 102 bs := boot.NewCoreBootParticipant(info, info.Type(), coreDev) 103 reboot, err := bs.SetNextBoot() 104 c.Assert(err, IsNil) 105 106 v, err := s.bootloader.GetBootVars("snap_try_core", "snap_mode") 107 c.Assert(err, IsNil) 108 c.Assert(v, DeepEquals, map[string]string{ 109 "snap_try_core": "core18_1818.snap", 110 "snap_mode": boot.TryStatus, 111 }) 112 113 c.Check(reboot, Equals, true) 114 } 115 116 func (s *bootenvSuite) TestSetNextBootForKernel(c *C) { 117 coreDev := boottest.MockDevice("krnl") 118 119 info := &snap.Info{} 120 info.SnapType = snap.TypeKernel 121 info.RealName = "krnl" 122 info.Revision = snap.R(42) 123 124 bp := boot.NewCoreBootParticipant(info, snap.TypeKernel, coreDev) 125 reboot, err := bp.SetNextBoot() 126 c.Assert(err, IsNil) 127 128 v, err := s.bootloader.GetBootVars("snap_try_kernel", "snap_mode") 129 c.Assert(err, IsNil) 130 c.Assert(v, DeepEquals, map[string]string{ 131 "snap_try_kernel": "krnl_42.snap", 132 "snap_mode": boot.TryStatus, 133 }) 134 135 bootVars := map[string]string{ 136 "snap_kernel": "krnl_40.snap", 137 "snap_try_kernel": "krnl_42.snap"} 138 s.bootloader.SetBootVars(bootVars) 139 c.Check(reboot, Equals, true) 140 141 // simulate good boot 142 bootVars = map[string]string{"snap_kernel": "krnl_42.snap"} 143 s.bootloader.SetBootVars(bootVars) 144 145 reboot, err = bp.SetNextBoot() 146 c.Assert(err, IsNil) 147 c.Check(reboot, Equals, false) 148 } 149 150 func (s *bootenv20Suite) TestSetNextBoot20ForKernel(c *C) { 151 coreDev := boottest.MockUC20Device("pc-kernel") 152 c.Assert(coreDev.HasModeenv(), Equals, true) 153 154 r := setupUC20Bootenv( 155 c, 156 s.bootloader, 157 s.normalDefaultState, 158 ) 159 defer r() 160 161 bs := boot.NewCoreBootParticipant(s.kern2, snap.TypeKernel, coreDev) 162 c.Assert(bs.IsTrivial(), Equals, false) 163 reboot, err := bs.SetNextBoot() 164 c.Assert(err, IsNil) 165 166 // check that kernel_status is now try 167 v, err := s.bootloader.GetBootVars("kernel_status") 168 c.Assert(err, IsNil) 169 c.Assert(v, DeepEquals, map[string]string{ 170 "kernel_status": boot.TryStatus, 171 }) 172 173 c.Check(reboot, Equals, true) 174 175 // check that SetNextBoot enabled kernel2 as a TryKernel 176 actual, _ := s.bootloader.GetRunKernelImageFunctionSnapCalls("EnableTryKernel") 177 c.Assert(actual, DeepEquals, []snap.PlaceInfo{s.kern2}) 178 179 // also didn't move any try kernels to trusted kernels 180 actual, _ = s.bootloader.GetRunKernelImageFunctionSnapCalls("EnableKernel") 181 c.Assert(actual, DeepEquals, []snap.PlaceInfo(nil)) 182 183 // check that SetNextBoot asked the bootloader for a kernel 184 _, nKernelCalls := s.bootloader.GetRunKernelImageFunctionSnapCalls("Kernel") 185 c.Assert(nKernelCalls, Equals, 1) 186 187 // and that the modeenv now has this kernel listed 188 m2, err := boot.ReadModeenv("") 189 c.Assert(err, IsNil) 190 c.Assert(m2.CurrentKernels, DeepEquals, []string{s.kern1.Filename(), s.kern2.Filename()}) 191 } 192 193 func (s *bootenv20EnvRefKernelSuite) TestSetNextBoot20ForKernel(c *C) { 194 coreDev := boottest.MockUC20Device("pc-kernel") 195 c.Assert(coreDev.HasModeenv(), Equals, true) 196 197 r := setupUC20Bootenv( 198 c, 199 s.bootloader, 200 s.normalDefaultState, 201 ) 202 defer r() 203 204 bs := boot.NewCoreBootParticipant(s.kern2, snap.TypeKernel, coreDev) 205 c.Assert(bs.IsTrivial(), Equals, false) 206 reboot, err := bs.SetNextBoot() 207 c.Assert(err, IsNil) 208 209 m := s.bootloader.BootVars 210 c.Assert(m, DeepEquals, map[string]string{ 211 "kernel_status": boot.TryStatus, 212 "snap_try_kernel": s.kern2.Filename(), 213 "snap_kernel": s.kern1.Filename(), 214 }) 215 216 c.Check(reboot, Equals, true) 217 218 // and that the modeenv now has this kernel listed 219 m2, err := boot.ReadModeenv("") 220 c.Assert(err, IsNil) 221 c.Assert(m2.CurrentKernels, DeepEquals, []string{s.kern1.Filename(), s.kern2.Filename()}) 222 } 223 224 func (s *bootenvSuite) TestSetNextBootForKernelForTheSameKernel(c *C) { 225 coreDev := boottest.MockDevice("krnl") 226 227 info := &snap.Info{} 228 info.SnapType = snap.TypeKernel 229 info.RealName = "krnl" 230 info.Revision = snap.R(40) 231 232 bootVars := map[string]string{"snap_kernel": "krnl_40.snap"} 233 s.bootloader.SetBootVars(bootVars) 234 235 reboot, err := boot.NewCoreBootParticipant(info, snap.TypeKernel, coreDev).SetNextBoot() 236 c.Assert(err, IsNil) 237 238 v, err := s.bootloader.GetBootVars("snap_kernel") 239 c.Assert(err, IsNil) 240 c.Assert(v, DeepEquals, map[string]string{ 241 "snap_kernel": "krnl_40.snap", 242 }) 243 244 c.Check(reboot, Equals, false) 245 } 246 247 func (s *bootenv20Suite) TestSetNextBoot20ForKernelForTheSameKernel(c *C) { 248 coreDev := boottest.MockUC20Device("pc-kernel") 249 c.Assert(coreDev.HasModeenv(), Equals, true) 250 251 r := setupUC20Bootenv( 252 c, 253 s.bootloader, 254 s.normalDefaultState, 255 ) 256 defer r() 257 258 bs := boot.NewCoreBootParticipant(s.kern1, snap.TypeKernel, coreDev) 259 c.Assert(bs.IsTrivial(), Equals, false) 260 reboot, err := bs.SetNextBoot() 261 c.Assert(err, IsNil) 262 263 // check that kernel_status is cleared 264 v, err := s.bootloader.GetBootVars("kernel_status") 265 c.Assert(err, IsNil) 266 c.Assert(v, DeepEquals, map[string]string{ 267 "kernel_status": boot.DefaultStatus, 268 }) 269 270 c.Check(reboot, Equals, false) 271 272 // check that SetNextBoot didn't try to enable any try kernels 273 actual, _ := s.bootloader.GetRunKernelImageFunctionSnapCalls("EnableTryKernel") 274 c.Assert(actual, HasLen, 0) 275 276 // also didn't move any try kernels to trusted kernels 277 actual, _ = s.bootloader.GetRunKernelImageFunctionSnapCalls("EnableKernel") 278 c.Assert(actual, HasLen, 0) 279 280 // check that SetNextBoot asked the bootloader for a kernel 281 _, nKernelCalls := s.bootloader.GetRunKernelImageFunctionSnapCalls("Kernel") 282 c.Assert(nKernelCalls, Equals, 1) 283 284 // and that the modeenv now has this kernel listed 285 m2, err := boot.ReadModeenv("") 286 c.Assert(err, IsNil) 287 c.Assert(m2.CurrentKernels, DeepEquals, []string{s.kern1.Filename()}) 288 } 289 290 func (s *bootenv20EnvRefKernelSuite) TestSetNextBoot20ForKernelForTheSameKernel(c *C) { 291 coreDev := boottest.MockUC20Device("pc-kernel") 292 c.Assert(coreDev.HasModeenv(), Equals, true) 293 294 r := setupUC20Bootenv( 295 c, 296 s.bootloader, 297 s.normalDefaultState, 298 ) 299 defer r() 300 301 bs := boot.NewCoreBootParticipant(s.kern1, snap.TypeKernel, coreDev) 302 c.Assert(bs.IsTrivial(), Equals, false) 303 reboot, err := bs.SetNextBoot() 304 c.Assert(err, IsNil) 305 306 // check that kernel_status is cleared 307 m := s.bootloader.BootVars 308 c.Assert(m, DeepEquals, map[string]string{ 309 "kernel_status": boot.DefaultStatus, 310 "snap_kernel": s.kern1.Filename(), 311 "snap_try_kernel": "", 312 }) 313 314 c.Check(reboot, Equals, false) 315 316 // and that the modeenv now has this kernel listed 317 m2, err := boot.ReadModeenv("") 318 c.Assert(err, IsNil) 319 c.Assert(m2.CurrentKernels, DeepEquals, []string{s.kern1.Filename()}) 320 } 321 322 func (s *bootenvSuite) TestSetNextBootForKernelForTheSameKernelTryMode(c *C) { 323 coreDev := boottest.MockDevice("krnl") 324 325 info := &snap.Info{} 326 info.SnapType = snap.TypeKernel 327 info.RealName = "krnl" 328 info.Revision = snap.R(40) 329 330 bootVars := map[string]string{ 331 "snap_kernel": "krnl_40.snap", 332 "snap_try_kernel": "krnl_99.snap", 333 "snap_mode": boot.TryStatus} 334 s.bootloader.SetBootVars(bootVars) 335 336 reboot, err := boot.NewCoreBootParticipant(info, snap.TypeKernel, coreDev).SetNextBoot() 337 c.Assert(err, IsNil) 338 339 v, err := s.bootloader.GetBootVars("snap_kernel", "snap_try_kernel", "snap_mode") 340 c.Assert(err, IsNil) 341 c.Assert(v, DeepEquals, map[string]string{ 342 "snap_kernel": "krnl_40.snap", 343 "snap_try_kernel": "", 344 "snap_mode": boot.DefaultStatus, 345 }) 346 347 c.Check(reboot, Equals, false) 348 } 349 350 func (s *bootenv20Suite) TestSetNextBoot20ForKernelForTheSameKernelTryMode(c *C) { 351 coreDev := boottest.MockUC20Device("pc-kernel") 352 c.Assert(coreDev.HasModeenv(), Equals, true) 353 354 // set all the same vars as if we were doing trying, except don't set a try 355 // kernel 356 r := setupUC20Bootenv( 357 c, 358 s.bootloader, 359 &bootenv20Setup{ 360 modeenv: &boot.Modeenv{ 361 Mode: "run", 362 Base: s.base1.Filename(), 363 CurrentKernels: []string{s.kern1.Filename()}, 364 }, 365 kern: s.kern1, 366 // no try-kernel 367 kernStatus: boot.TryStatus, 368 }, 369 ) 370 defer r() 371 372 bs := boot.NewCoreBootParticipant(s.kern1, snap.TypeKernel, coreDev) 373 c.Assert(bs.IsTrivial(), Equals, false) 374 reboot, err := bs.SetNextBoot() 375 c.Assert(err, IsNil) 376 377 // check that kernel_status is cleared 378 v, err := s.bootloader.GetBootVars("kernel_status") 379 c.Assert(err, IsNil) 380 c.Assert(v, DeepEquals, map[string]string{ 381 "kernel_status": boot.DefaultStatus, 382 }) 383 384 c.Check(reboot, Equals, false) 385 386 // check that SetNextBoot didn't try to enable any try kernels 387 actual, _ := s.bootloader.GetRunKernelImageFunctionSnapCalls("EnableTryKernel") 388 c.Assert(actual, HasLen, 0) 389 390 // also didn't move any try kernels to trusted kernels 391 actual, _ = s.bootloader.GetRunKernelImageFunctionSnapCalls("EnableKernel") 392 c.Assert(actual, HasLen, 0) 393 394 // check that SetNextBoot asked the bootloader for a kernel 395 _, nKernelCalls := s.bootloader.GetRunKernelImageFunctionSnapCalls("Kernel") 396 c.Assert(nKernelCalls, Equals, 1) 397 398 // and that the modeenv didn't change 399 m2, err := boot.ReadModeenv("") 400 c.Assert(err, IsNil) 401 c.Assert(m2.CurrentKernels, DeepEquals, []string{s.kern1.Filename()}) 402 } 403 404 func (s *bootenv20EnvRefKernelSuite) TestSetNextBoot20ForKernelForTheSameKernelTryMode(c *C) { 405 coreDev := boottest.MockUC20Device("pc-kernel") 406 c.Assert(coreDev.HasModeenv(), Equals, true) 407 408 // set all the same vars as if we were doing trying, except don't set a try 409 // kernel 410 r := setupUC20Bootenv( 411 c, 412 s.bootloader, 413 &bootenv20Setup{ 414 modeenv: &boot.Modeenv{ 415 Mode: "run", 416 Base: s.base1.Filename(), 417 CurrentKernels: []string{s.kern1.Filename()}, 418 }, 419 kern: s.kern1, 420 // no try-kernel 421 kernStatus: boot.TryStatus, 422 }, 423 ) 424 defer r() 425 426 bs := boot.NewCoreBootParticipant(s.kern1, snap.TypeKernel, coreDev) 427 c.Assert(bs.IsTrivial(), Equals, false) 428 reboot, err := bs.SetNextBoot() 429 c.Assert(err, IsNil) 430 431 // check that kernel_status is cleared 432 m := s.bootloader.BootVars 433 c.Assert(m, DeepEquals, map[string]string{ 434 "kernel_status": boot.DefaultStatus, 435 "snap_kernel": s.kern1.Filename(), 436 "snap_try_kernel": "", 437 }) 438 439 c.Check(reboot, Equals, false) 440 441 // and that the modeenv didn't change 442 m2, err := boot.ReadModeenv("") 443 c.Assert(err, IsNil) 444 c.Assert(m2.CurrentKernels, DeepEquals, []string{s.kern1.Filename()}) 445 } 446 447 type ubootSuite struct { 448 baseBootenvSuite 449 } 450 451 var _ = Suite(&ubootSuite{}) 452 453 // forceUbootBootloader sets up a uboot bootloader, in the uc16/uc18 style 454 // where all env is stored in a single uboot.env 455 func (s *ubootSuite) forceUbootBootloader(c *C) { 456 bootloader.Force(nil) 457 458 mockGadgetDir := c.MkDir() 459 // this is testing the uc16/uc18 style uboot bootloader layout, the file 460 // must be non-empty for uc16/uc18 gadget config install behavior 461 err := ioutil.WriteFile(filepath.Join(mockGadgetDir, "uboot.conf"), []byte{1}, 0644) 462 c.Assert(err, IsNil) 463 err = bootloader.InstallBootConfig(mockGadgetDir, dirs.GlobalRootDir, nil) 464 c.Assert(err, IsNil) 465 466 bloader, err := bootloader.Find("", nil) 467 c.Assert(err, IsNil) 468 c.Check(bloader, NotNil) 469 s.forceBootloader(bloader) 470 471 fn := filepath.Join(s.bootdir, "/uboot/uboot.env") 472 c.Assert(osutil.FileExists(fn), Equals, true) 473 } 474 475 // forceUbootBootloader sets up a uboot bootloader, in the uc20 style where we 476 // have a separate boot.sel file for snapd specific bootloader env 477 func (s *ubootSuite) forceUC20UbootBootloader(c *C) { 478 bootloader.Force(nil) 479 480 // for the uboot bootloader InstallBootConfig we pass in 481 // NoSlashBoot because that's where the gadget assets get 482 // installed to 483 installOpts := &bootloader.Options{ 484 Role: bootloader.RoleRunMode, 485 NoSlashBoot: true, 486 } 487 488 mockGadgetDir := c.MkDir() 489 // this must be empty for uc20 behavior 490 // TODO:UC20: update this test for the new behavior when that is implemented 491 err := ioutil.WriteFile(filepath.Join(mockGadgetDir, "uboot.conf"), nil, 0644) 492 c.Assert(err, IsNil) 493 err = bootloader.InstallBootConfig(mockGadgetDir, dirs.GlobalRootDir, installOpts) 494 c.Assert(err, IsNil) 495 496 // in reality for uc20, we will bind mount <ubuntu-boot>/uboot/ubuntu/ onto 497 // /boot/uboot, so to emulate this at runtime for the tests, just put files 498 // into "/uboot" under bootdir for the test to see things that on disk are 499 // at "/uboot/ubuntu" as "/boot/uboot/" 500 501 fn := filepath.Join(dirs.GlobalRootDir, "/uboot/ubuntu/boot.sel") 502 c.Assert(osutil.FileExists(fn), Equals, true) 503 504 targetFile := filepath.Join(s.bootdir, "uboot", "boot.sel") 505 err = os.MkdirAll(filepath.Dir(targetFile), 0755) 506 c.Assert(err, IsNil) 507 err = os.Rename(fn, targetFile) 508 c.Assert(err, IsNil) 509 510 // find the run mode bootloader under /boot 511 runtimeOpts := &bootloader.Options{ 512 Role: bootloader.RoleRunMode, 513 } 514 515 bloader, err := bootloader.Find("", runtimeOpts) 516 c.Assert(err, IsNil) 517 c.Check(bloader, NotNil) 518 s.forceBootloader(bloader) 519 c.Assert(bloader.Name(), Equals, "uboot") 520 } 521 522 func (s *ubootSuite) TestExtractKernelAssetsAndRemoveOnUboot(c *C) { 523 524 // test for both uc16/uc18 style uboot bootloader and for uc20 style bootloader 525 bloaderSetups := []func(){ 526 func() { s.forceUbootBootloader(c) }, 527 func() { s.forceUC20UbootBootloader(c) }, 528 } 529 530 for _, setup := range bloaderSetups { 531 setup() 532 533 files := [][]string{ 534 {"kernel.img", "I'm a kernel"}, 535 {"initrd.img", "...and I'm an initrd"}, 536 {"dtbs/foo.dtb", "g'day, I'm foo.dtb"}, 537 {"dtbs/bar.dtb", "hello, I'm bar.dtb"}, 538 // must be last 539 {"meta/kernel.yaml", "version: 4.2"}, 540 } 541 542 si := &snap.SideInfo{ 543 RealName: "ubuntu-kernel", 544 Revision: snap.R(42), 545 } 546 fn := snaptest.MakeTestSnapWithFiles(c, packageKernel, files) 547 snapf, err := snapfile.Open(fn) 548 c.Assert(err, IsNil) 549 550 info, err := snap.ReadInfoFromSnapFile(snapf, si) 551 c.Assert(err, IsNil) 552 553 bp := boot.NewCoreKernel(info, boottest.MockDevice("")) 554 err = bp.ExtractKernelAssets(snapf) 555 c.Assert(err, IsNil) 556 557 // this is where the kernel/initrd is unpacked 558 kernelAssetsDir := filepath.Join(s.bootdir, "/uboot/ubuntu-kernel_42.snap") 559 for _, def := range files { 560 if def[0] == "meta/kernel.yaml" { 561 break 562 } 563 564 fullFn := filepath.Join(kernelAssetsDir, def[0]) 565 c.Check(fullFn, testutil.FileEquals, def[1]) 566 } 567 568 // it's idempotent 569 err = bp.ExtractKernelAssets(snapf) 570 c.Assert(err, IsNil) 571 572 // remove 573 err = bp.RemoveKernelAssets() 574 c.Assert(err, IsNil) 575 c.Check(osutil.FileExists(kernelAssetsDir), Equals, false) 576 577 // it's idempotent 578 err = bp.RemoveKernelAssets() 579 c.Assert(err, IsNil) 580 581 } 582 583 } 584 585 type grubSuite struct { 586 baseBootenvSuite 587 } 588 589 var _ = Suite(&grubSuite{}) 590 591 func (s *grubSuite) SetUpTest(c *C) { 592 s.baseBootenvSuite.SetUpTest(c) 593 s.forceGrubBootloader(c) 594 } 595 596 func (s *grubSuite) forceGrubBootloader(c *C) bootloader.Bootloader { 597 bootloader.Force(nil) 598 599 // make mock grub bootenv dir 600 mockGadgetDir := c.MkDir() 601 err := ioutil.WriteFile(filepath.Join(mockGadgetDir, "grub.conf"), nil, 0644) 602 c.Assert(err, IsNil) 603 err = bootloader.InstallBootConfig(mockGadgetDir, dirs.GlobalRootDir, nil) 604 c.Assert(err, IsNil) 605 606 bloader, err := bootloader.Find("", nil) 607 c.Assert(err, IsNil) 608 c.Check(bloader, NotNil) 609 bloader.SetBootVars(map[string]string{ 610 "snap_kernel": "kernel_41.snap", 611 "snap_core": "core_21.snap", 612 }) 613 s.forceBootloader(bloader) 614 615 fn := filepath.Join(s.bootdir, "/grub/grub.cfg") 616 c.Assert(osutil.FileExists(fn), Equals, true) 617 return bloader 618 } 619 620 func (s *grubSuite) TestExtractKernelAssetsNoUnpacksKernelForGrub(c *C) { 621 files := [][]string{ 622 {"kernel.img", "I'm a kernel"}, 623 {"initrd.img", "...and I'm an initrd"}, 624 {"meta/kernel.yaml", "version: 4.2"}, 625 } 626 si := &snap.SideInfo{ 627 RealName: "ubuntu-kernel", 628 Revision: snap.R(42), 629 } 630 fn := snaptest.MakeTestSnapWithFiles(c, packageKernel, files) 631 snapf, err := snapfile.Open(fn) 632 c.Assert(err, IsNil) 633 634 info, err := snap.ReadInfoFromSnapFile(snapf, si) 635 c.Assert(err, IsNil) 636 637 bp := boot.NewCoreKernel(info, boottest.MockDevice("")) 638 err = bp.ExtractKernelAssets(snapf) 639 c.Assert(err, IsNil) 640 641 // kernel is *not* here 642 kernimg := filepath.Join(s.bootdir, "grub", "ubuntu-kernel_42.snap", "kernel.img") 643 c.Assert(osutil.FileExists(kernimg), Equals, false) 644 645 // it's idempotent 646 err = bp.ExtractKernelAssets(snapf) 647 c.Assert(err, IsNil) 648 } 649 650 func (s *grubSuite) TestExtractKernelForceWorks(c *C) { 651 files := [][]string{ 652 {"kernel.img", "I'm a kernel"}, 653 {"initrd.img", "...and I'm an initrd"}, 654 {"meta/force-kernel-extraction", ""}, 655 {"meta/kernel.yaml", "version: 4.2"}, 656 } 657 si := &snap.SideInfo{ 658 RealName: "ubuntu-kernel", 659 Revision: snap.R(42), 660 } 661 fn := snaptest.MakeTestSnapWithFiles(c, packageKernel, files) 662 snapf, err := snapfile.Open(fn) 663 c.Assert(err, IsNil) 664 665 info, err := snap.ReadInfoFromSnapFile(snapf, si) 666 c.Assert(err, IsNil) 667 668 bp := boot.NewCoreKernel(info, boottest.MockDevice("")) 669 err = bp.ExtractKernelAssets(snapf) 670 c.Assert(err, IsNil) 671 672 // kernel is extracted 673 kernimg := filepath.Join(s.bootdir, "/grub/ubuntu-kernel_42.snap/kernel.img") 674 c.Assert(osutil.FileExists(kernimg), Equals, true) 675 // initrd 676 initrdimg := filepath.Join(s.bootdir, "/grub/ubuntu-kernel_42.snap/initrd.img") 677 c.Assert(osutil.FileExists(initrdimg), Equals, true) 678 679 // it's idempotent 680 err = bp.ExtractKernelAssets(snapf) 681 c.Assert(err, IsNil) 682 683 // ensure that removal of assets also works 684 err = bp.RemoveKernelAssets() 685 c.Assert(err, IsNil) 686 exists, _, err := osutil.DirExists(filepath.Dir(kernimg)) 687 c.Assert(err, IsNil) 688 c.Check(exists, Equals, false) 689 690 // it's idempotent 691 err = bp.RemoveKernelAssets() 692 c.Assert(err, IsNil) 693 }