func (sdbs *sysDBSuite) TestTrusted(c *C) { trusted := sysdb.Trusted() c.Check(trusted, HasLen, 2) restore := sysdb.InjectTrusted(sdbs.extraTrusted) defer restore() trustedEx := sysdb.Trusted() c.Check(trustedEx, HasLen, 4) }
func (s *Store) collectAssertions() (asserts.Backstore, error) { bs := asserts.NewMemoryBackstore() add := func(a asserts.Assertion) { bs.Put(a.Type(), a) } for _, t := range sysdb.Trusted() { add(t) } add(systestkeys.TestRootAccount) add(systestkeys.TestRootAccountKey) add(systestkeys.TestStoreAccountKey) aFiles, err := filepath.Glob(filepath.Join(s.assertDir, "*")) if err != nil { return nil, err } for _, fn := range aFiles { b, err := ioutil.ReadFile(fn) if err != nil { return nil, err } a, err := asserts.Decode(b) if err != nil { return nil, err } add(a) } return bs, nil }
func MakeFakeRefreshForSnaps(snaps []string, blobDir string) error { storePrivKey, _ := assertstest.ReadPrivKey(systestkeys.TestStorePrivKey) db, err := asserts.OpenDatabase(&asserts.DatabaseConfig{ KeypairManager: asserts.NewMemoryKeypairManager(), Backstore: asserts.NewMemoryBackstore(), Trusted: sysdb.Trusted(), }) if err != nil { return err } // for signing db.ImportKey(storePrivKey) var cliConfig client.Config cli := client.New(&cliConfig) retrieve := func(ref *asserts.Ref) (asserts.Assertion, error) { headers := make(map[string]string) for i, k := range ref.Type.PrimaryKey { headers[k] = ref.PrimaryKey[i] } as, err := cli.Known(ref.Type.Name, headers) if err != nil { return nil, err } switch len(as) { case 1: return as[0], nil case 0: return nil, asserts.ErrNotFound default: panic(fmt.Sprintf("multiple assertions when retrieving by primary key: %v", ref)) } } save := func(a asserts.Assertion) error { err := db.Add(a) if err != nil { if _, ok := err.(*asserts.RevisionError); !ok { return err } } return writeAssert(a, blobDir) } f := asserts.NewFetcher(db, retrieve, save) for _, snap := range snaps { if err := makeFakeRefreshForSnap(snap, blobDir, db, f); err != nil { return err } } return nil }
func MakeFakeRefreshForSnaps(snaps []string, blobDir string) error { storePrivKey, _ := assertstest.ReadPrivKey(systestkeys.TestStorePrivKey) db, err := asserts.OpenDatabase(&asserts.DatabaseConfig{ KeypairManager: asserts.NewMemoryKeypairManager(), Backstore: asserts.NewMemoryBackstore(), Trusted: sysdb.Trusted(), }) if err != nil { return err } // for signing db.ImportKey(storePrivKey) // XXX: ideally for consistency we should talk to the local snapd // but this allows us to go working until snapd itself // start being fully assertion using sto := store.New(nil, nil) retrieve := func(ref *asserts.Ref) (asserts.Assertion, error) { return sto.Assertion(ref.Type, ref.PrimaryKey, nil) } save := func(a asserts.Assertion) error { err := db.Add(a) if err != nil { if _, ok := err.(*asserts.RevisionError); !ok { return err } } return writeAssert(a, blobDir) } f := asserts.NewFetcher(db, retrieve, save) for _, snap := range snaps { if err := makeFakeRefreshForSnap(snap, blobDir, db, f); err != nil { return err } } return nil }
func fetchSnapAssertions(sto *store.Store, snapPath string, snapInfo *snap.Info, dlOpts *image.DownloadOptions) error { db, err := asserts.OpenDatabase(&asserts.DatabaseConfig{ Backstore: asserts.NewMemoryBackstore(), Trusted: sysdb.Trusted(), }) if err != nil { return err } w, err := os.Create(snapPath + ".assertions") if err != nil { return fmt.Errorf(i18n.G("cannot create assertions file: %v"), err) } defer w.Close() encoder := asserts.NewEncoder(w) save := func(a asserts.Assertion) error { return encoder.Encode(a) } f := image.StoreAssertionFetcher(sto, dlOpts, db, save) return image.FetchAndCheckSnapAssertions(snapPath, snapInfo, f, db) }
func bootstrapToRootDir(sto Store, model *asserts.Model, opts *Options, local *localInfos) error { // FIXME: try to avoid doing this if opts.RootDir != "" { dirs.SetRootDir(opts.RootDir) defer dirs.SetRootDir("/") } // sanity check target if osutil.FileExists(dirs.SnapStateFile) { return fmt.Errorf("cannot bootstrap over existing system") } // TODO: developer database in home or use snapd (but need // a bit more API there, potential issues when crossing stores/series) db, err := asserts.OpenDatabase(&asserts.DatabaseConfig{ Backstore: asserts.NewMemoryBackstore(), Trusted: sysdb.Trusted(), }) if err != nil { return err } f := makeFetcher(sto, &DownloadOptions{}, db) if err := f.Save(model); err != nil { if !osutil.GetenvBool("UBUNTU_IMAGE_SKIP_COPY_UNVERIFIED_MODEL") { return fmt.Errorf("cannot fetch and check prerequisites for the model assertion: %v", err) } else { logger.Noticef("Cannot fetch and check prerequisites for the model assertion, it will not be copied into the image: %v", err) f.addedRefs = nil } } // put snaps in place if err := os.MkdirAll(dirs.SnapBlobDir, 0755); err != nil { return err } snapSeedDir := filepath.Join(dirs.SnapSeedDir, "snaps") assertSeedDir := filepath.Join(dirs.SnapSeedDir, "assertions") dlOpts := &DownloadOptions{ TargetDir: snapSeedDir, Channel: opts.Channel, DevMode: false, // XXX: should this be true? } for _, d := range []string{snapSeedDir, assertSeedDir} { if err := os.MkdirAll(d, 0755); err != nil { return err } } snaps := []string{} // core,kernel,gadget first snaps = append(snaps, local.PreferLocal(defaultCore)) snaps = append(snaps, local.PreferLocal(model.Kernel())) snaps = append(snaps, local.PreferLocal(model.Gadget())) // then required and the user requested stuff for _, snapName := range model.RequiredSnaps() { snaps = append(snaps, local.PreferLocal(snapName)) } snaps = append(snaps, opts.Snaps...) seen := make(map[string]bool) downloadedSnapsInfo := map[string]*snap.Info{} var seedYaml snap.Seed for _, snapName := range snaps { name := local.Name(snapName) if seen[name] { fmt.Fprintf(Stdout, "%s already prepared, skipping\n", name) continue } if name != snapName { fmt.Fprintf(Stdout, "Copying %q (%s)\n", snapName, name) } else { fmt.Fprintf(Stdout, "Fetching %s\n", snapName) } fn, info, err := acquireSnap(sto, name, dlOpts, local) if err != nil { return err } seen[name] = true // if it comes from the store fetch the snap assertions too // TODO: support somehow including available assertions // also for local snaps if info.SnapID != "" { err = FetchAndCheckSnapAssertions(fn, info, f, db) if err != nil { return err } } typ := info.Type // kernel/os are required for booting if typ == snap.TypeKernel || typ == snap.TypeOS { dst := filepath.Join(dirs.SnapBlobDir, filepath.Base(fn)) if err := osutil.CopyFile(fn, dst, 0); err != nil { return err } // store the snap.Info for kernel/os so // that the bootload can DTRT downloadedSnapsInfo[dst] = info } // set seed.yaml seedYaml.Snaps = append(seedYaml.Snaps, &snap.SeedSnap{ Name: info.Name(), SnapID: info.SnapID, // cross-ref Channel: info.Channel, File: filepath.Base(fn), DevMode: info.NeedsDevMode(), // no assertions for this snap were put in the seed Unasserted: info.SnapID == "", }) } for _, aRef := range f.addedRefs { var afn string // the names don't matter in practice as long as they don't conflict if aRef.Type == asserts.ModelType { afn = "model" } else { afn = fmt.Sprintf("%s.%s", strings.Join(aRef.PrimaryKey, ","), aRef.Type.Name) } a, err := aRef.Resolve(db.Find) if err != nil { return fmt.Errorf("internal error: lost saved assertion") } err = ioutil.WriteFile(filepath.Join(assertSeedDir, afn), asserts.Encode(a), 0644) if err != nil { return err } } // TODO: add the refs as an assertions list of maps section to seed.yaml seedFn := filepath.Join(dirs.SnapSeedDir, "seed.yaml") if err := seedYaml.Write(seedFn); err != nil { return fmt.Errorf("cannot write seed.yaml: %s", err) } // now do the bootloader stuff if err := partition.InstallBootConfig(opts.GadgetUnpackDir); err != nil { return err } if err := setBootvars(downloadedSnapsInfo); err != nil { return err } // and the cloud-init things if err := installCloudConfig(opts.GadgetUnpackDir); err != nil { return err } return nil }