mirror of
https://github.com/token2/snapd.git
synced 2026-03-13 11:15:47 -07:00
This is needed because the uc18/uc16 bootloader implementations do not actually do this, and instead snapd needs to reset the value. Also modify the bootenv bootloader logic simulation to not clean this anymore, just as the real bootloaders do. This all requires some slight changes to the test logic, which since they are checking the BootVars map directly will see some additional empty keys in the map as markSuccessful will now write those empty keys. Eventually we should port these tests to use GetBootVars and not use the map directly since empty string keys show up the same as missing keys with GetBootVars and that would have prevented needing to change these tests at all. Signed-off-by: Ian Johnson <ian.johnson@canonical.com>
170 lines
5.5 KiB
Go
170 lines
5.5 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 boottest
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/snapcore/snapd/bootloader/bootloadertest"
|
|
"github.com/snapcore/snapd/snap"
|
|
)
|
|
|
|
// Bootenv16 implements manipulating a UC16/18 boot env for testing.
|
|
type Bootenv16 struct {
|
|
*bootloadertest.MockBootloader
|
|
statusVar string
|
|
}
|
|
|
|
// MockUC16Bootenv wraps a mock bootloader for UC16/18 boot env
|
|
// manipulation.
|
|
func MockUC16Bootenv(b *bootloadertest.MockBootloader) *Bootenv16 {
|
|
return &Bootenv16{
|
|
MockBootloader: b,
|
|
statusVar: "snap_mode",
|
|
}
|
|
}
|
|
|
|
// SetBootKernel sets the current boot kernel string. Should be
|
|
// something like "pc-kernel_1234.snap".
|
|
func (b16 Bootenv16) SetBootKernel(kernel string) {
|
|
b16.SetBootVars(map[string]string{"snap_kernel": kernel})
|
|
}
|
|
|
|
// SetBootTryKernel sets the try boot kernel string. Should be
|
|
// something like "pc-kernel_1235.snap".
|
|
func (b16 Bootenv16) SetBootTryKernel(kernel string) {
|
|
b16.SetBootVars(map[string]string{"snap_try_kernel": kernel})
|
|
}
|
|
|
|
// SetBootBase sets the current boot base string. Should be something
|
|
// like "core_1234.snap".
|
|
func (b16 Bootenv16) SetBootBase(base string) {
|
|
b16.SetBootVars(map[string]string{"snap_core": base})
|
|
}
|
|
|
|
// SetTryingDuringReboot indicates that new kernel or base are being tried
|
|
// same as done by bootloader config.
|
|
func (b16 Bootenv16) SetTryingDuringReboot(which []snap.Type) error {
|
|
if b16.BootVars[b16.statusVar] != "try" {
|
|
return fmt.Errorf("bootloader must be in 'try' mode")
|
|
}
|
|
b16.BootVars[b16.statusVar] = "trying"
|
|
return nil
|
|
}
|
|
|
|
func includesType(which []snap.Type, t snap.Type) bool {
|
|
for _, t1 := range which {
|
|
if t1 == t {
|
|
return true
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func exactlyType(which []snap.Type, t snap.Type) bool {
|
|
if len(which) != 1 {
|
|
return false
|
|
}
|
|
if which[0] != t {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// SetRollbackAcrossReboot will simulate a rollback across reboots. This
|
|
// means that the bootloader had "snap_try_{core,kernel}" set but this
|
|
// boot failed. In this case the bootloader will clear
|
|
// "snap_try_{core,kernel}" and "snap_mode" which means the "old" kernel,core
|
|
// in "snap_{core,kernel}" will be used. which indicates whether rollback
|
|
// applies to kernel, base or both.
|
|
func (b16 Bootenv16) SetRollbackAcrossReboot(which []snap.Type) error {
|
|
if b16.BootVars[b16.statusVar] != "try" {
|
|
return fmt.Errorf("rollback can only be simulated in 'try' mode")
|
|
}
|
|
rollbackBase := includesType(which, snap.TypeBase)
|
|
rollbackKernel := includesType(which, snap.TypeKernel)
|
|
if !rollbackBase && !rollbackKernel {
|
|
return fmt.Errorf("rollback of either base or kernel must be requested")
|
|
}
|
|
if rollbackBase && b16.BootVars["snap_core"] == "" && b16.BootVars["snap_kernel"] == "" {
|
|
return fmt.Errorf("base rollback can only be simulated if snap_core is set")
|
|
}
|
|
if rollbackKernel && b16.BootVars["snap_kernel"] == "" {
|
|
return fmt.Errorf("kernel rollback can only be simulated if snap_kernel is set")
|
|
}
|
|
// clean only statusVar - the try vars will be cleaned by snapd NOT by the
|
|
// bootloader
|
|
b16.BootVars[b16.statusVar] = ""
|
|
return nil
|
|
}
|
|
|
|
// RunBootenv20 implements manipulating a UC20 run-mode boot env for
|
|
// testing.
|
|
type RunBootenv20 struct {
|
|
*bootloadertest.MockExtractedRunKernelImageBootloader
|
|
}
|
|
|
|
// MockUC20EnvRefExtractedKernelRunBootenv wraps a mock bootloader for UC20 run-mode boot
|
|
// env manipulation.
|
|
func MockUC20EnvRefExtractedKernelRunBootenv(b *bootloadertest.MockBootloader) *Bootenv16 {
|
|
// TODO:UC20: implement this w/o returning Bootenv16 because that doesn't
|
|
// make a lot of sense to the caller
|
|
return &Bootenv16{
|
|
MockBootloader: b,
|
|
statusVar: "kernel_status",
|
|
}
|
|
}
|
|
|
|
// MockUC20RunBootenv wraps a mock bootloader for UC20 run-mode boot
|
|
// env manipulation.
|
|
func MockUC20RunBootenv(b *bootloadertest.MockBootloader) *RunBootenv20 {
|
|
return &RunBootenv20{b.WithExtractedRunKernelImage()}
|
|
}
|
|
|
|
// TODO:UC20: expose actual snap-boostrap logic for testing
|
|
|
|
// SetTryingDuringReboot indicates that new kernel or base are being tried
|
|
// same as done by bootloader config.
|
|
func (b20 RunBootenv20) SetTryingDuringReboot(which []snap.Type) error {
|
|
if !exactlyType(which, snap.TypeKernel) {
|
|
return fmt.Errorf("for now only kernel related simulation is supported")
|
|
}
|
|
if b20.BootVars["kernel_status"] != "try" {
|
|
return fmt.Errorf("bootloader must be in 'try' mode")
|
|
}
|
|
b20.BootVars["kernel_status"] = "trying"
|
|
return nil
|
|
}
|
|
|
|
// SetRollbackAcrossReboot will simulate a rollback across reboots for either
|
|
// a new base or kernel or both, as indicated by which.
|
|
// TODO: only kernel is supported for now.
|
|
func (b20 RunBootenv20) SetRollbackAcrossReboot(which []snap.Type) error {
|
|
if !exactlyType(which, snap.TypeKernel) {
|
|
return fmt.Errorf("for now only kernel related simulation is supported")
|
|
}
|
|
if b20.BootVars["kernel_status"] != "try" {
|
|
return fmt.Errorf("rollback can only be simulated in 'try' mode")
|
|
}
|
|
// clean try bootvars and snap_mode
|
|
b20.BootVars["kernel_status"] = ""
|
|
return nil
|
|
}
|