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