diff options
| author | Valentin David <valentin.david@canonical.com> | 2023-05-15 13:36:24 +0200 |
|---|---|---|
| committer | Valentin David <me@valentindavid.com> | 2023-05-24 09:54:52 +0200 |
| commit | eefba60eae6328e663e51977792f5843347f04ab (patch) | |
| tree | 218568d8d114014ac55e713f0de89d43fbd97ca0 | |
| parent | cfa84643c765d520daad94a51137d8aed1d5c4c6 (diff) | |
cmd/snap-bootstrap: cache loaded seeds
| -rw-r--r-- | cmd/snap-bootstrap/cmd_initramfs_mounts.go | 19 | ||||
| -rw-r--r-- | cmd/snap-bootstrap/initramfs_mounts_state.go | 27 | ||||
| -rw-r--r-- | seed/seed.go | 30 | ||||
| -rw-r--r-- | seed/seed20_test.go | 67 |
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) |
