Skip to content
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

Merged

Conversation

andrewphelpsj
Copy link
Member

In #14088 I broke tests/nested/manual/hybrid-remodel when attempting to fix a different bug. By moving the remodeling check, I accidentally omitted checking for remodeling when updating a prereq. This change makes sure that we check for remodeling when installing and updating prereqs.

@andrewphelpsj andrewphelpsj added the Run nested The PR also runs tests inluded in nested suite label Jun 27, 2024
@andrewphelpsj andrewphelpsj reopened this Jun 27, 2024
Copy link
Collaborator

@pedronis pedronis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it feels that we need some matching unit test(s) to capture these behaviors, that would have avoided the regression being surface only by spread?

@valentindavid
Copy link
Contributor

There are still lots of failures in spread tests related to remodel.

…hat might be getting updated during a remodel
Copy link
Contributor

@MiguelPires MiguelPires left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM for the fix, but the function is a bit strangely named now. It'd be nice to clean it up a bit but not a blocker for this PR

@@ -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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks a bit weird now. It's inside a isInstalled case but we run a shouldAttemptInstall check? It's also inconsistent with the comment above it.
Tbh the original is also not great, since it has more logic to it than than just checking if the snap is running

Copy link
Member Author

Choose a reason for hiding this comment

The 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.

@pedronis pedronis added this to the 2.64 milestone Jul 1, 2024
@pedronis pedronis added the ⚠ Critical High-priority stuff (e.g. to fix master) label Jul 1, 2024
Copy link
Collaborator

@pedronis pedronis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wondering whether the code can't be simplified further now

@@ -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 {
Copy link
Collaborator

Choose a reason for hiding this comment

The 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?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it can be dropped here to just always return err, regardless if nil or not.

// 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 false, nil
}

// snap is being installed, retry later
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this comment making sense in all cases now?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to account for the refresh case

Copy link
Collaborator

@pedronis pedronis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did another pass, some questions/comments

// 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.
Copy link
Collaborator

Choose a reason for hiding this comment

The 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?

Copy link
Member Author

Choose a reason for hiding this comment

The 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:

Those are mutually exclusive, unless I'm misunderstanding the question. The first if runs when the prerequisite is a default provider and the rest runs if it's another type of dependency (base, snapd). So that checks doesn't run after updating. Also the updatePrereqIfOutdated has code to check if its already being updated so it would catch a conflict

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, that comment was about the inProgress check vs the updatePrereqIfOutdated call which was the code snippet in the link. It wasn't about the remodel check

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I see I was conflating them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I misunderstood the question, my bad

// snap is being installed, retry later
return true, nil
// snap is either being installed or updated
return false, onInFlight
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that return directly onInFlight is helpful here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I return onInFlight here to distinguish between when we are remodeling or when we aren't.

Copy link
Member Author

@andrewphelpsj andrewphelpsj Jul 2, 2024

Choose a reason for hiding this comment

The 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 updatePrereqIfOutdated during a remodel since it tries to reach out to the store (we should have already downloaded all the snaps needed for the remodel, cc @MiguelPires to make sure I'm not lying), I think we can just move the check for remodeling earlier in the function.

@@ -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) {
Copy link
Collaborator

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

… want to update prereqs during a remodel anyways
Copy link
Contributor

@MiguelPires MiguelPires left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@@ -403,6 +403,76 @@ func (s *prereqSuite) TestDoPrereqRetryWhenBaseInFlight(c *C) {
c.Check(chg.Status(), Equals, state.DoneStatus)
}

func (s *prereqSuite) TestDoPrereqNoRetryWhenBaseInFlightDuringRemodel(c *C) {
Copy link
Contributor

Choose a reason for hiding this comment

The 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

// 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I misunderstood the question, my bad

Copy link
Collaborator

@pedronis pedronis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you

@alfonsosanchezbeato alfonsosanchezbeato merged commit 015a2e4 into canonical:master Jul 2, 2024
47 of 51 checks passed
@andrewphelpsj andrewphelpsj deleted the fix-hybrid-remodel branch July 2, 2024 19:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
⚠ Critical High-priority stuff (e.g. to fix master) Run nested The PR also runs tests inluded in nested suite
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants