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  }