github.com/chipaca/snappy@v0.0.0-20210104084008-1f06296fe8ad/seed/seed.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2019-2020 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 seed implements loading and validating of seed data. 21 package seed 22 23 import ( 24 "errors" 25 "fmt" 26 "path/filepath" 27 28 "github.com/snapcore/snapd/asserts" 29 "github.com/snapcore/snapd/seed/internal" 30 "github.com/snapcore/snapd/snap" 31 "github.com/snapcore/snapd/timings" 32 ) 33 34 var ( 35 ErrNoAssertions = errors.New("no seed assertions") 36 ErrNoMeta = errors.New("no seed metadata") 37 ) 38 39 // Snap holds the details of a snap in a seed. 40 type Snap struct { 41 Path string 42 43 SideInfo *snap.SideInfo 44 45 // EssentialType is the type of the snap as specified by the model. 46 // Provided only for essential snaps (Essential = true). 47 EssentialType snap.Type 48 49 Essential bool 50 Required bool 51 52 // options 53 Channel string 54 DevMode bool 55 Classic bool 56 } 57 58 func (s *Snap) SnapName() string { 59 return s.SideInfo.RealName 60 } 61 62 func (s *Snap) ID() string { 63 return s.SideInfo.SnapID 64 } 65 66 // PlaceInfo returns a PlaceInfo for the seed snap. 67 func (s *Snap) PlaceInfo() snap.PlaceInfo { 68 return &snap.Info{SideInfo: *s.SideInfo} 69 } 70 71 // Seed supports loading assertions and seed snaps' metadata. 72 type Seed interface { 73 // LoadAssertions loads all assertions from the seed with 74 // cross-checks. A read-only view on an assertions database 75 // can be passed in together with a commitTo function which 76 // will be used to commit the assertions to the underlying 77 // database. If db is nil an internal temporary database will 78 // be setup instead. ErrNoAssertions will be returned if there 79 // is no assertions directory in the seed, this is legitimate 80 // only on classic. 81 LoadAssertions(db asserts.RODatabase, commitTo func(*asserts.Batch) error) error 82 83 // Model returns the seed provided model assertion. 84 // It will panic if called before LoadAssertions. 85 Model() *asserts.Model 86 87 // Brand returns the brand information of the seed. 88 // It will panic if called before LoadAssertions. 89 Brand() (*asserts.Account, error) 90 91 // LoadMeta loads the seed and seed's snaps metadata while 92 // verifying the underlying snaps against assertions. It can 93 // return ErrNoMeta if there is no metadata nor snaps in the 94 // seed, this is legitimate only on classic. 95 // It will panic if called before LoadAssertions. 96 LoadMeta(tm timings.Measurer) error 97 98 // UsesSnapdSnap returns whether the system as defined by the 99 // seed will use the snapd snap, after LoadMeta. 100 UsesSnapdSnap() bool 101 102 // EssentialSnaps returns the essential snaps as defined by 103 // the seed, after LoadMeta. 104 EssentialSnaps() []*Snap 105 106 // ModeSnaps returns the snaps that should be available 107 // in the given mode as defined by the seed, after LoadMeta. 108 ModeSnaps(mode string) ([]*Snap, error) 109 } 110 111 // EssentialMetaLoaderSeed is a Seed that can be asked to load and verify 112 // only a subset of the essential model snaps via LoadEssentialMeta. 113 type EssentialMetaLoaderSeed interface { 114 Seed 115 116 // LoadEssentialMeta loads the seed's snaps metadata for the 117 // essential snaps with types in the essentialTypes set while 118 // verifying them against assertions. It can return ErrNoMeta 119 // if there is no metadata nor snaps in the seed, this is 120 // legitimate only on classic. It is an error to mix it with 121 // LoadMeta. 122 // It will panic if called before LoadAssertions. 123 LoadEssentialMeta(essentialTypes []snap.Type, tm timings.Measurer) error 124 } 125 126 // Open returns a Seed implementation for the seed at seedDir. 127 // label if not empty is used to identify a Core 20 recovery system seed. 128 func Open(seedDir, label string) (Seed, error) { 129 if label != "" { 130 if err := internal.ValidateUC20SeedSystemLabel(label); err != nil { 131 return nil, err 132 } 133 return &seed20{systemDir: filepath.Join(seedDir, "systems", label)}, nil 134 } 135 return &seed16{seedDir: seedDir}, nil 136 } 137 138 // ReadSystemEssential retrieves in one go information about the model 139 // and essential snaps of the given types for the Core 20 recovery 140 // system seed specified by seedDir and label (which cannot be empty). 141 func ReadSystemEssential(seedDir, label string, essentialTypes []snap.Type, tm timings.Measurer) (*asserts.Model, []*Snap, error) { 142 if label == "" { 143 return nil, nil, fmt.Errorf("system label cannot be empty") 144 } 145 seed, err := Open(seedDir, label) 146 if err != nil { 147 return nil, nil, err 148 } 149 150 seed20, ok := seed.(EssentialMetaLoaderSeed) 151 if !ok { 152 return nil, nil, fmt.Errorf("internal error: UC20 seed must implement EssentialMetaLoaderSeed") 153 } 154 155 // load assertions into a temporary database 156 if err := seed20.LoadAssertions(nil, nil); err != nil { 157 return nil, nil, err 158 } 159 160 // load and verify info about essential snaps 161 if err := seed20.LoadEssentialMeta(essentialTypes, tm); err != nil { 162 return nil, nil, err 163 } 164 165 return seed20.Model(), seed20.EssentialSnaps(), nil 166 }