summaryrefslogtreecommitdiff
diff options
authorValentin David <valentin.david@canonical.com>2023-05-15 13:36:24 +0200
committerValentin David <me@valentindavid.com>2023-05-24 09:54:52 +0200
commiteefba60eae6328e663e51977792f5843347f04ab (patch)
tree218568d8d114014ac55e713f0de89d43fbd97ca0
parentcfa84643c765d520daad94a51137d8aed1d5c4c6 (diff)
cmd/snap-bootstrap: cache loaded seeds
-rw-r--r--cmd/snap-bootstrap/cmd_initramfs_mounts.go19
-rw-r--r--cmd/snap-bootstrap/initramfs_mounts_state.go27
-rw-r--r--seed/seed.go30
-rw-r--r--seed/seed20_test.go67
4 files changed, 56 insertions, 87 deletions
diff --git a/cmd/snap-bootstrap/cmd_initramfs_mounts.go b/cmd/snap-bootstrap/cmd_initramfs_mounts.go
index 59708bed17..6abc3c4e49 100644
--- a/cmd/snap-bootstrap/cmd_initramfs_mounts.go
+++ b/cmd/snap-bootstrap/cmd_initramfs_mounts.go
@@ -49,6 +49,7 @@ import (
"github.com/snapcore/snapd/snap"
"github.com/snapcore/snapd/snap/squashfs"
"github.com/snapcore/snapd/sysconfig"
+ "github.com/snapcore/snapd/timings"
)
func init() {
@@ -1440,11 +1441,20 @@ func generateMountsCommonInstallRecover(mst *initramfsMountsState) (model *asser
// load model and verified essential snaps metadata
typs := []snap.Type{snap.TypeBase, snap.TypeKernel, snap.TypeSnapd, snap.TypeGadget}
- model, essSnaps, err := mst.ReadEssential("", typs)
+
+ theSeed, err := mst.LoadSeed("")
if err != nil {
+ return nil, nil, fmt.Errorf("cannot load seed: %v", err)
+ }
+
+ perf := timings.New(nil)
+ if err := theSeed.LoadEssentialMeta(typs, perf); err != nil {
return nil, nil, fmt.Errorf("cannot load metadata and verify essential bootstrap snaps %v: %v", typs, err)
}
+ model = theSeed.Model()
+ essSnaps := theSeed.EssentialSnaps()
+
// 2.1. measure model
err = stampedAction(fmt.Sprintf("%s-model-measured", mst.recoverySystem), func() error {
return secbootMeasureSnapModelWhenPossible(func() (*asserts.Model, error) {
@@ -1865,10 +1875,15 @@ func generateMountsModeRun(mst *initramfsMountsState) error {
// 4.5 mount snapd snap only on first boot
if modeEnv.RecoverySystem != "" && !isClassic {
// load the recovery system and generate mount for snapd
- _, essSnaps, err := mst.ReadEssential(modeEnv.RecoverySystem, []snap.Type{snap.TypeSnapd})
+ theSeed, err := mst.LoadSeed(modeEnv.RecoverySystem)
if err != nil {
return fmt.Errorf("cannot load metadata and verify snapd snap: %v", err)
}
+ perf := timings.New(nil)
+ if err := theSeed.LoadEssentialMeta([]snap.Type{snap.TypeSnapd}, perf); err != nil {
+ return fmt.Errorf("cannot load metadata and verify snapd snap: %v", err)
+ }
+ essSnaps := theSeed.EssentialSnaps()
if err := doSystemdMount(essSnaps[0].Path, filepath.Join(boot.InitramfsRunMntDir, "snapd"), mountReadOnlyOptions); err != nil {
return fmt.Errorf("cannot mount snapd snap: %v", err)
}
diff --git a/cmd/snap-bootstrap/initramfs_mounts_state.go b/cmd/snap-bootstrap/initramfs_mounts_state.go
index 2636462d0d..57b910e32f 100644
--- a/cmd/snap-bootstrap/initramfs_mounts_state.go
+++ b/cmd/snap-bootstrap/initramfs_mounts_state.go
@@ -48,21 +48,30 @@ type initramfsMountsState struct {
recoverySystem string
verifiedModel gadget.Model
+ seeds map[string]seed.Seed
}
var errRunModeNoImpliedRecoverySystem = errors.New("internal error: no implied recovery system in run mode")
-// ReadEssential returns the model and verified essential
-// snaps from the recoverySystem. If recoverySystem is "" the
-// implied one will be used (only for modes other than run).
-func (mst *initramfsMountsState) ReadEssential(recoverySystem string, essentialTypes []snap.Type) (*asserts.Model, []*seed.Snap, error) {
+// LoadSeed returns the seed for the recoverySystem.
+// If recoverySystem is "" the implied one will be used (only for
+// modes other than run).
+func (mst *initramfsMountsState) LoadSeed(recoverySystem string) (seed.Seed, error) {
if recoverySystem == "" {
if mst.mode == "run" {
- return nil, nil, errRunModeNoImpliedRecoverySystem
+ return nil, errRunModeNoImpliedRecoverySystem
}
recoverySystem = mst.recoverySystem
}
+ if mst.seeds == nil {
+ mst.seeds = make(map[string]seed.Seed)
+ }
+ foundSeed, hasSeed := mst.seeds[recoverySystem]
+ if hasSeed {
+ return foundSeed, nil
+ }
+
perf := timings.New(nil)
// get the current time to pass to ReadSystemEssentialAndBetterEarliestTime
@@ -79,9 +88,9 @@ func (mst *initramfsMountsState) ReadEssential(recoverySystem string, essentialT
if runtimeNumCPU() > 1 {
jobs = 2
}
- model, snaps, newTrustedEarliestTime, err := seed.ReadSystemEssentialAndBetterEarliestTime(boot.InitramfsUbuntuSeedDir, recoverySystem, essentialTypes, now, jobs, perf)
+ seed20, newTrustedEarliestTime, err := seed.ReadSeedAndBetterEarliestTime(boot.InitramfsUbuntuSeedDir, recoverySystem, now, jobs, perf)
if err != nil {
- return nil, nil, err
+ return nil, err
}
// set the time on the system to move forward if it is in the future - never
@@ -94,7 +103,9 @@ func (mst *initramfsMountsState) ReadEssential(recoverySystem string, essentialT
}
}
- return model, snaps, nil
+ mst.seeds[recoverySystem] = seed20
+
+ return seed20, nil
}
// SetVerifiedBootModel sets the "verifiedModel" field. It should only
diff --git a/seed/seed.go b/seed/seed.go
index d8dafe3c10..ac8fe522e2 100644
--- a/seed/seed.go
+++ b/seed/seed.go
@@ -242,22 +242,21 @@ func ReadSystemEssential(seedDir, label string, essentialTypes []snap.Type, tm t
return seed20.Model(), seed20.EssentialSnaps(), nil
}
-// ReadSystemEssentialAndBetterEarliestTime retrieves in one go
-// information about the model and essential snaps of the given types
-// for the Core 20 recovery system seed specified by seedDir and label
-// (which cannot be empty). numJobs specifies the suggested number of
-// jobs to run in parallel (0 disables parallelism).
-// It can operate even if current system time is unreliable by taking
-// a earliestTime lower bound for current time.
+// ReadSeedAndBetterEarliestTime retrieves in one go the seed and
+// assertions for the Core 20 recovery system seed specified by
+// seedDir and label (which cannot be empty). numJobs specifies the
+// suggested number of jobs to run in parallel (0 disables
+// parallelism). It can operate even if current system time is
+// unreliable by taking a earliestTime lower bound for current time.
// It returns as well an improved lower bound by considering
// appropriate assertions in the seed.
-func ReadSystemEssentialAndBetterEarliestTime(seedDir, label string, essentialTypes []snap.Type, earliestTime time.Time, numJobs int, tm timings.Measurer) (*asserts.Model, []*Snap, time.Time, error) {
+func ReadSeedAndBetterEarliestTime(seedDir, label string, earliestTime time.Time, numJobs int, tm timings.Measurer) (Seed, time.Time, error) {
if label == "" {
- return nil, nil, time.Time{}, fmt.Errorf("system label cannot be empty")
+ return nil, time.Time{}, fmt.Errorf("system label cannot be empty")
}
seed20, err := open(seedDir, label)
if err != nil {
- return nil, nil, time.Time{}, err
+ return nil, time.Time{}, err
}
@@ -293,7 +292,7 @@ func ReadSystemEssentialAndBetterEarliestTime(seedDir, label string, essentialTy
// create a temporary database, commitTo will invoke improve
db, commitTo, err := newMemAssertionsDB(improve)
if err != nil {
- return nil, nil, time.Time{}, err
+ return nil, time.Time{}, err
}
// set up the database to check for key expiry only assuming
// earliestTime (if not zero)
@@ -301,12 +300,7 @@ func ReadSystemEssentialAndBetterEarliestTime(seedDir, label string, essentialTy
// load assertions into the temporary database
if err := seed20.LoadAssertions(db, commitTo); err != nil {
- return nil, nil, time.Time{}, err
- }
-
- // load and verify info about essential snaps
- if err := seed20.LoadEssentialMeta(essentialTypes, tm); err != nil {
- return nil, nil, time.Time{}, err
+ return nil, time.Time{}, err
}
// consider the model's timestamp as well - it must be signed
@@ -316,5 +310,5 @@ func ReadSystemEssentialAndBetterEarliestTime(seedDir, label string, essentialTy
earliestTime = mod.Timestamp()
}
- return mod, seed20.EssentialSnaps(), earliestTime, nil
+ return seed20, earliestTime, nil
}
diff --git a/seed/seed20_test.go b/seed/seed20_test.go
index e3daafecc5..de84e00524 100644
--- a/seed/seed20_test.go
+++ b/seed/seed20_test.go
@@ -1231,53 +1231,6 @@ func (s *seed20Suite) TestReadSystemEssentialAndBetterEarliestTime(c *C) {
s.makeSnap(c, "required18", "developerid")
s.SetSnapAssertionNow(time.Time{})
- snapdSnap := &seed.Snap{
- Path: s.expectedPath("snapd"),
- SideInfo: &s.AssertedSnapInfo("snapd").SideInfo,
- EssentialType: snap.TypeSnapd,
- Essential: true,
- Required: true,
- Channel: "latest/stable",
- }
- pcKernelSnap := &seed.Snap{
- Path: s.expectedPath("pc-kernel"),
- SideInfo: &s.AssertedSnapInfo("pc-kernel").SideInfo,
- EssentialType: snap.TypeKernel,
- Essential: true,
- Required: true,
- Channel: "20",
- }
- core20Snap := &seed.Snap{Path: s.expectedPath("core20"),
- SideInfo: &s.AssertedSnapInfo("core20").SideInfo,
- EssentialType: snap.TypeBase,
- Essential: true,
- Required: true,
- Channel: "latest/stable",
- }
- pcSnap := &seed.Snap{
- Path: s.expectedPath("pc"),
- SideInfo: &s.AssertedSnapInfo("pc").SideInfo,
- EssentialType: snap.TypeGadget,
- Essential: true,
- Required: true,
- Channel: "20",
- }
-
- tests := []struct {
- onlyTypes []snap.Type
- expected []*seed.Snap
- }{
- {[]snap.Type{snap.TypeSnapd}, []*seed.Snap{snapdSnap}},
- {[]snap.Type{snap.TypeKernel}, []*seed.Snap{pcKernelSnap}},
- {[]snap.Type{snap.TypeBase}, []*seed.Snap{core20Snap}},
- {[]snap.Type{snap.TypeGadget}, []*seed.Snap{pcSnap}},
- {[]snap.Type{snap.TypeSnapd, snap.TypeKernel, snap.TypeBase}, []*seed.Snap{snapdSnap, pcKernelSnap, core20Snap}},
- // the order in essentialTypes is not relevant
- {[]snap.Type{snap.TypeGadget, snap.TypeKernel}, []*seed.Snap{pcKernelSnap, pcSnap}},
- // degenerate case
- {[]snap.Type{}, []*seed.Snap{snapdSnap, pcKernelSnap, core20Snap, pcSnap}},
- }
-
baseLabel := "20210315"
testReadSystemEssentialAndBetterEarliestTime := func(sysLabel string, earliestTime, modelTime, improvedTime time.Time) {
@@ -1310,17 +1263,13 @@ func (s *seed20Suite) TestReadSystemEssentialAndBetterEarliestTime(c *C) {
}},
}, nil)
- for _, t := range tests {
- // test short-cut helper as well
- mod, essSnaps, betterTime, err := seed.ReadSystemEssentialAndBetterEarliestTime(s.SeedDir, sysLabel, t.onlyTypes, earliestTime, 0, s.perfTimings)
- c.Assert(err, IsNil)
- c.Check(mod.BrandID(), Equals, "my-brand")
- c.Check(mod.Model(), Equals, "my-model")
- c.Check(mod.Timestamp().Equal(modelTime), Equals, true)
- c.Check(essSnaps, HasLen, len(t.expected))
- c.Check(essSnaps, DeepEquals, t.expected)
- c.Check(betterTime.Equal(improvedTime), Equals, true, Commentf("%v expected: %v", betterTime, improvedTime))
- }
+ // test short-cut helper as well
+ theSeed, betterTime, err := seed.ReadSeedAndBetterEarliestTime(s.SeedDir, sysLabel, earliestTime, 0, s.perfTimings)
+ c.Assert(err, IsNil)
+ c.Check(theSeed.Model().BrandID(), Equals, "my-brand")
+ c.Check(theSeed.Model().Model(), Equals, "my-model")
+ c.Check(theSeed.Model().Timestamp().Equal(modelTime), Equals, true)
+ c.Check(betterTime.Equal(improvedTime), Equals, true, Commentf("%v expected: %v", betterTime, improvedTime))
}
revsTime := s.AssertedSnapRevision("required18").Timestamp()
@@ -1379,7 +1328,7 @@ func (s *seed20Suite) TestReadSystemEssentialAndBetterEarliestTimeParallelism(c
}},
}, nil)
- _, _, _, err := seed.ReadSystemEssentialAndBetterEarliestTime(s.SeedDir, sysLabel, nil, time.Time{}, 3, s.perfTimings)
+ _, _, err := seed.ReadSeedAndBetterEarliestTime(s.SeedDir, sysLabel, time.Time{}, 3, s.perfTimings)
c.Assert(err, IsNil)
c.Assert(testSeed, NotNil)
c.Check(testSeed.Jobs, Equals, 3)