github.com/rigado/snapd@v2.42.5-go-mod+incompatible/bootloader/lk_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 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 bootloader_test
    21  
    22  import (
    23  	"io/ioutil"
    24  	"os"
    25  	"path/filepath"
    26  	"sort"
    27  
    28  	. "gopkg.in/check.v1"
    29  
    30  	"github.com/snapcore/snapd/bootloader"
    31  	"github.com/snapcore/snapd/bootloader/lkenv"
    32  	"github.com/snapcore/snapd/osutil"
    33  	"github.com/snapcore/snapd/snap"
    34  	"github.com/snapcore/snapd/snap/snaptest"
    35  )
    36  
    37  type lkTestSuite struct {
    38  	baseBootenvTestSuite
    39  }
    40  
    41  var _ = Suite(&lkTestSuite{})
    42  
    43  func (s *lkTestSuite) TestNewLkNolkReturnsNil(c *C) {
    44  	l := bootloader.NewLk("/does/not/exist", nil)
    45  	c.Assert(l, IsNil)
    46  }
    47  
    48  func (s *lkTestSuite) TestNewLk(c *C) {
    49  	bootloader.MockLkFiles(c, s.rootdir, nil)
    50  	l := bootloader.NewLk(s.rootdir, nil)
    51  	c.Assert(l, NotNil)
    52  	c.Check(bootloader.LkRuntimeMode(l), Equals, true)
    53  	c.Check(l.ConfigFile(), Equals, filepath.Join(s.rootdir, "/dev/disk/by-partlabel", "snapbootsel"))
    54  }
    55  
    56  func (s *lkTestSuite) TestNewLkImageBuildingTime(c *C) {
    57  	opts := &bootloader.Options{
    58  		PrepareImageTime: true,
    59  	}
    60  	bootloader.MockLkFiles(c, s.rootdir, opts)
    61  	l := bootloader.NewLk(s.rootdir, opts)
    62  	c.Assert(l, NotNil)
    63  	c.Check(bootloader.LkRuntimeMode(l), Equals, false)
    64  	c.Check(l.ConfigFile(), Equals, filepath.Join(s.rootdir, "/boot/lk", "snapbootsel.bin"))
    65  }
    66  
    67  func (s *lkTestSuite) TestSetGetBootVar(c *C) {
    68  	bootloader.MockLkFiles(c, s.rootdir, nil)
    69  	l := bootloader.NewLk(s.rootdir, nil)
    70  	bootVars := map[string]string{"snap_mode": "try"}
    71  	l.SetBootVars(bootVars)
    72  
    73  	v, err := l.GetBootVars("snap_mode")
    74  	c.Assert(err, IsNil)
    75  	c.Check(v, HasLen, 1)
    76  	c.Check(v["snap_mode"], Equals, "try")
    77  }
    78  
    79  func (s *lkTestSuite) TestExtractKernelAssetsUnpacksBootimgImageBuilding(c *C) {
    80  	opts := &bootloader.Options{
    81  		PrepareImageTime: true,
    82  	}
    83  	bootloader.MockLkFiles(c, s.rootdir, opts)
    84  	l := bootloader.NewLk(s.rootdir, opts)
    85  
    86  	c.Assert(l, NotNil)
    87  
    88  	files := [][]string{
    89  		{"kernel.img", "I'm a kernel"},
    90  		{"initrd.img", "...and I'm an initrd"},
    91  		{"boot.img", "...and I'm an boot image"},
    92  		{"dtbs/foo.dtb", "g'day, I'm foo.dtb"},
    93  		{"dtbs/bar.dtb", "hello, I'm bar.dtb"},
    94  		// must be last
    95  		{"meta/kernel.yaml", "version: 4.2"},
    96  	}
    97  	si := &snap.SideInfo{
    98  		RealName: "ubuntu-kernel",
    99  		Revision: snap.R(42),
   100  	}
   101  	fn := snaptest.MakeTestSnapWithFiles(c, packageKernel, files)
   102  	snapf, err := snap.Open(fn)
   103  	c.Assert(err, IsNil)
   104  
   105  	info, err := snap.ReadInfoFromSnapFile(snapf, si)
   106  	c.Assert(err, IsNil)
   107  
   108  	err = l.ExtractKernelAssets(info, snapf)
   109  	c.Assert(err, IsNil)
   110  
   111  	// just boot.img and snapbootsel.bin are there, no kernel.img
   112  	infos, err := ioutil.ReadDir(filepath.Join(s.rootdir, "boot", "lk", ""))
   113  	c.Assert(err, IsNil)
   114  	var fnames []string
   115  	for _, info := range infos {
   116  		fnames = append(fnames, info.Name())
   117  	}
   118  	sort.Strings(fnames)
   119  	c.Assert(fnames, HasLen, 2)
   120  	c.Assert(fnames, DeepEquals, []string{"boot.img", "snapbootsel.bin"})
   121  }
   122  
   123  func (s *lkTestSuite) TestExtractKernelAssetsUnpacksCustomBootimgImageBuilding(c *C) {
   124  	opts := &bootloader.Options{
   125  		PrepareImageTime: true,
   126  	}
   127  	bootloader.MockLkFiles(c, s.rootdir, opts)
   128  	l := bootloader.NewLk(s.rootdir, opts)
   129  
   130  	c.Assert(l, NotNil)
   131  
   132  	// first configure custom boot image file name
   133  	env := lkenv.NewEnv(l.ConfigFile())
   134  	env.Load()
   135  	env.ConfigureBootimgName("boot-2.img")
   136  	err := env.Save()
   137  	c.Assert(err, IsNil)
   138  
   139  	files := [][]string{
   140  		{"kernel.img", "I'm a kernel"},
   141  		{"initrd.img", "...and I'm an initrd"},
   142  		{"boot-2.img", "...and I'm an boot image"},
   143  		{"dtbs/foo.dtb", "g'day, I'm foo.dtb"},
   144  		{"dtbs/bar.dtb", "hello, I'm bar.dtb"},
   145  		// must be last
   146  		{"meta/kernel.yaml", "version: 4.2"},
   147  	}
   148  	si := &snap.SideInfo{
   149  		RealName: "ubuntu-kernel",
   150  		Revision: snap.R(42),
   151  	}
   152  	fn := snaptest.MakeTestSnapWithFiles(c, packageKernel, files)
   153  	snapf, err := snap.Open(fn)
   154  	c.Assert(err, IsNil)
   155  
   156  	info, err := snap.ReadInfoFromSnapFile(snapf, si)
   157  	c.Assert(err, IsNil)
   158  
   159  	err = l.ExtractKernelAssets(info, snapf)
   160  	c.Assert(err, IsNil)
   161  
   162  	// boot-2.img is there
   163  	bootimg := filepath.Join(s.rootdir, "boot", "lk", "boot-2.img")
   164  	c.Assert(osutil.FileExists(bootimg), Equals, true)
   165  }
   166  
   167  func (s *lkTestSuite) TestExtractKernelAssetsUnpacksAndRemoveInRuntimeMode(c *C) {
   168  	bootloader.MockLkFiles(c, s.rootdir, nil)
   169  	lk := bootloader.NewLk(s.rootdir, nil)
   170  	c.Assert(lk, NotNil)
   171  
   172  	// create mock bootsel, boot_a, boot_b partitions
   173  	for _, partName := range []string{"snapbootsel", "boot_a", "boot_b"} {
   174  		mockPart := filepath.Join(s.rootdir, "/dev/disk/by-partlabel/", partName)
   175  		err := os.MkdirAll(filepath.Dir(mockPart), 0755)
   176  		c.Assert(err, IsNil)
   177  		err = ioutil.WriteFile(mockPart, nil, 0600)
   178  		c.Assert(err, IsNil)
   179  	}
   180  	// ensure we have a valid boot env
   181  	bootselPartition := filepath.Join(s.rootdir, "/dev/disk/by-partlabel/snapbootsel")
   182  	lkenv := lkenv.NewEnv(bootselPartition)
   183  	lkenv.ConfigureBootPartitions("boot_a", "boot_b")
   184  	err := lkenv.Save()
   185  	c.Assert(err, IsNil)
   186  
   187  	// mock a kernel snap that has a boot.img
   188  	files := [][]string{
   189  		{"boot.img", "I'm the default boot image name"},
   190  	}
   191  	si := &snap.SideInfo{
   192  		RealName: "ubuntu-kernel",
   193  		Revision: snap.R(42),
   194  	}
   195  	fn := snaptest.MakeTestSnapWithFiles(c, packageKernel, files)
   196  	snapf, err := snap.Open(fn)
   197  	c.Assert(err, IsNil)
   198  
   199  	info, err := snap.ReadInfoFromSnapFile(snapf, si)
   200  	c.Assert(err, IsNil)
   201  
   202  	// now extract
   203  	err = lk.ExtractKernelAssets(info, snapf)
   204  	c.Assert(err, IsNil)
   205  
   206  	// and validate it went to the "boot_a" partition
   207  	bootA := filepath.Join(s.rootdir, "/dev/disk/by-partlabel/boot_a")
   208  	content, err := ioutil.ReadFile(bootA)
   209  	c.Assert(err, IsNil)
   210  	c.Assert(string(content), Equals, "I'm the default boot image name")
   211  
   212  	// also validate that bootB is empty
   213  	bootB := filepath.Join(s.rootdir, "/dev/disk/by-partlabel/boot_b")
   214  	content, err = ioutil.ReadFile(bootB)
   215  	c.Assert(err, IsNil)
   216  	c.Assert(content, HasLen, 0)
   217  
   218  	// test that boot partition got set
   219  	err = lkenv.Load()
   220  	c.Assert(err, IsNil)
   221  	bootPart, err := lkenv.GetBootPartition("ubuntu-kernel_42.snap")
   222  	c.Assert(err, IsNil)
   223  	c.Assert(bootPart, Equals, "boot_a")
   224  
   225  	// now remove the kernel
   226  	err = lk.RemoveKernelAssets(info)
   227  	c.Assert(err, IsNil)
   228  	// and ensure its no longer available in the boot partions
   229  	err = lkenv.Load()
   230  	c.Assert(err, IsNil)
   231  	bootPart, err = lkenv.GetBootPartition("ubuntu-kernel_42.snap")
   232  	c.Assert(err, ErrorMatches, "cannot find kernel .* in boot image partitions")
   233  	c.Assert(bootPart, Equals, "")
   234  }