Files
snapd/boot/kernel_os_test.go
Miguel Pires 29c9752d66 many: s/ioutil.WriteFile/os.WriteFile (#13217)
Replace ioutil.WriteFile with os.WriteFile since the former has been
deprecated since go1.16 and simply calls the latter.

Signed-off-by: Miguel Pires <miguel.pires@canonical.com>
2023-09-26 11:38:46 +01:00

805 lines
24 KiB
Go

// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2014-2019 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package boot_test
import (
"errors"
"os"
"path/filepath"
. "gopkg.in/check.v1"
"github.com/snapcore/snapd/boot"
"github.com/snapcore/snapd/boot/boottest"
"github.com/snapcore/snapd/bootloader"
"github.com/snapcore/snapd/dirs"
"github.com/snapcore/snapd/osutil"
"github.com/snapcore/snapd/snap"
"github.com/snapcore/snapd/snap/snapfile"
"github.com/snapcore/snapd/snap/snaptest"
"github.com/snapcore/snapd/testutil"
)
const packageKernel = `
name: ubuntu-kernel
version: 4.0-1
type: kernel
vendor: Someone
`
func (s *bootenvSuite) TestExtractKernelAssetsError(c *C) {
bootloader.ForceError(errors.New("brkn"))
err := boot.NewCoreKernel(&snap.Info{}, boottest.MockDevice("")).ExtractKernelAssets(nil)
c.Check(err, ErrorMatches, `cannot extract kernel assets: brkn`)
}
func (s *bootenvSuite) TestRemoveKernelAssetsError(c *C) {
bootloader.ForceError(errors.New("brkn"))
err := boot.NewCoreKernel(&snap.Info{}, boottest.MockDevice("")).RemoveKernelAssets()
c.Check(err, ErrorMatches, `cannot remove kernel assets: brkn`)
}
func (s *bootenvSuite) TestSetNextBootError(c *C) {
coreDev := boottest.MockDevice("some-snap")
s.bootloader.GetErr = errors.New("zap")
_, err := boot.NewCoreBootParticipant(&snap.Info{}, snap.TypeKernel, coreDev).SetNextBoot(boot.NextBootContext{BootWithoutTry: false})
c.Check(err, ErrorMatches, `cannot set next boot: zap`)
bootloader.ForceError(errors.New("brkn"))
_, err = boot.NewCoreBootParticipant(&snap.Info{}, snap.TypeKernel, coreDev).SetNextBoot(boot.NextBootContext{BootWithoutTry: false})
c.Check(err, ErrorMatches, `cannot set next boot: brkn`)
}
func (s *bootenvSuite) TestSetNextBootForCore(c *C) {
coreDev := boottest.MockDevice("core")
info := &snap.Info{}
info.SnapType = snap.TypeOS
info.RealName = "core"
info.Revision = snap.R(100)
bs := boot.NewCoreBootParticipant(info, info.Type(), coreDev)
rebootInfo, err := bs.SetNextBoot(boot.NextBootContext{BootWithoutTry: false})
c.Assert(err, IsNil)
v, err := s.bootloader.GetBootVars("snap_try_core", "snap_mode")
c.Assert(err, IsNil)
c.Assert(v, DeepEquals, map[string]string{
"snap_try_core": "core_100.snap",
"snap_mode": boot.TryStatus,
})
c.Check(rebootInfo, Equals, boot.RebootInfo{RebootRequired: true})
}
func (s *bootenvSuite) TestSetNextBootWithBaseForCore(c *C) {
coreDev := boottest.MockDevice("core18")
info := &snap.Info{}
info.SnapType = snap.TypeBase
info.RealName = "core18"
info.Revision = snap.R(1818)
bs := boot.NewCoreBootParticipant(info, info.Type(), coreDev)
rebootInfo, err := bs.SetNextBoot(boot.NextBootContext{BootWithoutTry: false})
c.Assert(err, IsNil)
v, err := s.bootloader.GetBootVars("snap_try_core", "snap_mode")
c.Assert(err, IsNil)
c.Assert(v, DeepEquals, map[string]string{
"snap_try_core": "core18_1818.snap",
"snap_mode": boot.TryStatus,
})
c.Check(rebootInfo, Equals, boot.RebootInfo{RebootRequired: true})
}
func (s *bootenvSuite) TestSetNextBootForKernel(c *C) {
coreDev := boottest.MockDevice("krnl")
info := &snap.Info{}
info.SnapType = snap.TypeKernel
info.RealName = "krnl"
info.Revision = snap.R(42)
bp := boot.NewCoreBootParticipant(info, snap.TypeKernel, coreDev)
rebootInfo, err := bp.SetNextBoot(boot.NextBootContext{BootWithoutTry: false})
c.Assert(err, IsNil)
v, err := s.bootloader.GetBootVars("snap_try_kernel", "snap_mode")
c.Assert(err, IsNil)
c.Assert(v, DeepEquals, map[string]string{
"snap_try_kernel": "krnl_42.snap",
"snap_mode": boot.TryStatus,
})
bootVars := map[string]string{
"snap_kernel": "krnl_40.snap",
"snap_try_kernel": "krnl_42.snap"}
s.bootloader.SetBootVars(bootVars)
c.Check(rebootInfo, Equals, boot.RebootInfo{RebootRequired: true})
// simulate good boot
bootVars = map[string]string{"snap_kernel": "krnl_42.snap"}
s.bootloader.SetBootVars(bootVars)
rebootInfo, err = bp.SetNextBoot(boot.NextBootContext{BootWithoutTry: false})
c.Assert(err, IsNil)
c.Check(rebootInfo, Equals, boot.RebootInfo{RebootRequired: false})
}
func (s *bootenv20Suite) TestSetNextBoot20ForKernel(c *C) {
coreDev := boottest.MockUC20Device("", nil)
c.Assert(coreDev.HasModeenv(), Equals, true)
r := setupUC20Bootenv(
c,
s.bootloader,
s.normalDefaultState,
)
defer r()
bs := boot.NewCoreBootParticipant(s.kern2, snap.TypeKernel, coreDev)
c.Assert(bs.IsTrivial(), Equals, false)
rebootInfo, err := bs.SetNextBoot(boot.NextBootContext{BootWithoutTry: false})
c.Assert(err, IsNil)
// check that kernel_status is now try
v, err := s.bootloader.GetBootVars("kernel_status")
c.Assert(err, IsNil)
c.Assert(v, DeepEquals, map[string]string{
"kernel_status": boot.TryStatus,
})
c.Check(rebootInfo, DeepEquals, boot.RebootInfo{
RebootRequired: true,
BootloaderOptions: &bootloader.Options{
Role: bootloader.RoleRunMode,
},
})
// check that SetNextBoot enabled kernel2 as a TryKernel
actual, _ := s.bootloader.GetRunKernelImageFunctionSnapCalls("EnableTryKernel")
c.Assert(actual, DeepEquals, []snap.PlaceInfo{s.kern2})
// also didn't move any try kernels to trusted kernels
actual, _ = s.bootloader.GetRunKernelImageFunctionSnapCalls("EnableKernel")
c.Assert(actual, DeepEquals, []snap.PlaceInfo(nil))
// check that SetNextBoot asked the bootloader for a kernel
_, nKernelCalls := s.bootloader.GetRunKernelImageFunctionSnapCalls("Kernel")
c.Assert(nKernelCalls, Equals, 1)
// and that the modeenv now has this kernel listed
m2, err := boot.ReadModeenv("")
c.Assert(err, IsNil)
c.Assert(m2.CurrentKernels, DeepEquals, []string{s.kern1.Filename(), s.kern2.Filename()})
}
func (s *bootenv20EnvRefKernelSuite) TestSetNextBoot20ForKernel(c *C) {
coreDev := boottest.MockUC20Device("", nil)
c.Assert(coreDev.HasModeenv(), Equals, true)
r := setupUC20Bootenv(
c,
s.bootloader,
s.normalDefaultState,
)
defer r()
bs := boot.NewCoreBootParticipant(s.kern2, snap.TypeKernel, coreDev)
c.Assert(bs.IsTrivial(), Equals, false)
rebootInfo, err := bs.SetNextBoot(boot.NextBootContext{BootWithoutTry: false})
c.Assert(err, IsNil)
m := s.bootloader.BootVars
c.Assert(m, DeepEquals, map[string]string{
"kernel_status": boot.TryStatus,
"snap_try_kernel": s.kern2.Filename(),
"snap_kernel": s.kern1.Filename(),
})
c.Check(rebootInfo, DeepEquals, boot.RebootInfo{
RebootRequired: true,
BootloaderOptions: &bootloader.Options{
Role: bootloader.RoleRunMode,
},
})
// and that the modeenv now has this kernel listed
m2, err := boot.ReadModeenv("")
c.Assert(err, IsNil)
c.Assert(m2.CurrentKernels, DeepEquals, []string{s.kern1.Filename(), s.kern2.Filename()})
}
func (s *bootenvSuite) TestSetNextBootForKernelForTheSameKernel(c *C) {
coreDev := boottest.MockDevice("krnl")
info := &snap.Info{}
info.SnapType = snap.TypeKernel
info.RealName = "krnl"
info.Revision = snap.R(40)
bootVars := map[string]string{"snap_kernel": "krnl_40.snap"}
s.bootloader.SetBootVars(bootVars)
rebootInfo, err := boot.NewCoreBootParticipant(info, snap.TypeKernel, coreDev).SetNextBoot(boot.NextBootContext{BootWithoutTry: false})
c.Assert(err, IsNil)
v, err := s.bootloader.GetBootVars("snap_kernel")
c.Assert(err, IsNil)
c.Assert(v, DeepEquals, map[string]string{
"snap_kernel": "krnl_40.snap",
})
c.Check(rebootInfo, Equals, boot.RebootInfo{RebootRequired: false})
}
func (s *bootenv20Suite) TestSetNextBoot20ForKernelForTheSameKernel(c *C) {
coreDev := boottest.MockUC20Device("", nil)
c.Assert(coreDev.HasModeenv(), Equals, true)
r := setupUC20Bootenv(
c,
s.bootloader,
s.normalDefaultState,
)
defer r()
bs := boot.NewCoreBootParticipant(s.kern1, snap.TypeKernel, coreDev)
c.Assert(bs.IsTrivial(), Equals, false)
rebootInfo, err := bs.SetNextBoot(boot.NextBootContext{BootWithoutTry: false})
c.Assert(err, IsNil)
// check that kernel_status is cleared
v, err := s.bootloader.GetBootVars("kernel_status")
c.Assert(err, IsNil)
c.Assert(v, DeepEquals, map[string]string{
"kernel_status": boot.DefaultStatus,
})
c.Check(rebootInfo, Equals, boot.RebootInfo{RebootRequired: false})
// check that SetNextBoot didn't try to enable any try kernels
actual, _ := s.bootloader.GetRunKernelImageFunctionSnapCalls("EnableTryKernel")
c.Assert(actual, HasLen, 0)
// also didn't move any try kernels to trusted kernels
actual, _ = s.bootloader.GetRunKernelImageFunctionSnapCalls("EnableKernel")
c.Assert(actual, HasLen, 0)
// check that SetNextBoot asked the bootloader for a kernel
_, nKernelCalls := s.bootloader.GetRunKernelImageFunctionSnapCalls("Kernel")
c.Assert(nKernelCalls, Equals, 1)
// and that the modeenv now has this kernel listed
m2, err := boot.ReadModeenv("")
c.Assert(err, IsNil)
c.Assert(m2.CurrentKernels, DeepEquals, []string{s.kern1.Filename()})
}
func (s *bootenv20EnvRefKernelSuite) TestSetNextBoot20ForKernelForTheSameKernel(c *C) {
coreDev := boottest.MockUC20Device("", nil)
c.Assert(coreDev.HasModeenv(), Equals, true)
r := setupUC20Bootenv(
c,
s.bootloader,
s.normalDefaultState,
)
defer r()
bs := boot.NewCoreBootParticipant(s.kern1, snap.TypeKernel, coreDev)
c.Assert(bs.IsTrivial(), Equals, false)
rebootInfo, err := bs.SetNextBoot(boot.NextBootContext{BootWithoutTry: false})
c.Assert(err, IsNil)
// check that kernel_status is cleared
m := s.bootloader.BootVars
c.Assert(m, DeepEquals, map[string]string{
"kernel_status": boot.DefaultStatus,
"snap_kernel": s.kern1.Filename(),
"snap_try_kernel": "",
})
c.Check(rebootInfo, Equals, boot.RebootInfo{RebootRequired: false})
// and that the modeenv now has this kernel listed
m2, err := boot.ReadModeenv("")
c.Assert(err, IsNil)
c.Assert(m2.CurrentKernels, DeepEquals, []string{s.kern1.Filename()})
}
func (s *bootenvSuite) TestSetNextBootForKernelForTheSameKernelTryMode(c *C) {
coreDev := boottest.MockDevice("krnl")
info := &snap.Info{}
info.SnapType = snap.TypeKernel
info.RealName = "krnl"
info.Revision = snap.R(40)
bootVars := map[string]string{
"snap_kernel": "krnl_40.snap",
"snap_try_kernel": "krnl_99.snap",
"snap_mode": boot.TryStatus}
s.bootloader.SetBootVars(bootVars)
rebootInfo, err := boot.NewCoreBootParticipant(info, snap.TypeKernel, coreDev).SetNextBoot(boot.NextBootContext{BootWithoutTry: false})
c.Assert(err, IsNil)
v, err := s.bootloader.GetBootVars("snap_kernel", "snap_try_kernel", "snap_mode")
c.Assert(err, IsNil)
c.Assert(v, DeepEquals, map[string]string{
"snap_kernel": "krnl_40.snap",
"snap_try_kernel": "",
"snap_mode": boot.DefaultStatus,
})
c.Check(rebootInfo, Equals, boot.RebootInfo{RebootRequired: false})
}
func (s *bootenv20Suite) TestSetNextBoot20ForKernelForTheSameKernelTryMode(c *C) {
coreDev := boottest.MockUC20Device("", nil)
c.Assert(coreDev.HasModeenv(), Equals, true)
// set all the same vars as if we were doing trying, except don't set a try
// kernel
r := setupUC20Bootenv(
c,
s.bootloader,
&bootenv20Setup{
modeenv: &boot.Modeenv{
Mode: "run",
Base: s.base1.Filename(),
CurrentKernels: []string{s.kern1.Filename()},
},
kern: s.kern1,
// no try-kernel
kernStatus: boot.TryStatus,
},
)
defer r()
bs := boot.NewCoreBootParticipant(s.kern1, snap.TypeKernel, coreDev)
c.Assert(bs.IsTrivial(), Equals, false)
rebootInfo, err := bs.SetNextBoot(boot.NextBootContext{BootWithoutTry: false})
c.Assert(err, IsNil)
// check that kernel_status is cleared
v, err := s.bootloader.GetBootVars("kernel_status")
c.Assert(err, IsNil)
c.Assert(v, DeepEquals, map[string]string{
"kernel_status": boot.DefaultStatus,
})
c.Check(rebootInfo, Equals, boot.RebootInfo{RebootRequired: false})
// check that SetNextBoot didn't try to enable any try kernels
actual, _ := s.bootloader.GetRunKernelImageFunctionSnapCalls("EnableTryKernel")
c.Assert(actual, HasLen, 0)
// also didn't move any try kernels to trusted kernels
actual, _ = s.bootloader.GetRunKernelImageFunctionSnapCalls("EnableKernel")
c.Assert(actual, HasLen, 0)
// check that SetNextBoot asked the bootloader for a kernel
_, nKernelCalls := s.bootloader.GetRunKernelImageFunctionSnapCalls("Kernel")
c.Assert(nKernelCalls, Equals, 1)
// and that the modeenv didn't change
m2, err := boot.ReadModeenv("")
c.Assert(err, IsNil)
c.Assert(m2.CurrentKernels, DeepEquals, []string{s.kern1.Filename()})
}
func (s *bootenv20EnvRefKernelSuite) TestSetNextBoot20ForKernelForTheSameKernelTryMode(c *C) {
coreDev := boottest.MockUC20Device("", nil)
c.Assert(coreDev.HasModeenv(), Equals, true)
// set all the same vars as if we were doing trying, except don't set a try
// kernel
r := setupUC20Bootenv(
c,
s.bootloader,
&bootenv20Setup{
modeenv: &boot.Modeenv{
Mode: "run",
Base: s.base1.Filename(),
CurrentKernels: []string{s.kern1.Filename()},
},
kern: s.kern1,
// no try-kernel
kernStatus: boot.TryStatus,
},
)
defer r()
bs := boot.NewCoreBootParticipant(s.kern1, snap.TypeKernel, coreDev)
c.Assert(bs.IsTrivial(), Equals, false)
rebootInfo, err := bs.SetNextBoot(boot.NextBootContext{BootWithoutTry: false})
c.Assert(err, IsNil)
// check that kernel_status is cleared
m := s.bootloader.BootVars
c.Assert(m, DeepEquals, map[string]string{
"kernel_status": boot.DefaultStatus,
"snap_kernel": s.kern1.Filename(),
"snap_try_kernel": "",
})
c.Check(rebootInfo, Equals, boot.RebootInfo{RebootRequired: false})
// and that the modeenv didn't change
m2, err := boot.ReadModeenv("")
c.Assert(err, IsNil)
c.Assert(m2.CurrentKernels, DeepEquals, []string{s.kern1.Filename()})
}
type ubootSuite struct {
baseBootenvSuite
}
var _ = Suite(&ubootSuite{})
// forceUbootBootloader sets up a uboot bootloader, in the uc16/uc18 style
// where all env is stored in a single uboot.env
func (s *ubootSuite) forceUbootBootloader(c *C) {
bootloader.Force(nil)
mockGadgetDir := c.MkDir()
// this is testing the uc16/uc18 style uboot bootloader layout, the file
// must be non-empty for uc16/uc18 gadget config install behavior
err := os.WriteFile(filepath.Join(mockGadgetDir, "uboot.conf"), []byte{1}, 0644)
c.Assert(err, IsNil)
err = bootloader.InstallBootConfig(mockGadgetDir, dirs.GlobalRootDir, nil)
c.Assert(err, IsNil)
bloader, err := bootloader.Find("", nil)
c.Assert(err, IsNil)
c.Check(bloader, NotNil)
s.forceBootloader(bloader)
fn := filepath.Join(s.bootdir, "/uboot/uboot.env")
c.Assert(osutil.FileExists(fn), Equals, true)
}
// forceUbootBootloader sets up a uboot bootloader, in the uc20 style where we
// have a separate boot.sel file for snapd specific bootloader env
func (s *ubootSuite) forceUC20UbootBootloader(c *C) {
bootloader.Force(nil)
// for the uboot bootloader InstallBootConfig we pass in
// NoSlashBoot because that's where the gadget assets get
// installed to
installOpts := &bootloader.Options{
Role: bootloader.RoleRunMode,
NoSlashBoot: true,
}
mockGadgetDir := c.MkDir()
// this must be empty for uc20 behavior
// TODO:UC20: update this test for the new behavior when that is implemented
err := os.WriteFile(filepath.Join(mockGadgetDir, "uboot.conf"), nil, 0644)
c.Assert(err, IsNil)
err = bootloader.InstallBootConfig(mockGadgetDir, dirs.GlobalRootDir, installOpts)
c.Assert(err, IsNil)
// in reality for uc20, we will bind mount <ubuntu-boot>/uboot/ubuntu/ onto
// /boot/uboot, so to emulate this at runtime for the tests, just put files
// into "/uboot" under bootdir for the test to see things that on disk are
// at "/uboot/ubuntu" as "/boot/uboot/"
fn := filepath.Join(dirs.GlobalRootDir, "/uboot/ubuntu/boot.sel")
c.Assert(osutil.FileExists(fn), Equals, true)
targetFile := filepath.Join(s.bootdir, "uboot", "boot.sel")
err = os.MkdirAll(filepath.Dir(targetFile), 0755)
c.Assert(err, IsNil)
err = os.Rename(fn, targetFile)
c.Assert(err, IsNil)
// find the run mode bootloader under /boot
runtimeOpts := &bootloader.Options{
Role: bootloader.RoleRunMode,
}
bloader, err := bootloader.Find("", runtimeOpts)
c.Assert(err, IsNil)
c.Check(bloader, NotNil)
s.forceBootloader(bloader)
c.Assert(bloader.Name(), Equals, "uboot")
}
func (s *ubootSuite) TestExtractKernelAssetsAndRemoveOnUboot(c *C) {
// test for both uc16/uc18 style uboot bootloader and for uc20 style bootloader
bloaderSetups := []func(){
func() { s.forceUbootBootloader(c) },
func() { s.forceUC20UbootBootloader(c) },
}
for _, setup := range bloaderSetups {
setup()
files := [][]string{
{"kernel.img", "I'm a kernel"},
{"initrd.img", "...and I'm an initrd"},
{"dtbs/foo.dtb", "g'day, I'm foo.dtb"},
{"dtbs/bar.dtb", "hello, I'm bar.dtb"},
// must be last
{"meta/kernel.yaml", "version: 4.2"},
}
si := &snap.SideInfo{
RealName: "ubuntu-kernel",
Revision: snap.R(42),
}
fn := snaptest.MakeTestSnapWithFiles(c, packageKernel, files)
snapf, err := snapfile.Open(fn)
c.Assert(err, IsNil)
info, err := snap.ReadInfoFromSnapFile(snapf, si)
c.Assert(err, IsNil)
bp := boot.NewCoreKernel(info, boottest.MockDevice(""))
err = bp.ExtractKernelAssets(snapf)
c.Assert(err, IsNil)
// this is where the kernel/initrd is unpacked
kernelAssetsDir := filepath.Join(s.bootdir, "/uboot/ubuntu-kernel_42.snap")
for _, def := range files {
if def[0] == "meta/kernel.yaml" {
break
}
fullFn := filepath.Join(kernelAssetsDir, def[0])
c.Check(fullFn, testutil.FileEquals, def[1])
}
// it's idempotent
err = bp.ExtractKernelAssets(snapf)
c.Assert(err, IsNil)
// remove
err = bp.RemoveKernelAssets()
c.Assert(err, IsNil)
c.Check(osutil.FileExists(kernelAssetsDir), Equals, false)
// it's idempotent
err = bp.RemoveKernelAssets()
c.Assert(err, IsNil)
}
}
type grubSuite struct {
baseBootenvSuite
}
var _ = Suite(&grubSuite{})
func (s *grubSuite) SetUpTest(c *C) {
s.baseBootenvSuite.SetUpTest(c)
s.forceGrubBootloader(c)
}
func (s *grubSuite) forceGrubBootloader(c *C) bootloader.Bootloader {
bootloader.Force(nil)
// make mock grub bootenv dir
mockGadgetDir := c.MkDir()
err := os.WriteFile(filepath.Join(mockGadgetDir, "grub.conf"), nil, 0644)
c.Assert(err, IsNil)
err = bootloader.InstallBootConfig(mockGadgetDir, dirs.GlobalRootDir, nil)
c.Assert(err, IsNil)
bloader, err := bootloader.Find("", nil)
c.Assert(err, IsNil)
c.Check(bloader, NotNil)
bloader.SetBootVars(map[string]string{
"snap_kernel": "kernel_41.snap",
"snap_core": "core_21.snap",
})
s.forceBootloader(bloader)
fn := filepath.Join(s.bootdir, "/grub/grub.cfg")
c.Assert(osutil.FileExists(fn), Equals, true)
return bloader
}
func (s *grubSuite) TestExtractKernelAssetsNoUnpacksKernelForGrub(c *C) {
files := [][]string{
{"kernel.img", "I'm a kernel"},
{"initrd.img", "...and I'm an initrd"},
{"meta/kernel.yaml", "version: 4.2"},
}
si := &snap.SideInfo{
RealName: "ubuntu-kernel",
Revision: snap.R(42),
}
fn := snaptest.MakeTestSnapWithFiles(c, packageKernel, files)
snapf, err := snapfile.Open(fn)
c.Assert(err, IsNil)
info, err := snap.ReadInfoFromSnapFile(snapf, si)
c.Assert(err, IsNil)
bp := boot.NewCoreKernel(info, boottest.MockDevice(""))
err = bp.ExtractKernelAssets(snapf)
c.Assert(err, IsNil)
// kernel is *not* here
kernimg := filepath.Join(s.bootdir, "grub", "ubuntu-kernel_42.snap", "kernel.img")
c.Assert(osutil.FileExists(kernimg), Equals, false)
// it's idempotent
err = bp.ExtractKernelAssets(snapf)
c.Assert(err, IsNil)
}
func (s *grubSuite) TestExtractKernelForceWorks(c *C) {
files := [][]string{
{"kernel.img", "I'm a kernel"},
{"initrd.img", "...and I'm an initrd"},
{"meta/force-kernel-extraction", ""},
{"meta/kernel.yaml", "version: 4.2"},
}
si := &snap.SideInfo{
RealName: "ubuntu-kernel",
Revision: snap.R(42),
}
fn := snaptest.MakeTestSnapWithFiles(c, packageKernel, files)
snapf, err := snapfile.Open(fn)
c.Assert(err, IsNil)
info, err := snap.ReadInfoFromSnapFile(snapf, si)
c.Assert(err, IsNil)
bp := boot.NewCoreKernel(info, boottest.MockDevice(""))
err = bp.ExtractKernelAssets(snapf)
c.Assert(err, IsNil)
// kernel is extracted
kernimg := filepath.Join(s.bootdir, "/grub/ubuntu-kernel_42.snap/kernel.img")
c.Assert(osutil.FileExists(kernimg), Equals, true)
// initrd
initrdimg := filepath.Join(s.bootdir, "/grub/ubuntu-kernel_42.snap/initrd.img")
c.Assert(osutil.FileExists(initrdimg), Equals, true)
// it's idempotent
err = bp.ExtractKernelAssets(snapf)
c.Assert(err, IsNil)
// ensure that removal of assets also works
err = bp.RemoveKernelAssets()
c.Assert(err, IsNil)
exists, _, err := osutil.DirExists(filepath.Dir(kernimg))
c.Assert(err, IsNil)
c.Check(exists, Equals, false)
// it's idempotent
err = bp.RemoveKernelAssets()
c.Assert(err, IsNil)
}
func (s *bootenv20RebootBootloaderSuite) TestSetNextBoot20ForKernel(c *C) {
coreDev := boottest.MockUC20Device("", nil)
c.Assert(coreDev.HasModeenv(), Equals, true)
r := setupUC20Bootenv(
c,
s.bootloader,
s.normalDefaultState,
)
defer r()
bs := boot.NewCoreBootParticipant(s.kern2, snap.TypeKernel, coreDev)
c.Assert(bs.IsTrivial(), Equals, false)
rebootInfo, err := bs.SetNextBoot(boot.NextBootContext{BootWithoutTry: false})
c.Assert(err, IsNil)
m := s.bootloader.BootVars
c.Assert(m, DeepEquals, map[string]string{
"kernel_status": boot.TryStatus,
"snap_try_kernel": s.kern2.Filename(),
"snap_kernel": s.kern1.Filename(),
})
c.Assert(rebootInfo.RebootRequired, Equals, true)
// Test that we get the bootloader options
c.Assert(rebootInfo.BootloaderOptions, DeepEquals, &bootloader.Options{Role: bootloader.RoleRunMode})
// and that the modeenv now has this kernel listed
m2, err := boot.ReadModeenv("")
c.Assert(err, IsNil)
c.Assert(m2.CurrentKernels, DeepEquals, []string{s.kern1.Filename(), s.kern2.Filename()})
}
func (s *bootenvSuite) TestSetNextBootForCoreUndo(c *C) {
coreDev := boottest.MockDevice("core")
info := &snap.Info{}
info.SnapType = snap.TypeOS
info.RealName = "core"
info.Revision = snap.R(100)
bs := boot.NewCoreBootParticipant(info, info.Type(), coreDev)
rebootInfo, err := bs.SetNextBoot(boot.NextBootContext{BootWithoutTry: true})
c.Assert(err, IsNil)
v, err := s.bootloader.GetBootVars("snap_core", "snap_try_core", "snap_mode")
c.Assert(err, IsNil)
c.Assert(v, DeepEquals, map[string]string{
"snap_core": "core_100.snap",
"snap_try_core": "",
"snap_mode": boot.DefaultStatus,
})
c.Check(rebootInfo, Equals, boot.RebootInfo{RebootRequired: true})
}
func (s *bootenvSuite) TestSetNextBootWithBaseForCoreUndo(c *C) {
coreDev := boottest.MockDevice("core18")
info := &snap.Info{}
info.SnapType = snap.TypeBase
info.RealName = "core18"
info.Revision = snap.R(1818)
bs := boot.NewCoreBootParticipant(info, info.Type(), coreDev)
rebootInfo, err := bs.SetNextBoot(boot.NextBootContext{BootWithoutTry: true})
c.Assert(err, IsNil)
v, err := s.bootloader.GetBootVars("snap_core", "snap_try_core", "snap_mode")
c.Assert(err, IsNil)
c.Assert(v, DeepEquals, map[string]string{
"snap_core": "core18_1818.snap",
"snap_try_core": "",
"snap_mode": boot.DefaultStatus,
})
c.Check(rebootInfo, Equals, boot.RebootInfo{RebootRequired: true})
}
func (s *bootenvSuite) TestSetNextBootForKernelUndo(c *C) {
coreDev := boottest.MockDevice("krnl")
info := &snap.Info{}
info.SnapType = snap.TypeKernel
info.RealName = "krnl"
info.Revision = snap.R(42)
bp := boot.NewCoreBootParticipant(info, snap.TypeKernel, coreDev)
rebootInfo, err := bp.SetNextBoot(boot.NextBootContext{BootWithoutTry: true})
c.Assert(err, IsNil)
v, err := s.bootloader.GetBootVars("snap_kernel", "snap_try_kernel", "snap_mode")
c.Assert(err, IsNil)
c.Assert(v, DeepEquals, map[string]string{
"snap_kernel": "krnl_42.snap",
"snap_try_kernel": "",
"snap_mode": boot.DefaultStatus,
})
c.Check(rebootInfo, Equals, boot.RebootInfo{RebootRequired: true})
}