-
Notifications
You must be signed in to change notification settings - Fork 608
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
Volume QA part II: fixes and tests #3133
Conversation
bc9bcff
to
a197d56
Compare
@AkihiroSuda what's the timeline for v2? Do I still have time for more or are we frozen for v2 already? I would have liked to cleanup / fix all bugs for |
Planned to be synced with containerd v2 |
Cool. So I guess we also need this in then: containerd/stargz-snapshotter#1545 And #2902 to pass. Lmk if there is something I can do to help with ^. |
nerdctl v2 will have containerd v2 binaries in the
Thanks, I'd appreciate if you can help #2902 and its dependencies (stargz, soci, etc.) 🙇 |
a42487c
to
7d995eb
Compare
@@ -45,6 +48,12 @@ func processVolumeCreateOptions(cmd *cobra.Command) (types.VolumeCreateOptions, | |||
if err != nil { | |||
return types.VolumeCreateOptions{}, err | |||
} | |||
for _, label := range labels { |
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.
Align with docker behavior. Empty labels are not allowed.
if err != nil { | ||
log.L.Warn(err) | ||
} else { | ||
volEnts, err := os.ReadDir(volStore) | ||
volEnts, err := volStore.List(false) |
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.
Replace direct access to underlying filesystem implementation by a proper api call.
@@ -151,7 +164,7 @@ func Create(ctx context.Context, client *containerd.Client, args []string, netMa | |||
} | |||
|
|||
var mountOpts []oci.SpecOpts | |||
mountOpts, internalLabels.anonVolumes, internalLabels.mountPoints, err = generateMountOpts(ctx, client, ensuredImage, options) | |||
mountOpts, internalLabels.anonVolumes, internalLabels.mountPoints, err = generateMountOpts(ctx, client, ensuredImage, volStore, options) |
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.
Since we are now locking the volume store, we need to pass it along.
@@ -32,9 +31,6 @@ func Create(name string, options types.VolumeCreateOptions) (*native.Volume, err | |||
name = stringid.GenerateRandomID() | |||
options.Labels = append(options.Labels, labels.AnonymousVolumes+"=") | |||
} | |||
if err := identifiers.Validate(name); err != nil { | |||
return nil, fmt.Errorf("malformed name %s: %w", name, err) | |||
} |
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.
Useless, as this is performed by the volume store.
var vol, err = volStore.Get(name, options.Size) | ||
if err != nil { | ||
return err | ||
warns = append(warns, err) |
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.
Align with docker behavior
containers, err := client.Containers(ctx) | ||
if err != nil { | ||
return err | ||
} | ||
usedVolumes, err := usedVolumes(ctx, containers) | ||
|
||
usedVolumesList, err := usedVolumes(ctx, containers) |
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.
Better variable name...
continue | ||
} | ||
if !options.All { | ||
if volume.Labels == nil { |
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.
Now that labels can be nil, need to check for that.
for _, name := range volumes { | ||
if _, ok := usedVolumes[name]; ok { | ||
return fmt.Errorf("volume %q is in use", name) | ||
if _, ok := usedVolumesList[name]; ok { |
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.
Align with docker behavior
@@ -41,6 +41,9 @@ func (c *Composer) upVolume(ctx context.Context, shortName string) error { | |||
|
|||
// shortName is like "db_data", fullName is like "compose-wordpress_db_data" | |||
fullName := vol.Name | |||
// FIXME: this is racy. By the time we get below to creating the volume, there is no guarantee that things are still fine | |||
// Furthermore, volStore.Get no longer errors if the volume already exists (docker behavior), so, the purpose of this | |||
// call needs to be assessed (it might still error if the name is malformed, or if there is a filesystem error) | |||
volExists, err := c.VolumeExists(fullName) |
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.
I do not understand the compose code. Why do we shell out?
Leaving these untouched for now.
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.
shell out
IIRC it was just for ease of quick implementation
log.L.WithError(err).Errorf("failed to unlock %q", dir) | ||
} | ||
}() | ||
return fn() | ||
} | ||
|
||
func Flock(f *os.File, flags int) error { | ||
func flock(f *os.File, flags int) error { |
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.
This should not be public. It is unix only.
vol, err := volStore.Get(res.Name, false) | ||
|
||
// Create returns an existing volume or creates a new one if necessary. | ||
vol, err := volStore.Create(res.Name, nil) |
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.
No reason for any of that anymore.
@@ -106,16 +106,26 @@ func (m *MockVolumeStoreMockRecorder) Remove(names any) *gomock.Call { | |||
return m.mock.ctrl.RecordCallWithMethodType(m.mock, "Remove", reflect.TypeOf((*MockVolumeStore)(nil).Remove), names) | |||
} | |||
|
|||
// Dir mocks the Dir method of VolumeStore | |||
func (m *MockVolumeStore) Dir() string { | |||
// Lock mocks the Lock method of VolumeStore |
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.
The mock stuff. Still have no idea what is this and what to do here.
Merely ensuring we fullfill the interface here, but if you have info on what I should do here, please speak.
@@ -31,21 +31,33 @@ import ( | |||
"github.com/containerd/nerdctl/v2/pkg/strutil" | |||
) | |||
|
|||
// Path returns a string like `/var/lib/nerdctl/1935db59/volumes/default`. | |||
func Path(dataStore, ns string) (string, error) { |
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.
This should not be public.
Consumer should only use the interface methods and not fiddle with the underlying (filesystem based) implementation.
} | ||
|
||
func (vs *volumeStore) Dir() string { |
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.
See other comment on publicizing these.
@@ -32,6 +32,11 @@ import ( | |||
|
|||
func TestSystemPrune(t *testing.T) { | |||
testutil.RequiresBuild(t) | |||
// FIXME: for some reason, using a dedicated namespace does work well with rootless, but fails with rootful... :/ |
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.
No idea what's going on here, and why this happens only with rootful.
Will investigate later when I get to system tests...
t.Parallel() | ||
} | ||
|
||
// FIXME: for an unknown reason, when testing ipv6, calling NewBaseWithNamespace per sub-test, in the tearDown/tearUp methods |
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.
No idea.........
I guess it is another thing to add to the list for whomever is going to cleanup our testing helpers eventually.
a78e999
to
0aca67e
Compare
@AkihiroSuda this is finally ready - sorry it took so long to get there. Also it is bigger that I wanted it to be - sorry about that as well. I guess problems just kept on piling up as I parallelized more... Pure code changes are relatively small and targeted. The rest is merely small bug fixes - and a boatload of new tests. I have added a bunch of github comments alongside the code to facilitate review. PTAL at your convenience. Thanks! |
Signed-off-by: apostasie <[email protected]>
Rebased. @AkihiroSuda last tiny push does remove the spurious commented leftovers, extra line, and updated the comment on rootful/buidkit. Just did another proofread of the diff - we should be good to go (let's make sure the CI is happy of course). |
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.
Thanks
Thanks a lot @AkihiroSuda |
This is part 2 of #3125 - same idea.
The original motivation was to significantly increase testing coverage & quality, convergence with docker behavior, and stability wrt concurrency for anything related to volume lifecycle.
In the process of doing so, several issues cropped-up, that this PR also fix.
Tests:
move tests from _linux to all platforms (not sure why it was linux only in the first place)- wish I had a windows env to testCode changes:
nil
, not[]string{}
--label ""
should errorget
thencreate
" by justcreate
(since behavior has been recently changed and now always returns success)Path
) to prevent leaking implementation to the consumer (see for examplecmd/nerdctl/namespace.go b/cmd/nerdctl/namespace.go
that was reading the filesystem directly instead of callingList
)Lock
andUnlock
methods on the store, for operations that need to call multiple methods successively or need guarantees that volumes cannot be modified at all until they are donelockutil
, so that we don't expose anymoreFlock
(unimplemented for non Unix), and instead expose new lock/unlock methodsusedVolumes
(called in volume remove and prune) can be raced by container creation, and other sources of racyness in volumes #3132 (and fix Volume code may be racy #3123 hopefully)While this is a significant PR in term of apparent code change size, the added testing should give us a good confidence boost on what's happening wrt volumes.