github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/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  }