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: deduplicate snap names in remove/install/update #10910

Merged
merged 2 commits into from Oct 25, 2021

Conversation

MiguelPires
Copy link
Contributor

@MiguelPires MiguelPires commented Oct 12, 2021

Calling snap remove, install or refresh with the same snap name twice was causes the operation to succeed once and fail with strange errors. This PR extends the validation of snapstate operations to prevent calling these operations with duplicate snap names. It also adds validation of the snap name format to some operations that didn't have it previously. This PR deduplicates the snap names passed into remove, install and update.

https://bugs.launchpad.net/snapd/+bug/1843725

@MiguelPires MiguelPires added the Simple 😃 A small PR which can be reviewed quickly label Oct 12, 2021
mardy
mardy previously approved these changes Oct 12, 2021
Copy link
Contributor

@mardy mardy left a comment

Choose a reason for hiding this comment

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

LGTM, just a minor question inline.

// * is duplicated in the list
func validateSnapNames(op string, names []string) error {
if invalidNames := findInvalidSnapNames(names); len(invalidNames) > 0 {
return fmt.Errorf("cannot %s due to invalid snap names: %v", op, strings.Join(invalidNames, ", "))
Copy link
Contributor

Choose a reason for hiding this comment

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

Why aren't you just passing invalidNames to fmt.Errorf? It should be doing the string concatenation itself.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thought it looked simpler without the brackets around the list. I can change it though, it's not a strong opinion

Copy link
Contributor

Choose a reason for hiding this comment

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

Mine is not strong either, I was mostly curious :-) Let's see what others say.

@codecov-commenter
Copy link

codecov-commenter commented Oct 12, 2021

Codecov Report

Merging #10910 (0e16c10) into master (8373aa5) will increase coverage by 0.00%.
The diff coverage is 100.00%.

Impacted file tree graph

@@           Coverage Diff           @@
##           master   #10910   +/-   ##
=======================================
  Coverage   78.18%   78.18%           
=======================================
  Files         910      910           
  Lines      102783   102781    -2     
=======================================
+ Hits        80360    80363    +3     
+ Misses      17404    17398    -6     
- Partials     5019     5020    +1     
Flag Coverage Δ
unittests 78.18% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
overlord/snapstate/snapstate.go 78.26% <100.00%> (+0.05%) ⬆️
strutil/strutil.go 99.39% <100.00%> (+0.03%) ⬆️
osutil/disks/labels.go 81.57% <0.00%> (-4.32%) ⬇️
store/cache.go 69.23% <0.00%> (-1.93%) ⬇️
overlord/hookstate/ctlcmd/refresh.go 71.56% <0.00%> (-0.09%) ⬇️
cmd/snap/cmd_snap_op.go 77.93% <0.00%> (+0.13%) ⬆️
overlord/ifacestate/handlers.go 65.02% <0.00%> (+0.14%) ⬆️
overlord/snapstate/autorefresh_gating.go 77.48% <0.00%> (+0.39%) ⬆️
cmd/snap/cmd_debug_state.go 70.64% <0.00%> (+0.45%) ⬆️
osutil/synctree.go 79.24% <0.00%> (+2.83%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 8373aa5...0e16c10. Read the comment docs.

Copy link
Collaborator

@bboozzoo bboozzoo left a comment

Choose a reason for hiding this comment

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

LGTM

// (only one condition needs to be met):
// * differs from the expected format
// * is duplicated in the list
func validateSnapNames(op string, names []string) error {
Copy link
Collaborator

Choose a reason for hiding this comment

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

since we're changing it, this should probably be named like validateSnapNamesForOp(...) since a generic validation would probably be placed in snap/naming, and this one here is operation specific and returns an contextualized error.

@@ -1195,6 +1199,10 @@ func UpdateMany(ctx context.Context, st *state.State, names []string, userID int
type updateFilter func(*snap.Info, *SnapState) bool

func updateManyFiltered(ctx context.Context, st *state.State, names []string, userID int, filter updateFilter, flags *Flags, fromChange string) ([]string, []*state.TaskSet, error) {
if err := validateSnapNames("refresh", names); 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.

Also, for refresh, passing duplicates worked before. I wonder if changing this now can break people. It's probably useful to get a second opinion from @pedronis

Copy link
Collaborator

Choose a reason for hiding this comment

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

my thinking is if refresh worked so far, to just make duplicate names in install also work by coalescing them, so:

"snap install|refresh foo bar foo baz" is simply the same as "snap install|refresh foo bar baz"

scripts using env variables might be scenarios where this kind of thing happens

@pedronis pedronis added Needs Samuele review Needs a review from Samuele before it can land ⛔ Blocked labels Oct 18, 2021
@pedronis pedronis self-requested a review October 18, 2021 08:28
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.

as commented we should probably make duplicates work by coalescing them also in install if they worked in refresh so far anyway

@MiguelPires
Copy link
Contributor Author

I forced-pushed since the new code doesn't have much in common with the previous one. The new version deduplicates the snap names pass into *Many functions. I'll update the PR title to reflect this

@MiguelPires MiguelPires changed the title o/snapstate: check snaps for duplicate or invalid names o/snapstate: deduplicate snap names in remove/install/update Oct 20, 2021
Copy link
Collaborator

@bboozzoo bboozzoo left a comment

Choose a reason for hiding this comment

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

LGTM with little tweaks


installed, ts, err := snapstate.InstallMany(s.state, []string{"some-snap", "some-base", "some-snap", "some-base"}, s.user.ID)
c.Assert(err, IsNil)
c.Check(installed, testutil.DeepUnsortedMatches, []string{"some-snap", "some-base"})
Copy link
Collaborator

Choose a reason for hiding this comment

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

you can probably use DeepEquals as the order is preserved

Suggested change
c.Check(installed, testutil.DeepUnsortedMatches, []string{"some-snap", "some-base"})
c.Check(installed, DeepEquals, []string{"some-snap", "some-base"})

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's true for install but for UpdateMany we actually invert the order

}{
{input: []string{"a", "b", "c"}, output: []string{"a", "b", "c"}},
{input: []string{"a", "b", "a"}, output: []string{"a", "b"}},
{input: []string{"a", "a", "a", "a", "b", "b", "a"}, output: []string{"a", "b"}},
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
{input: []string{"a", "a", "a", "a", "b", "b", "a"}, output: []string{"a", "b"}},
// order of of first occurrence is preserved
{input: []string{"a", "a", "a", "c", "a", "b", "b", "a"}, output: []string{"a", "c", "b"}},

@pedronis pedronis dismissed mardy’s stale review October 21, 2021 14:33

this has changed since

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.

thanks

@mvo5 mvo5 merged commit fa19474 into snapcore:master Oct 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
⛔ Blocked Needs Samuele review Needs a review from Samuele before it can land Simple 😃 A small PR which can be reviewed quickly
Projects
None yet
6 participants