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 }