Skip to content

overlord/snapstate: figure out satisfied installation targets when intstalling from store#16705

Draft
bboozzoo wants to merge 1 commit intocanonical:masterfrom
bboozzoo:bboozzoo/snapstate-already-satisfied-install-many
Draft

overlord/snapstate: figure out satisfied installation targets when intstalling from store#16705
bboozzoo wants to merge 1 commit intocanonical:masterfrom
bboozzoo:bboozzoo/snapstate-already-satisfied-install-many

Conversation

@bboozzoo
Copy link
Contributor

@bboozzoo bboozzoo commented Mar 3, 2026

The store installation goal supports skipping snaps which are already satisfied. In an extreme case, all requested snaps could already be installed in the system, which should not produce any installation tasks.

Thanks for helping us make a better snapd!
Have you signed the license agreement and read the contribution guide?

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the store install goal logic in overlord/snapstate so that snaps already present on the system (when SkipIfPresent is used) are treated as “satisfied” and do not generate installation tasks—allowing InstallMany to succeed with no tasks when everything is already installed.

Changes:

  • Track and surface “satisfied” snaps during storeInstallGoal.validateAndPrune, and avoid sending store install actions when nothing remains to install.
  • Extend target with a satisfied flag and update InstallWithGoal to skip task creation for satisfied targets while still returning their snap.Info.
  • Update/add unit tests to cover empty installs and installs where some/all snaps are already present.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
overlord/snapstate/target.go Adds satisfied-target handling to pruning and install planning, and skips task creation for already-installed snaps.
overlord/snapstate/snapstate_install_test.go Updates expectations for empty install lists and adds coverage for partially/fully satisfied InstallMany calls.
Comments suppressed due to low confidence (2)

overlord/snapstate/target.go:772

  • validateAndPrune appends to s.satisfied but never resets it. If a storeInstallGoal instance is reused across calls, previously satisfied snaps will leak into subsequent operations and produce duplicate/incorrect satisfied targets. Consider clearing s.satisfied at the start of validateAndPrune (similar to how s.snaps is rewritten) or making toInstall/validateAndPrune treat this field as strictly local state.
		snapst, ok := installedSnaps[sn.InstanceName]
		if ok && snapst.IsInstalled() {
			if !sn.SkipIfPresent {
				return &snap.AlreadyInstalledError{Snap: sn.InstanceName}
			}
			s.satisfied = append(s.satisfied, snapst)
			continue
		}

overlord/snapstate/snapstate_install_test.go:6623

  • The comment says this is a taskset for "other-snap installation", but in this test other-snap is already present and the single taskset should correspond to installing some-snap. Please update the comment to match the assertion below.
	// one taskset for other-snap installation
	c.Assert(tss, HasLen, 1)

}

return installs, err
return append(installs, satisfiedTargets...), err
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

toInstall appends satisfiedTargets after installs, which can reorder results vs the original request order when a satisfied snap appears before a snap that still needs installation (e.g. [present, missing] becomes [missing, present]). This breaks the stated ordering guarantee on storeInstallGoal.snaps and can affect task ordering/lane grouping. Consider rebuilding the final []target in the original requested order (e.g. keep an ordered list of requested instance names and map name->target for both installed and store results).

Suggested change
return append(installs, satisfiedTargets...), err
// Combine installs and already-satisfied snaps into a single slice and impose
// a deterministic ordering that does not depend on whether the snap needs
// installation. This avoids reordering relative to each other based solely
// on satisfaction state.
allTargets := make([]target, 0, len(installs)+len(satisfiedTargets))
allTargets = append(allTargets, installs...)
allTargets = append(allTargets, satisfiedTargets...)
sort.SliceStable(allTargets, func(i, j int) bool {
return allTargets[i].info.InstanceName() < allTargets[j].info.InstanceName()
})
return allTargets, err

Copilot uses AI. Check for mistakes.
Comment on lines +860 to +875
if t.satisfied {
infos = append(infos, t.info)
continue
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

Satisfied targets are still included in installInfos (built before the loop that skips t.satisfied) and therefore participate in checkDiskSpace/installSize. Since CurrentInfo() (used for satisfied targets) does not populate Info.DownloadInfo, this can trigger internal error: download info missing when disk-space checking is enabled. Exclude satisfied targets from installInfos (and disk-space checks) or otherwise ensure they have valid download info.

Copilot uses AI. Check for mistakes.
@codecov
Copy link

codecov bot commented Mar 3, 2026

Codecov Report

❌ Patch coverage is 84.31373% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.54%. Comparing base (17f7243) to head (e091519).
⚠️ Report is 3 commits behind head on master.

Files with missing lines Patch % Lines
overlord/snapstate/target.go 84.31% 5 Missing and 3 partials ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##           master   #16705   +/-   ##
=======================================
  Coverage   77.54%   77.54%           
=======================================
  Files        1360     1360           
  Lines      187369   187335   -34     
  Branches     2446     2446           
=======================================
- Hits       145289   145274   -15     
+ Misses      33304    33288   -16     
+ Partials     8776     8773    -3     
Flag Coverage Δ
unittests 77.54% <84.31%> (+<0.01%) ⬆️

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

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@bboozzoo bboozzoo force-pushed the bboozzoo/snapstate-already-satisfied-install-many branch from 99d6c8e to bab7912 Compare March 3, 2026 09:09
@bboozzoo bboozzoo requested a review from Copilot March 3, 2026 09:09
@github-actions
Copy link

github-actions bot commented Mar 3, 2026

Tue Mar 3 11:05:43 UTC 2026
The following results are from: https://github.com/canonical/snapd/actions/runs/22616593690

Failures:

Preparing:

  • openstack:ubuntu-20.04-64:tests/main/nss-modules:nis

Executing:

  • openstack:ubuntu-core-20-64:tests/core/snapd-maintenance-msg
  • openstack:ubuntu-core-20-64:tests/main/catalog-update
  • openstack:ubuntu-core-24-64:tests/core/gadget-update-pc
  • openstack:ubuntu-core-24-64:tests/main/snap-user-service-restart-on-upgrade
  • openstack:ubuntu-20.04-64:tests/main/interface-allow-auto-connection:true
  • openstack:ubuntu-20.04-64:tests/main/catalog-update
  • openstack:ubuntu-25.10-64:tests/main/snap-quota-memory
  • openstack:ubuntu-25.10-64:tests/main/try
  • openstack:ubuntu-24.04-64:tests/main/snap-sign:file

Restoring:

  • openstack:ubuntu-core-20-64:tests/core/snapd-maintenance-msg
  • openstack:ubuntu-core-20-64:tests/core/
  • openstack:ubuntu-core-20-64:
  • openstack:ubuntu-core-24-64:tests/core/gadget-update-pc
  • openstack:ubuntu-core-24-64:tests/core/
  • openstack:ubuntu-core-24-64:

Skipped tests from snapd-testing-skip

  • openstack:ubuntu-24.04-64:tests/main/i18n

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

overlord/snapstate/snapstate_install_test.go:6623

  • The comment says "one taskset for other-snap installation" but this test is asserting the task set installs some-snap (and other-snap is the already-present snap). Updating the comment will avoid confusion when reading/fixing this test later.
	// one taskset for other-snap installation
	c.Assert(tss, HasLen, 1)

…stalling from store

The store installation goal supports skipping snaps which are already
satisfied. In an extreme case, all requested snaps could already be
installed in the system, which should not produce any installation
tasks.

Signed-off-by: Maciej Borzecki <maciej.borzecki@canonical.com>
@bboozzoo bboozzoo force-pushed the bboozzoo/snapstate-already-satisfied-install-many branch from bab7912 to e091519 Compare March 3, 2026 09:26
Copy link
Contributor

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

do the places that call InstallMany do the right thing we they get empty tss and tasks?

@bboozzoo bboozzoo marked this pull request as draft March 3, 2026 16:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants