-
Notifications
You must be signed in to change notification settings - Fork 574
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: account for remodeling when installing prereqs as well as updating them #14137
Changes from 2 commits
6ae8f92
046dbf1
e0a62d6
5509871
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 |
---|---|---|
|
@@ -324,19 +324,28 @@ func (m *SnapManager) installOneBaseOrRequired(t *state.Task, snapName string, c | |
return nil, err | ||
} | ||
|
||
inProgress := func(snapName string) (bool, error) { | ||
shouldAttemptInstall := func(snapName string) (bool, error) { | ||
linkTask, err := findLinkSnapTaskForSnap(st, snapName) | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
if linkTask == nil { | ||
// snap is not being installed | ||
return true, nil | ||
} | ||
|
||
// if we are remodeling, then we should return early due to the way that | ||
// tasks are ordered by the remodeling code. specifically, all snap | ||
// downloads during a remodel happen prior to snap installation. thus, | ||
// we cannot wait for snaps to be installed here. see remodelTasks for | ||
// more information on how the tasks are ordered. | ||
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. wont' this be a problem also for updatePrereqIfOutdated code? doesn't it mean we should simply check this before all other checks and return early? instead of doing the check here? 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 spoke to Miguel about this earlier, because I was also confused about the ordering of the original code:
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. Just to clarify, that comment was about the 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. Hmm I see I was conflating them. 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. Then I misunderstood the question, my bad |
||
if deviceCtx.ForRemodeling() { | ||
return false, nil | ||
} | ||
|
||
// snap is being installed, retry later | ||
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. is this comment making sense in all cases now? 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. Updated to account for the refresh case |
||
return true, nil | ||
return false, onInFlight | ||
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'm not sure that return directly onInFlight is helpful here 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 return 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 reworked how this looks in the most recent commit. Since we don't actually want to go into |
||
} | ||
|
||
if isInstalled { | ||
|
@@ -346,28 +355,17 @@ func (m *SnapManager) installOneBaseOrRequired(t *state.Task, snapName string, c | |
} | ||
|
||
// other kind of dependency, check if it's in progress | ||
if ok, err := inProgress(snapName); err != nil { | ||
if _, err := shouldAttemptInstall(snapName); 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 looks a bit weird now. It's inside a 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 agree that the name isn't good. Unfortunately I haven't been able to come up with something better. 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. do we actually need this code inside the "if" now? wouldn't the code outside the "if" do the same in practice? 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. No, it can be dropped here to just always return |
||
return nil, err | ||
} else if ok { | ||
return nil, onInFlight | ||
} | ||
return nil, nil | ||
} | ||
|
||
// not installed, wait for it if it is. If not, we'll install it | ||
if ok, err := inProgress(snapName); err != nil { | ||
if ok, err := shouldAttemptInstall(snapName); err != nil { | ||
return nil, err | ||
} else if ok { | ||
// if we are remodeling, then we should return early due to the way that | ||
// tasks are ordered by the remodeling code. specifically, all snap | ||
// downloads during a remodel happen prior to snap installation. thus, | ||
// we cannot wait for snaps to be installed here. see remodelTasks for | ||
// more information on how the tasks are ordered. | ||
if deviceCtx.ForRemodeling() { | ||
return nil, nil | ||
} | ||
|
||
return nil, onInFlight | ||
} else if !ok { | ||
return nil, nil | ||
} | ||
|
||
// not installed, nor queued for install -> install it | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -403,6 +403,76 @@ func (s *prereqSuite) TestDoPrereqRetryWhenBaseInFlight(c *C) { | |
c.Check(chg.Status(), Equals, state.DoneStatus) | ||
} | ||
|
||
func (s *prereqSuite) TestDoPrereqNoRetryWhenBaseInFlightDuringRemodel(c *C) { | ||
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 could have other variants (skips when there's a install in progress, a possible update of a prereq, a missing base, etc) but maybe it's not worth it to add those right now since we want this merged soon |
||
restore := snapstate.MockPrerequisitesRetryTimeout(1 * time.Millisecond) | ||
defer restore() | ||
|
||
s.runner.AddHandler("link-snap", func(task *state.Task, _ *tomb.Tomb) error { | ||
st := task.State() | ||
st.Lock() | ||
defer st.Unlock() | ||
|
||
snapsup, err := snapstate.TaskSnapSetup(task) | ||
c.Assert(err, IsNil) | ||
fmt.Println(snapsup.InstanceName()) | ||
|
||
return nil | ||
}, nil) | ||
|
||
s.state.Lock() | ||
defer s.state.Unlock() | ||
|
||
restore = snapstatetest.MockDeviceContext(&snapstatetest.TrivialDeviceContext{ | ||
Remodeling: true, | ||
}) | ||
defer restore() | ||
|
||
// make it look like core is already installed | ||
snapstate.Set(s.state, "core", &snapstate.SnapState{ | ||
Active: true, | ||
Sequence: snapstatetest.NewSequenceFromSnapSideInfos([]*snap.SideInfo{ | ||
{RealName: "core", Revision: snap.R(1)}, | ||
}), | ||
Current: snap.R(1), | ||
SnapType: "os", | ||
}) | ||
|
||
// pretend foo gets installed and needs core (which we will make it look | ||
// like the install is in progress) | ||
prereqTask := s.state.NewTask("prerequisites", "foo") | ||
prereqTask.Set("snap-setup", &snapstate.SnapSetup{ | ||
SideInfo: &snap.SideInfo{ | ||
RealName: "foo", | ||
}, | ||
}) | ||
|
||
tCore := s.state.NewTask("link-snap", "Pretend core gets installed") | ||
tCore.Set("snap-setup", &snapstate.SnapSetup{ | ||
SideInfo: &snap.SideInfo{ | ||
RealName: "core", | ||
Revision: snap.R(11), | ||
}, | ||
}) | ||
|
||
// this makes sure that the prereq task runs first, but the link-snap task | ||
// for core will be found by the prereq task handler | ||
tCore.WaitFor(prereqTask) | ||
|
||
chg := s.state.NewChange("sample", "...") | ||
chg.AddTask(prereqTask) | ||
chg.AddTask(tCore) | ||
|
||
s.state.Unlock() | ||
s.se.Ensure() | ||
s.se.Wait() | ||
s.state.Lock() | ||
|
||
// prereq task is done, but the core task isn't done. this means that we | ||
// didn't wait for the core task to finish, since we are remodeling | ||
c.Check(prereqTask.Status(), Equals, state.DoneStatus) | ||
c.Check(tCore.Status(), Equals, state.DoStatus) | ||
} | ||
|
||
func (s *prereqSuite) TestDoPrereqChannelEnvvars(c *C) { | ||
os.Setenv("SNAPD_BASES_CHANNEL", "edge") | ||
defer os.Unsetenv("SNAPD_BASES_CHANNEL") | ||
|
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 then this name can go back to the old one? it's really a bit confusing for the usage inside
if isInstalled