-
Notifications
You must be signed in to change notification settings - Fork 576
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
o/snapstate: handle refreshing a snap that only has component revision changes #14486
Changes from 7 commits
f129277
95f7eb9
cea160f
eeb3824
14165a1
e21ad34
188128b
bc036e4
3712562
541066d
6d38bec
9254023
d838bc8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2714,7 +2714,7 @@ func (m *SnapManager) undoLinkSnap(t *state.Task, _ *tomb.Tomb) error { | |
return err | ||
} | ||
|
||
if len(snapst.Sequence.Revisions) == 1 { | ||
if oldCurrent.Unset() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this mean doing this only on firstInstall ? maybe is a good idea to call the name the predicate like that and use the var? I'm not entirely sure I understand the need for this change There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. During a refresh where we only refresh components, we treat it a lot like Naming the predicate to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added tests for this case here: 541066d |
||
// XXX: shouldn't these two just log and carry on? this is an undo handler... | ||
timings.Run(perfTimings, "discard-snap-namespace", fmt.Sprintf("discard the namespace of snap %q", snapsup.InstanceName()), func(tm timings.Measurer) { | ||
err = m.backend.DiscardSnapNamespace(snapsup.InstanceName()) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -523,12 +523,16 @@ func (m *SnapManager) doUnlinkCurrentComponent(t *state.Task, _ *tomb.Tomb) (err | |
defer st.Unlock() | ||
|
||
// snapSt is a copy of the current state | ||
compSetup, _, snapSt, err := compSetupAndState(t) | ||
compSetup, snapsup, snapSt, err := compSetupAndState(t) | ||
if err != nil { | ||
return err | ||
} | ||
cref := compSetup.CompSideInfo.Component | ||
|
||
if err := saveCurrentKernelModuleComponents(t, snapsup, snapSt); err != nil { | ||
return err | ||
} | ||
|
||
// Expected to be installed | ||
snapInfo, err := snapSt.CurrentInfo() | ||
if err != nil { | ||
|
@@ -561,12 +565,6 @@ func (m *SnapManager) doUnlinkComponent(t *state.Task, _ *tomb.Tomb) (err error) | |
return err | ||
} | ||
|
||
// TODO:COMPS: test taking this branch when unlinking components during a | ||
// refresh where we lose components | ||
if err := saveCurrentKernelModuleComponents(t, snapSup, snapSt); err != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was in the wrong place. We now do this in these 3 places:
Previously we had it in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are we sure we do not need to save the kernel-modules components here too? For instance, if we are removing one of these components, to get the state restored on rollback. I'm not sure if in that case we do an unlink current component. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In that case we use "unlink-current-component", since we don't support removing components for anything but the current snap revision. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
return err | ||
} | ||
|
||
cref := compSetup.CompSideInfo.Component | ||
// Remove component for the specified revision | ||
if err := m.unlinkComponent( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -453,8 +453,14 @@ func doInstall(st *state.State, snapst *SnapState, snapsup SnapSetup, compsups [ | |
addTask(t) | ||
} | ||
|
||
// run refresh hooks when updating existing snap, otherwise run install hook further down. | ||
runRefreshHooks := snapst.IsInstalled() && !snapsup.Flags.Revert | ||
// if the snap is already installed, and the revision we are refreshing to | ||
// is the same as the current revision, and we're not forcing an update, | ||
// then we know that we're really modifying the state of components. | ||
componentOnlyUpdate := snapst.IsInstalled() && snapsup.Revision() == snapst.Current && !snapsup.AlwaysUpdate | ||
|
||
// run refresh hooks when updating existing snap, otherwise run install hook | ||
// further down. | ||
runRefreshHooks := snapst.IsInstalled() && !componentOnlyUpdate && !snapsup.Flags.Revert | ||
if runRefreshHooks { | ||
preRefreshHook := SetupPreRefreshHook(st, snapsup.InstanceName()) | ||
addTask(preRefreshHook) | ||
|
@@ -620,8 +626,6 @@ func doInstall(st *state.State, snapst *SnapState, snapsup SnapSetup, compsups [ | |
startSnapServices := st.NewTask("start-snap-services", fmt.Sprintf(i18n.G("Start snap %q%s services"), snapsup.InstanceName(), revisionStr)) | ||
addTask(startSnapServices) | ||
|
||
// TODO:COMPS: test discarding components during a snap refresh (coming | ||
// soon!) | ||
for _, t := range tasksBeforeDiscard { | ||
addTask(t) | ||
} | ||
|
@@ -776,7 +780,7 @@ func splitComponentTasksForInstall( | |
|
||
tasksBeforePreRefreshHook = append(tasksBeforePreRefreshHook, componentTS.beforeLink...) | ||
tasksAfterLinkSnap = append(tasksAfterLinkSnap, componentTS.linkTask) | ||
tasksAfterPostOpHook = append(tasksAfterPostOpHook, componentTS.postOpHookAndAfter...) | ||
tasksAfterPostOpHook = append(tasksAfterPostOpHook, componentTS.postOpHookToDiscard...) | ||
if componentTS.discardTask != nil { | ||
tasksBeforeDiscard = append(tasksBeforeDiscard, componentTS.discardTask) | ||
} | ||
|
@@ -1881,12 +1885,32 @@ type update struct { | |
// revision of the snap. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it seems the doc comment for this needs changes, also I wonder if turning this around and calling it revisionDiverged wouldn't be clear? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I personally think that "satisfied" works better here as a method on |
||
// | ||
// TODO:COMPS: check if we need to change the state of components | ||
andrewphelpsj marked this conversation as resolved.
Show resolved
Hide resolved
|
||
func (u *update) revisionSatisfied() bool { | ||
func (u *update) revisionSatisfied() (bool, error) { | ||
if u.Setup.AlwaysUpdate || !u.SnapState.IsInstalled() { | ||
return false | ||
return false, nil | ||
} | ||
|
||
if u.SnapState.Current != u.Setup.Revision() { | ||
return false, nil | ||
} | ||
|
||
comps, err := u.SnapState.CurrentComponentInfos() | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
return u.SnapState.Current == u.Setup.Revision() | ||
currentCompRevs := make(map[string]snap.Revision, len(comps)) | ||
for _, comp := range comps { | ||
currentCompRevs[comp.Component.ComponentName] = comp.Revision | ||
} | ||
|
||
for _, comp := range u.Components { | ||
if currentCompRevs[comp.CompSideInfo.Component.ComponentName] != comp.Revision() { | ||
return false, nil | ||
} | ||
} | ||
alfonsosanchezbeato marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
return true, nil | ||
} | ||
|
||
func doPotentiallySplitUpdate(st *state.State, requested []string, updates []update, opts Options) ([]string, *UpdateTaskSets, error) { | ||
|
@@ -1991,7 +2015,12 @@ func doUpdate(st *state.State, requested []string, updates []update, opts Option | |
// and bases and then other snaps | ||
for _, up := range updates { | ||
// if the update is already satisfied, then we can skip it | ||
if up.revisionSatisfied() { | ||
ok, err := up.revisionSatisfied() | ||
if err != nil { | ||
return nil, false, nil, err | ||
} | ||
|
||
if ok { | ||
alreadySatisfied = append(alreadySatisfied, up) | ||
continue | ||
} | ||
|
@@ -2267,7 +2296,12 @@ func autoAliasesUpdate(st *state.State, requested []string, updates []update) (c | |
// snaps with updates | ||
updating := make(map[string]bool, len(updates)) | ||
for _, up := range updates { | ||
updating[up.Setup.InstanceName()] = !up.revisionSatisfied() | ||
ok, err := up.revisionSatisfied() | ||
if err != nil { | ||
return nil, nil, nil, err | ||
} | ||
|
||
updating[up.Setup.InstanceName()] = !ok | ||
} | ||
|
||
// add explicitly auto-aliases only for snaps that are not updated | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does ToDiscard means here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The range of the tasks, [post-refresh/install hook -> discard). I'm happy to take suggestions on naming there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe all *state.Task field should have a name ending in "Task", and all the []*state.Task ones, one ending in "Tasks" ?