github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/seed/seedwriter/helpers.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2014-2019 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 seedwriter 21 22 import ( 23 "fmt" 24 25 "github.com/snapcore/snapd/asserts" 26 "github.com/snapcore/snapd/asserts/snapasserts" 27 "github.com/snapcore/snapd/snap" 28 ) 29 30 // A RefAssertsFetcher is a Fetcher that can at any point return 31 // references to the fetched assertions. 32 type RefAssertsFetcher interface { 33 asserts.Fetcher 34 Refs() []*asserts.Ref 35 ResetRefs() 36 } 37 38 type refRecFetcher struct { 39 asserts.Fetcher 40 refs []*asserts.Ref 41 } 42 43 func (rrf *refRecFetcher) Refs() []*asserts.Ref { 44 return rrf.refs 45 } 46 47 func (rrf *refRecFetcher) ResetRefs() { 48 rrf.refs = nil 49 } 50 51 // A NewFetcherFunc can build a Fetcher saving to an (implicit) 52 // database and also calling the given additional save function. 53 type NewFetcherFunc func(save func(asserts.Assertion) error) asserts.Fetcher 54 55 // MakeRefAssertsFetcher makes a RefAssertsFetcher using newFetcher which can 56 // build a base Fetcher with an additional save function. 57 func MakeRefAssertsFetcher(newFetcher NewFetcherFunc) RefAssertsFetcher { 58 var rrf refRecFetcher 59 save := func(a asserts.Assertion) error { 60 rrf.refs = append(rrf.refs, a.Ref()) 61 return nil 62 } 63 rrf.Fetcher = newFetcher(save) 64 return &rrf 65 } 66 67 func whichModelSnap(modSnap *asserts.ModelSnap, model *asserts.Model) string { 68 switch modSnap.SnapType { 69 case "snapd": 70 return "snapd snap" 71 case "core": 72 return "core snap" 73 case "base": 74 what := fmt.Sprintf("base %q", modSnap.SnapName()) 75 if modSnap.SnapName() == model.Base() { 76 what = "boot " + what 77 } 78 return what 79 case "kernel": 80 return fmt.Sprintf("kernel %q", modSnap.SnapName()) 81 case "gadget": 82 return fmt.Sprintf("gadget %q", modSnap.SnapName()) 83 default: 84 return fmt.Sprintf("snap %q", modSnap.SnapName()) 85 } 86 } 87 88 func checkType(sn *SeedSnap, model *asserts.Model) error { 89 if sn.modelSnap == nil { 90 return nil 91 } 92 expectedType := snap.TypeApp 93 switch sn.modelSnap.SnapType { 94 case "snapd": 95 expectedType = snap.TypeSnapd 96 case "core": 97 expectedType = snap.TypeOS 98 case "base": 99 expectedType = snap.TypeBase 100 case "kernel": 101 expectedType = snap.TypeKernel 102 case "gadget": 103 expectedType = snap.TypeGadget 104 case "app": 105 expectedType = snap.TypeApp 106 case "": 107 // ModelSnap for Core 16/18 "required-snaps" have 108 // SnapType not set given the model assertion does not 109 // have the information 110 typ := sn.Info.Type() 111 if typ == snap.TypeKernel || typ == snap.TypeGadget { 112 return fmt.Errorf("snap %q has unexpected type: %s", sn.SnapName(), typ) 113 } 114 return nil 115 } 116 if sn.Info.Type() != expectedType { 117 what := whichModelSnap(sn.modelSnap, model) 118 return fmt.Errorf("%s has unexpected type: %s", what, sn.Info.Type()) 119 } 120 return nil 121 } 122 123 type seedSnapsByType []*SeedSnap 124 125 func (s seedSnapsByType) Len() int { return len(s) } 126 func (s seedSnapsByType) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 127 func (s seedSnapsByType) Less(i, j int) bool { 128 return s[i].Info.Type().SortsBefore(s[j].Info.Type()) 129 } 130 131 // finderFromFetcher exposes an assertion Finder interface out of a Fetcher. 132 type finderFromFetcher struct { 133 f asserts.Fetcher 134 db asserts.RODatabase 135 } 136 137 func (fnd *finderFromFetcher) Find(assertionType *asserts.AssertionType, headers map[string]string) (asserts.Assertion, error) { 138 pk, err := asserts.PrimaryKeyFromHeaders(assertionType, headers) 139 if err != nil { 140 return nil, err 141 } 142 ref := &asserts.Ref{ 143 Type: assertionType, 144 PrimaryKey: pk, 145 } 146 if err := fnd.f.Fetch(ref); err != nil { 147 return nil, err 148 } 149 return fnd.db.Find(assertionType, headers) 150 } 151 152 // DeriveSideInfo tries to construct a SideInfo for the given snap 153 // using its digest to fetch the relevant snap assertions. It will 154 // fail with an asserts.NotFoundError if it cannot find them. 155 func DeriveSideInfo(snapPath string, rf RefAssertsFetcher, db asserts.RODatabase) (*snap.SideInfo, []*asserts.Ref, error) { 156 fnd := &finderFromFetcher{f: rf, db: db} 157 prev := len(rf.Refs()) 158 si, err := snapasserts.DeriveSideInfo(snapPath, fnd) 159 if err != nil { 160 return nil, nil, err 161 } 162 return si, rf.Refs()[prev:], nil 163 }