gopkg.in/ubuntu-core/snappy.v0@v0.0.0-20210902073436-25a8614f10a6/overlord/patch/patch6_2.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2018 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 patch
    21  
    22  import (
    23  	"encoding/json"
    24  	"fmt"
    25  	"time"
    26  
    27  	"github.com/snapcore/snapd/overlord/state"
    28  	"github.com/snapcore/snapd/snap"
    29  )
    30  
    31  type patch62SideInfo struct {
    32  	RealName          string        `yaml:"name,omitempty" json:"name,omitempty"`
    33  	SnapID            string        `yaml:"snap-id" json:"snap-id"`
    34  	Revision          snap.Revision `yaml:"revision" json:"revision"`
    35  	Channel           string        `yaml:"channel,omitempty" json:"channel,omitempty"`
    36  	Contact           string        `yaml:"contact,omitempty" json:"contact,omitempty"`
    37  	EditedTitle       string        `yaml:"title,omitempty" json:"title,omitempty"`
    38  	EditedSummary     string        `yaml:"summary,omitempty" json:"summary,omitempty"`
    39  	EditedDescription string        `yaml:"description,omitempty" json:"description,omitempty"`
    40  	Private           bool          `yaml:"private,omitempty" json:"private,omitempty"`
    41  	Paid              bool          `yaml:"paid,omitempty" json:"paid,omitempty"`
    42  }
    43  
    44  type patch62Flags struct {
    45  	DevMode          bool `json:"devmode,omitempty"`
    46  	JailMode         bool `json:"jailmode,omitempty"`
    47  	Classic          bool `json:"classic,omitempty"`
    48  	TryMode          bool `json:"trymode,omitempty"`
    49  	Revert           bool `json:"revert,omitempty"`
    50  	RemoveSnapPath   bool `json:"remove-snap-path,omitempty"`
    51  	IgnoreValidation bool `json:"ignore-validation,omitempty"`
    52  	Required         bool `json:"required,omitempty"`
    53  	SkipConfigure    bool `json:"skip-configure,omitempty"`
    54  	Unaliased        bool `json:"unaliased,omitempty"`
    55  	Amend            bool `json:"amend,omitempty"`
    56  	IsAutoRefresh    bool `json:"is-auto-refresh,omitempty"`
    57  	NoReRefresh      bool `json:"no-rerefresh,omitempty"`
    58  	RequireTypeBase  bool `json:"require-base-type,omitempty"`
    59  }
    60  
    61  type patch62SnapState struct {
    62  	SnapType string             `json:"type"`
    63  	Sequence []*patch62SideInfo `json:"sequence"`
    64  	Active   bool               `json:"active,omitempty"`
    65  	Current  snap.Revision      `json:"current"`
    66  	Channel  string             `json:"channel,omitempty"`
    67  	patch62Flags
    68  	Aliases              interface{} `json:"aliases,omitempty"`
    69  	AutoAliasesDisabled  bool        `json:"auto-aliases-disabled,omitempty"`
    70  	AliasesPending       bool        `json:"aliases-pending,omitempty"`
    71  	UserID               int         `json:"user-id,omitempty"`
    72  	InstanceKey          string      `json:"instance-key,omitempty"`
    73  	CohortKey            string      `json:"cohort-key,omitempty"`
    74  	RefreshInhibitedTime *time.Time  `json:"refresh-inhibited-time,omitempty"`
    75  }
    76  
    77  type patch62SnapSetup struct {
    78  	Channel   string    `json:"channel,omitempty"`
    79  	UserID    int       `json:"user-id,omitempty"`
    80  	Base      string    `json:"base,omitempty"`
    81  	Type      snap.Type `json:"type,omitempty"`
    82  	PlugsOnly bool      `json:"plugs-only,omitempty"`
    83  	CohortKey string    `json:"cohort-key,omitempty"`
    84  	Prereq    []string  `json:"prereq,omitempty"`
    85  	patch62Flags
    86  	SnapPath     string           `json:"snap-path,omitempty"`
    87  	DownloadInfo interface{}      `json:"download-info,omitempty"`
    88  	SideInfo     *patch62SideInfo `json:"side-info,omitempty"`
    89  	patch62auxStoreInfo
    90  	InstanceKey string `json:"instance-key,omitempty"`
    91  }
    92  
    93  type patch62auxStoreInfo struct {
    94  	Media interface{} `json:"media,omitempty"`
    95  }
    96  
    97  func hasSnapdSnapID(snapst patch62SnapState) bool {
    98  	for _, seq := range snapst.Sequence {
    99  		if snap.IsSnapd(seq.SnapID) {
   100  			return true
   101  		}
   102  	}
   103  	return false
   104  }
   105  
   106  // patch6_2:
   107  //  - ensure snapd snaps in the snapstate have TypeSnapd for backward compatibility with old snapd snap releases.
   108  //  - ensure snapd snaps have TypeSnapd in pending install tasks.
   109  func patch6_2(st *state.State) error {
   110  	var snaps map[string]*json.RawMessage
   111  	if err := st.Get("snaps", &snaps); err != nil && err != state.ErrNoState {
   112  		return fmt.Errorf("internal error: cannot get snaps: %s", err)
   113  	}
   114  
   115  	var hasSnapdSnap bool
   116  	// check if we have snapd snap with TypeSnapd already in state, in such case
   117  	// we shouldn't try to migrate any other snaps because we can have at most
   118  	// one snapd snap.
   119  	for _, raw := range snaps {
   120  		var snapst patch62SnapState
   121  		if err := json.Unmarshal([]byte(*raw), &snapst); err != nil {
   122  			return err
   123  		}
   124  		if hasSnapdSnapID(snapst) && snapst.SnapType == string(snap.TypeSnapd) {
   125  			hasSnapdSnap = true
   126  			break
   127  		}
   128  	}
   129  
   130  	// Migrate snapstate unless we have a snapd snap with TypeSnapd already set.
   131  	if !hasSnapdSnap {
   132  		for name, raw := range snaps {
   133  			var snapst patch62SnapState
   134  			if err := json.Unmarshal([]byte(*raw), &snapst); err != nil {
   135  				return err
   136  			}
   137  			if hasSnapdSnapID(snapst) {
   138  				snapst.SnapType = string(snap.TypeSnapd)
   139  				data, err := json.Marshal(snapst)
   140  				if err != nil {
   141  					return err
   142  				}
   143  				newRaw := json.RawMessage(data)
   144  				snaps[name] = &newRaw
   145  				st.Set("snaps", snaps)
   146  				// We can have at most one snapd snap
   147  				break
   148  			}
   149  		}
   150  	}
   151  
   152  	// migrate tasks' snap setup
   153  	for _, task := range st.Tasks() {
   154  		chg := task.Change()
   155  		if chg != nil && chg.Status().Ready() {
   156  			continue
   157  		}
   158  
   159  		var snapsup patch62SnapSetup
   160  		err := task.Get("snap-setup", &snapsup)
   161  		if err != nil && err != state.ErrNoState {
   162  			return fmt.Errorf("internal error: cannot get snap-setup of task %s: %s", task.ID(), err)
   163  		}
   164  
   165  		if err == nil && snapsup.SideInfo != nil {
   166  			if snapsup.Type != snap.TypeSnapd && snap.IsSnapd(snapsup.SideInfo.SnapID) {
   167  				snapsup.Type = snap.TypeSnapd
   168  				task.Set("snap-setup", snapsup)
   169  			}
   170  		}
   171  	}
   172  	return nil
   173  }