Skip to content

Commit

Permalink
cmd/snap-update-ns: add CurrentProfileFromChanges made
Browse files Browse the repository at this point in the history
The new function takes the previously existing algorithm out of
executeMountProfileUpdate, as the original location makes it very tricky
to test due to the presence of all the system interactions through
change.Perform.

Add some simple tests that show how keep, mount and unmount changes are
preserved.

Signed-off-by: Zygmunt Krynicki <[email protected]>
  • Loading branch information
zyga committed Sep 23, 2024
1 parent 0620679 commit 4404ec1
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 7 deletions.
37 changes: 30 additions & 7 deletions cmd/snap-update-ns/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,40 @@ func executeMountProfileUpdate(upCtx MountProfileUpdateContext) error {

// Compute the new current profile so that it contains only changes that were made
// and save it back for next runs.
var currentAfter osutil.MountProfile
for i := len(changesMade) - 1; i >= 0; i-- {
change := changesMade[i]
currentAfter := CurrentProfileFromChangesMade(changesMade)
return upCtx.SaveCurrentProfile(&currentAfter)
}

// CurrentProfileFromChangesMade computes a new mount profile a slice of changes.
//
// The return value collects mount profile entries from changes of type "mount"
// and "keep" while discarding the changes of type "unmount". The order in
// which entries are collected depends on their type.
//
// The sequence of changes, as produced by NeededChanges, is computed by
// looking at two mount profiles, examining the most recent change and working
// backwards. Since the most recent change is the last entry in the mount
// profile, the first change describes the last mount entry of the old mount
// profile.
//
// The "keep" changes are thus collected in reverse order - the order of their
// true appearance, while "mount" changes are collected in the order of their
// appearance as this represents the actual order of performed mount
// operations.
func CurrentProfileFromChangesMade(changes []*Change) osutil.MountProfile {
var profile osutil.MountProfile

for i := len(changes) - 1; i >= 0; i-- {
change := changes[i]
if change.Action == Keep {
currentAfter.Entries = append(currentAfter.Entries, change.Entry)
profile.Entries = append(profile.Entries, change.Entry)
}
}
for _, change := range changesMade {
for _, change := range changes {
if change.Action == Mount {
currentAfter.Entries = append(currentAfter.Entries, change.Entry)
profile.Entries = append(profile.Entries, change.Entry)
}
}
return upCtx.SaveCurrentProfile(&currentAfter)

return profile
}
58 changes: 58 additions & 0 deletions cmd/snap-update-ns/update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,64 @@ func (s *updateSuite) TestKeepSyntheticMountsLP2043993(c *C) {
c.Check(saved.Entries[1], DeepEquals, desiredMountEntry)
}

func (s *updateSuite) TestCurrentProfileFromChangesMade(c *C) {
// Changes are computed back-to-front, starting from the last entry in
// the mount profile.
changes := []*update.Change{
{Action: update.Mount, Entry: osutil.MountEntry{Dir: "/dir-1"}},
{Action: update.Mount, Entry: osutil.MountEntry{Dir: "/dir-2"}},
{Action: update.Mount, Entry: osutil.MountEntry{Dir: "/dir-3"}},
}
profile := update.CurrentProfileFromChangesMade(changes)
c.Check(profile, DeepEquals, osutil.MountProfile{Entries: []osutil.MountEntry{
{Dir: "/dir-1"},
{Dir: "/dir-2"},
{Dir: "/dir-3"},
}})

// When we keep a number of entries we are not still processing them
// back-to-front but the order of actual changes is front-to-back.
changes = []*update.Change{
{Action: update.Keep, Entry: osutil.MountEntry{Dir: "/dir-3"}},
{Action: update.Keep, Entry: osutil.MountEntry{Dir: "/dir-2"}},
{Action: update.Keep, Entry: osutil.MountEntry{Dir: "/dir-1"}},
}
profile = update.CurrentProfileFromChangesMade(changes)
c.Check(profile, DeepEquals, osutil.MountProfile{Entries: []osutil.MountEntry{
{Dir: "/dir-1"},
{Dir: "/dir-2"},
{Dir: "/dir-3"},
}})

// When we unmount things they just don't appear in the resulting profile.
changes = []*update.Change{
{Action: update.Unmount, Entry: osutil.MountEntry{Dir: "/dir-1"}},
{Action: update.Unmount, Entry: osutil.MountEntry{Dir: "/dir-2"}},
{Action: update.Unmount, Entry: osutil.MountEntry{Dir: "/dir-3"}},
}
profile = update.CurrentProfileFromChangesMade(changes)
c.Check(profile, DeepEquals, osutil.MountProfile{})

// When we have a mixture of changes unmount entries are removed, keep
// entries are retained first, back to front and then mount entries are
// retained in the order in which they were executed.
changes = []*update.Change{
{Action: update.Unmount, Entry: osutil.MountEntry{Dir: "/old-2"}},
{Action: update.Unmount, Entry: osutil.MountEntry{Dir: "/old-1"}},
{Action: update.Keep, Entry: osutil.MountEntry{Dir: "/same-2"}},
{Action: update.Keep, Entry: osutil.MountEntry{Dir: "/same-1"}},
{Action: update.Mount, Entry: osutil.MountEntry{Dir: "/new-1"}},
{Action: update.Mount, Entry: osutil.MountEntry{Dir: "/new-2"}},
}
profile = update.CurrentProfileFromChangesMade(changes)
c.Check(profile, DeepEquals, osutil.MountProfile{Entries: []osutil.MountEntry{
{Dir: "/same-1"},
{Dir: "/same-2"},
{Dir: "/new-1"},
{Dir: "/new-2"},
}})
}

// testProfileUpdateContext implements MountProfileUpdateContext and is suitable for testing.
type testProfileUpdateContext struct {
loadCurrentProfile func() (*osutil.MountProfile, error)
Expand Down

0 comments on commit 4404ec1

Please sign in to comment.