The preceding commit advertises the default platform with the erofs OS feature. Move construction of that platform set into snapshotterPlatforms so the client-side matching contract can be tested without changing the advertisement.
EROFS identifies the image layer package format rather than a Linux-only host capability, so the feature-bearing entry remains derived from platforms.DefaultSpec. Test that the advertised set matches both the plain default platform and the same platform carrying the erofs feature.
Assisted-by: Claude Opus 5
Signed-off-by: Martín Fernández <mfernandez@crunchloop.io>
To make task.Delete retriable, this patch caches the delete result in
memory after the shim successfully deletes the task. If a later shutdown
attempt fails, a subsequent Delete retry can complete cleanup and return the
cached exit information.
If containerd restarts after deleting the task, the in-memory cache is lost,
and containerd will publish TaskExit and TaskDelete events again to
subscribers. Currently, the exit status returned by shim-delete is always
137. In a follow-up, containerd-shim-runc-v2 should store the actual exit
status in the state directory, so that shim-delete can reuse it instead of
returning a hard-coded value.
Implements: #8981
Signed-off-by: Wei Fu <fuweid89@gmail.com>
Neither doc previously said how much of a claimed transform chain is
actually honored; a reader could assume claiming any transform in a
chain was sufficient on its own. State the suffix rule plainly, with
the format/mkdir/overlay example the code itself now enforces, and
call out that format in particular can only ever be claimed as part
of a suffix that covers what follows it, never alone, since it
resolves mount points internal to the mount manager.
Signed-off-by: Derek McGowan <derek@mcg.dev>
Add a registry entry for the containerd.types.MountCapabilities extension,
and update the mount and bootstrap protocol docs for extensions replacing
the reserved-for-future-use capabilities field, and for the removal of the
runtime-allow-mounts annotation and the "/*" transform convention.
Signed-off-by: Derek McGowan <derek@mcg.dev>
Kata's EROFS snapshotter shim set containerd.io/runtime-allow-mounts
before the MountCapabilities bootstrap extension existed
(https://github.com/kata-containers/kata-containers/pull/12763), so
removing the annotation outright would break it and anyone else who
adopted it early with no migration window.
Rather than keep the annotation as a first-class, permanently
supported mechanism, confine falling back to it in
task_mounts_deprecated.go: when a shim's bootstrap result carries no
MountCapabilities extension, its runtime name is checked against the
annotation as a migration path, with the result cached per runtime
name for the life of the daemon, same as the removed mechanism did.
Two runtimes known to never set it, runc.v2 and runhcs.v1, are
skipped outright rather than queried.
The extension stays authoritative whenever a shim provides it: this
fallback only runs in its absence, and is confined to one file so it
can be deleted outright once known early adopters have migrated.
Signed-off-by: Derek McGowan <derek@mcg.dev>
When a container joins an existing sandbox via a Task API address supplied
directly by the sandbox controller (rather than by restoring
bootstrap.json), ShimManager.Start synthesized a BootstrapResult carrying
only the version, protocol and address. A shim that advertised
MountCapabilities at sandbox startup was therefore treated as if it had
advertised nothing for every container that joins the sandbox this way,
silently ignoring mount handling it explicitly claimed.
Recover the extensions from the sandbox's shim instance, which containerd
already holds in memory, via the existing shimCapabilities interface. This
is best effort: an external sandboxer whose shim instance containerd does
not track degrades to no extensions rather than failing sandbox startup,
matching today's behavior.
Reported independently by fuweid and Copilot on containerd/containerd#14002.
Signed-off-by: Derek McGowan <derek@mcg.dev>
A shim declared the mount types it performs itself through the annotation
removed in an earlier commit, discovered by invoking the shim binary a
second time with -info. Read them instead from the MountCapabilities
extension a shim advertises in its bootstrap result, which is already
available from the shim start that Create() performs anyway.
This requires starting the shim before activating the task's mounts.
Starting a shim does not need the rootfs; only the task.Create call
consumes it. Reordering means a failure after the shim has started must
now tear the shim down, so the teardown that was inlined in the
task.Create error path becomes a deferred cleanup covering the whole
window, reusing the existing cleanupShimTask helper. That defer is
registered after the mount deactivation defer so that the shim, which
may still be using the mounts, is stopped first.
Extract the mount activation logic into a new taskMountController in
task_mounts.go, rather than growing it further inline in Create(): it
already has its own state transitions (owned vs. reused activation,
NotImplemented, AlreadyExists) independent of shim startup, and this
keeps that reasoning testable without spawning a shim.
Also fix two latent nil pointer dereferences: Create() and Delete() both
called the mount.Manager interface directly with no nil check, which
panics whenever the mount manager plugin is not registered.
taskMountController.Activate and Deactivate treat a nil manager as
nothing to do.
Signed-off-by: Derek McGowan <derek@mcg.dev>
A claimed transform was recorded but never actually left unapplied:
every parsed transformer in a mount's chain was applied in full
regardless of what the caller had claimed, so a shim advertising it
performs "mkdir" in "format/mkdir/overlay" never got the chance to,
since the manager silently applied it anyway. This predates the shim
capability protocol — it was reachable before through the "format/*"
annotation convention — but this series turns it into a documented,
supported way for a shim to claim a transform, so a shim relying on it
(at least one is: Kata's EROFS snapshotter shim, per its annotation
usage) would find its claim silently ignored.
A claimed transform can only be honored as a suffix of the chain: each
transform's input is the previous one's output, so an outer, unclaimed
transform must still be applied even when an inner one is claimed,
since the inner one cannot run without it. planActivation now tracks,
per mount, how much of its chain — starting from the beginning — the
manager must apply itself: through the last unclaimed transform, which
by construction covers every transform before it too. Applying only
that prefix and returning the true, contiguous claimed suffix to the
caller is what actually makes the claim meaningful. This is only
observable for mounts[firstSystemMount], the one mount partially
transformed by the manager and returned to the caller to finish; every
earlier mount is fully internal to the manager and was, and remains,
always fully transformed regardless of any claim.
While changing this expression, also guard it against the case where
firstSystemMount reaches len(mounts) — every mount consumed inside the
manager, with no system mount left to transform — which indexes out of
range today. This is a distinct, pre-existing latent panic (for
example, reachable via WithTemporary combined with a transformed mount
type), tracked separately from the claim-handling fix above; guarding
it here only prevents a crash newly reachable by touching this line,
it does not address the mount.ActivationInfo.System non-empty
invariant that scenario also violates.
Signed-off-by: Derek McGowan <derek@mcg.dev>
Activate's planning phase — deciding, for each mount, which transforms
the manager must apply and whether the manager or the caller performs
the mount itself — was inline in a bolt transaction spanning hundreds
of lines, and every existing test of it goes through the full Activate
path, which needs root to mount anything for real.
Extract it into planActivation, a pure function of the mount list,
activation options, and registered transforms/handlers. No behavior
change; this is what makes the next commit's fix testable without
root.
Signed-off-by: Derek McGowan <derek@mcg.dev>
A caller that applies a mount transform itself had to say so by naming the
mount type "format/*", a sentinel the mount manager constructs internally
by concatenating a transform name with "/*". Both sides had to
independently know and agree on that convention, and the resulting string
is neither a mount type nor a transform name.
Add AllowTransforms, and WithAllowTransform to set it, so a transform can
be claimed by its own name instead. The "/*" convention is removed rather
than kept as a second accepted spelling: it existed only to be produced by
the runtime-allow-mounts annotation, which is removed in an earlier commit
in this series, and there is no other producer of it in this tree.
Signed-off-by: Derek McGowan <derek@mcg.dev>
parseStartResponse decodes a JSON bootstrap response into the deprecated
three-field client.BootstrapParams, so every other field of BootstrapResult
is silently discarded.
This is reached when reloading a bundle: writeBootstrapParams stores
bootstrap.json with encoding/json, and readBootstrapParams parses it back
through here. It matters once BootstrapResult carries extensions, because a
container joining an existing sandbox shim recovers that shim's result from
bootstrap.json rather than from a fresh shim start, and so would have seen
none of them.
Decode into BootstrapResult instead. The stored format does not change and
neither reader nor writer changes what it produces; encoding/json already
round-trips every field, including extensions, whose Any is an opaque type
URL and byte slice to it and so needs no type resolution, and including a
capability value this version of containerd does not define, which must
survive rather than being silently dropped.
This also removes the last use of the deprecated client.BootstrapParams.
Also fix TestRestoreBootstrapParams, which compared protobuf messages with
reflect-based deep equality. That is not sound, as generated types carry
internal state that varies with how the message was built.
Signed-off-by: Derek McGowan <derek@mcg.dev>
Pull in the mount capabilities extension.
The api module is consumed as a published version, so a local replace
is required to build against the unreleased proto changes. The replace
is added by 'make protos' whenever api/next.txtpb changes. It must be
dropped and go.mod pinned to a released api version before this is
merged.
This also moves the root module's own github.com/sirupsen/logrus
requirement from v1.10.1 to v1.10.2, which is not an intended dependency
bump. The published api module (v1.12.0-beta.0) requires logrus v1.9.3,
so it does not affect the root's resolution; the local api/go.mod on
upstream main already requires v1.10.2, and once the replace substitutes
it in, MVS takes the higher of the two. Verified by running 'go mod tidy'
on a copy of this tree with the replace directive removed: the root
stays at v1.10.1. This reverts on its own once the replace above is
dropped.
Signed-off-by: Derek McGowan <derek@mcg.dev>
A shim that performs some mount types or transformations itself, so that
containerd's mount manager does not perform them on its behalf, had no
way to say so other than a comma separated string in the generic
annotations map of its RuntimeInfo.
Add a containerd.types.MountCapabilities extension a shim can attach to
its BootstrapResult, naming the mount types and transforms it handles.
Detail lives in an extension rather than fields of BootstrapResult so
that containerd can ignore an extension whose type it does not
recognize, letting a shim advertise unconditionally.
Presence of the extension is enough: it is not gated behind a
Capability enum value, since with no other consumer of that field an
enum value here would only ever duplicate what the extension's
presence already says, while still permitting states with no single
correct interpretation, such as the enum value being set with no
extension attached, or the reverse.
This is additive: only a new field is added to BootstrapResult, and
buf breaking is clean.
Signed-off-by: Derek McGowan <derek@mcg.dev>
A shim declared the mount types it performs itself through a comma
separated string in the generic annotations map of its RuntimeInfo,
discovered by invoking the shim binary a second time with -info. The
values had to reproduce by hand the "<transform>/*" sentinel the mount
manager constructs internally, there was nowhere to put anything but a
name, and it was keyed by runtime name rather than shim instance, so it
could not reflect anything about the environment a particular shim is
running in.
Remove it along with loadShimInfo, shimInfo and the shimInfos cache,
and the runc.v2/runhcs.v1 shortcut that only existed to avoid paying
for it on the default runtimes. This is a breaking change targeted at
2.4; known usage is limited to Nerdbox, which can adopt the shim
capability protocol added in the following commits after this merges.
getRuntimeInfo itself stays: it is also used by PluginInfo and
validateRuntimeFeatures.
Signed-off-by: Derek McGowan <derek@mcg.dev>
- Add support for creating timers with custom histogram buckets.
- Update `github.com/prometheus/client_golang` to v1.20.5.
- Update the minimum supported Go version to Go 1.21.
- Improve HTTP handler instrumentation, including minor performance improvements and cleanup.
- Avoid mutating shared label maps when creating namespaces and metrics.
- Encapsulate the Prometheus collector used by `HTTPMetric`.
- Improve package and API documentation.
- Update `golang.org/x/sys` and other dependencies.
full diff: https://github.com/docker/go-metrics/compare/v0.0.1...v0.1.0
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Send a known trace context with the API call and assert that the
environment of the OCI hook runc executes carries it.
The shim propagates the context only when built with the shim_tracing
tag, so build the Linux integration job with it. The integration target
also has to pass the project build tags to the test compile, like the
other build targets already do.
Signed-off-by: Maksym Pavlenko <pavlenko.maksym@gmail.com>
runc and the OCI hooks it spawns are separate processes, so the trace
context can not reach them over ttrpc. Inject it into their environment
instead, riding on the request context via go-runc's WithExtraEnv, which
does not race with concurrent requests the way setting it on the shim
process would.
The otelttrpc interceptor extracts that context, so chain it first
explicitly instead of leaving it to plugin initialization order. Also
flush the spans the tracing plugin buffered before the shim exits.
Signed-off-by: Maksym Pavlenko <pavlenko.maksym@gmail.com>
The carrier implements the OpenTelemetry "Environment Variables as
Context Propagation Carriers" specification, which is how the shim hands
the trace context to the processes it spawns.
Signed-off-by: Maksym Pavlenko <pavlenko.maksym@gmail.com>
Go 1.27 has been released and we can re-enable matrix
building with min and max Go versions as well as move
most of CI jobs to use the latest Go 1.27. Leave install-go
action at 1.26.6.
Signed-off-by: Phil Estes <estesp@amazon.com>