Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions client/container_opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"encoding/json"
"errors"
"fmt"
"strings"

"github.com/containerd/containerd/v2/core/containers"
"github.com/containerd/containerd/v2/core/content"
Expand Down Expand Up @@ -52,6 +53,11 @@ type InfoConfig struct {
Refresh bool
}

const (
devboxAnnotationPrefix = "devbox.sealos.io/"
devboxSnapshotLabelPrefix = "containerd.io/snapshot/devbox-"
)

// WithRuntime allows a user to specify the runtime name and additional options that should
// be used to create tasks for the container
func WithRuntime(name string, options interface{}) NewContainerOpts {
Expand Down Expand Up @@ -255,10 +261,15 @@ func withNewSnapshot(id string, i Image, readonly bool, opts ...snapshots.Opt) N
return err
}

startOpts, err := withDevboxSnapshotLabels(opts...)
if err != nil {
return err
}

if readonly {
_, err = s.View(ctx, id, parent, opts...)
_, err = s.View(ctx, id, parent, startOpts...)
} else {
_, err = s.Prepare(ctx, id, parent, opts...)
_, err = s.Prepare(ctx, id, parent, startOpts...)
}
if err != nil {
return err
Expand All @@ -269,6 +280,30 @@ func withNewSnapshot(id string, i Image, readonly bool, opts ...snapshots.Opt) N
}
}

func withDevboxSnapshotLabels(opts ...snapshots.Opt) ([]snapshots.Opt, error) {
base := snapshots.Info{}
for _, opt := range opts {
if err := opt(&base); err != nil {
return nil, fmt.Errorf("error applying snapshot option: %w", err)
}
}

translated := make(map[string]string)
for label, value := range base.Labels {
if strings.HasPrefix(label, devboxAnnotationPrefix) {
translated[devboxSnapshotLabelPrefix+label[len(devboxAnnotationPrefix):]] = value
}
}
if len(translated) == 0 {
return opts, nil
}

startOpts := make([]snapshots.Opt, 0, len(opts)+1)
startOpts = append(startOpts, snapshots.WithLabels(translated))
startOpts = append(startOpts, opts...)
return startOpts, nil
}

// WithContainerExtension appends extension data to the container object.
// Use this to decorate the container object with additional data for the client
// integration.
Expand Down
52 changes: 52 additions & 0 deletions internal/cri/devboxsnapshotter/labels.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
Copyright The containerd Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package devboxsnapshotter

const (
DevboxSnapshotter = "devbox"
StargzSnapshotter = "stargz"
SealosDevboxContentIDAnnotation = "devbox.sealos.io/content-id"
SealosDevboxStorageLimitAnnotation = "devbox.sealos.io/storage-limit"
)

func LabelsFromAnnotations(annotations map[string]string) map[string]string {
if len(annotations) == 0 {
return nil
}

labels := make(map[string]string)
if contentID := annotations[SealosDevboxContentIDAnnotation]; contentID != "" {
labels[SealosDevboxContentIDAnnotation] = contentID
}
if storageLimit := annotations[SealosDevboxStorageLimitAnnotation]; storageLimit != "" {
labels[SealosDevboxStorageLimitAnnotation] = storageLimit
}
if len(labels) == 0 {
return nil
}

return labels
}

func IsWritableSnapshotter(name string) bool {
switch name {
case DevboxSnapshotter, StargzSnapshotter:
return true
default:
return false
}
}
41 changes: 41 additions & 0 deletions internal/cri/devboxsnapshotter/labels_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package devboxsnapshotter

import "testing"

func TestLabelsFromAnnotations(t *testing.T) {
labels := LabelsFromAnnotations(map[string]string{
SealosDevboxContentIDAnnotation: "workspace-1",
SealosDevboxStorageLimitAnnotation: "20Gi",
"other.annotation": "ignored",
})

if got := labels[SealosDevboxContentIDAnnotation]; got != "workspace-1" {
t.Fatalf("content-id label = %q, want %q", got, "workspace-1")
}
if got := labels[SealosDevboxStorageLimitAnnotation]; got != "20Gi" {
t.Fatalf("storage-limit label = %q, want %q", got, "20Gi")
}
if _, ok := labels["other.annotation"]; ok {
t.Fatalf("unexpected non-devbox label preserved: %+v", labels)
}
}

func TestIsWritableSnapshotter(t *testing.T) {
tests := []struct {
name string
snapshotter string
want bool
}{
{name: "devbox", snapshotter: DevboxSnapshotter, want: true},
{name: "stargz", snapshotter: StargzSnapshotter, want: true},
{name: "overlayfs", snapshotter: "overlayfs", want: false},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := IsWritableSnapshotter(tt.snapshotter); got != tt.want {
t.Fatalf("IsWritableSnapshotter(%q) = %v, want %v", tt.snapshotter, got, tt.want)
}
})
}
}
20 changes: 12 additions & 8 deletions internal/cri/server/container_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import (
"github.com/containerd/containerd/v2/core/snapshots"
"github.com/containerd/containerd/v2/internal/cri/annotations"
criconfig "github.com/containerd/containerd/v2/internal/cri/config"
"github.com/containerd/containerd/v2/internal/cri/devboxsnapshotter"
cio "github.com/containerd/containerd/v2/internal/cri/io"
crilabels "github.com/containerd/containerd/v2/internal/cri/labels"
customopts "github.com/containerd/containerd/v2/internal/cri/opts"
Expand All @@ -58,12 +59,15 @@ func init() {
}

func devboxSnapshotterOpts(config *runtime.PodSandboxConfig) (snapshots.Opt, error) {
labels := make(map[string]string)
if config != nil {
for k, v := range config.Annotations {
labels[k] = v
}
if config == nil {
return nil, nil
}

labels := devboxsnapshotter.LabelsFromAnnotations(config.Annotations)
if len(labels) == 0 {
return nil, nil
}

return snapshots.WithLabels(labels), nil
}

Expand Down Expand Up @@ -360,8 +364,8 @@ func (c *criService) createContainer(r *createContainerRequest) (_ string, retEr
return "", err
}

// Check if the snapshotter is devbox and add the devbox snapshotter opts.
if c.RuntimeSnapshotter(r.ctx, ociRuntime) == "devbox" {
runtimeSnapshotter := c.RuntimeSnapshotter(r.ctx, ociRuntime)
if devboxsnapshotter.IsWritableSnapshotter(runtimeSnapshotter) {
devboxOpt, err := devboxSnapshotterOpts(r.podSandboxConfig)
if err != nil {
return "", err
Expand All @@ -373,7 +377,7 @@ func (c *criService) createContainer(r *createContainerRequest) (_ string, retEr

// Set snapshotter before any other options.
opts := []containerd.NewContainerOpts{
containerd.WithSnapshotter(c.RuntimeSnapshotter(r.ctx, ociRuntime)),
containerd.WithSnapshotter(runtimeSnapshotter),
// Prepare container rootfs. This is always writeable even if
// the container wants a readonly rootfs since we want to give
// the runtime (runc) a chance to modify (e.g. to create mount
Expand Down
4 changes: 2 additions & 2 deletions internal/cri/server/container_stop.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"time"

eventtypes "github.com/containerd/containerd/api/events"
"github.com/containerd/containerd/v2/internal/cri/devboxsnapshotter"
containerstore "github.com/containerd/containerd/v2/internal/cri/store/container"
ctrdutil "github.com/containerd/containerd/v2/internal/cri/util"
"github.com/containerd/containerd/v2/pkg/protobuf"
Expand Down Expand Up @@ -85,8 +86,7 @@ func (c *criService) StopContainer(ctx context.Context, r *runtime.StopContainer

log.G(ctx).Infof("Check snapshotter: %s", snapshotter)

// Check if the snapshotter is devbox and update the devbox snapshot.
if snapshotter == "devbox" {
if devboxsnapshotter.IsWritableSnapshotter(snapshotter) {
err = c.client.UpdateDevboxSnapshot(ctx, snapshotter, i.ID, unmountLvm, "true")
if err != nil {
log.G(ctx).WithError(err).Errorf("Failed to update devbox snapshot: %s", err)
Expand Down
40 changes: 40 additions & 0 deletions internal/cri/server/devbox_snapshotter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package server

import (
"testing"

"github.com/containerd/containerd/v2/core/snapshots"
"github.com/containerd/containerd/v2/internal/cri/devboxsnapshotter"
runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
)

func TestDevboxSnapshotterOpts(t *testing.T) {
opt, err := devboxSnapshotterOpts(&runtime.PodSandboxConfig{
Annotations: map[string]string{
devboxsnapshotter.SealosDevboxContentIDAnnotation: "workspace-9",
devboxsnapshotter.SealosDevboxStorageLimitAnnotation: "8Gi",
"other.annotation": "ignored",
},
})
if err != nil {
t.Fatalf("devboxSnapshotterOpts() error = %v", err)
}
if opt == nil {
t.Fatal("devboxSnapshotterOpts() returned nil opt")
}

info := &snapshots.Info{Labels: make(map[string]string)}
if err := opt(info); err != nil {
t.Fatalf("applying snapshot opt error = %v", err)
}

if got := info.Labels[devboxsnapshotter.SealosDevboxContentIDAnnotation]; got != "workspace-9" {
t.Fatalf("content-id label = %q, want %q", got, "workspace-9")
}
if got := info.Labels[devboxsnapshotter.SealosDevboxStorageLimitAnnotation]; got != "8Gi" {
t.Fatalf("storage-limit label = %q, want %q", got, "8Gi")
}
if _, ok := info.Labels["other.annotation"]; ok {
t.Fatalf("unexpected unrelated annotation preserved: %+v", info.Labels)
}
}
3 changes: 2 additions & 1 deletion internal/cri/server/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
apitasks "github.com/containerd/containerd/api/services/tasks/v1"

containerd "github.com/containerd/containerd/v2/client"
"github.com/containerd/containerd/v2/internal/cri/devboxsnapshotter"
containerstore "github.com/containerd/containerd/v2/internal/cri/store/container"
sandboxstore "github.com/containerd/containerd/v2/internal/cri/store/sandbox"
ctrdutil "github.com/containerd/containerd/v2/internal/cri/util"
Expand Down Expand Up @@ -251,7 +252,7 @@ func (c *criService) handleContainerExit(ctx context.Context, e *eventtypes.Task
if err != nil {
return status, err
}
if container.Snapshotter == "devbox" {
if devboxsnapshotter.IsWritableSnapshotter(container.Snapshotter) {
if err := c.client.UpdateDevboxSnapshot(ctx, container.Snapshotter, container.ID, unmountLvm, "true"); err != nil {
log.G(ctx).WithError(err).Errorf("failed to update devbox snapshot for container %s", cntr.Container.ID())
}
Expand Down
3 changes: 2 additions & 1 deletion internal/cri/server/images/image_pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import (
"github.com/containerd/containerd/v2/core/transfer/registry"
"github.com/containerd/containerd/v2/internal/cri/annotations"
criconfig "github.com/containerd/containerd/v2/internal/cri/config"
"github.com/containerd/containerd/v2/internal/cri/devboxsnapshotter"
crilabels "github.com/containerd/containerd/v2/internal/cri/labels"
"github.com/containerd/containerd/v2/internal/cri/util"
snpkg "github.com/containerd/containerd/v2/pkg/snapshotters"
Expand Down Expand Up @@ -206,7 +207,7 @@ func (c *CRIImageService) PullImage(ctx context.Context, name string, credential
}

var imageLabels map[string]string
if r == repoTag && snapshotter == "devbox" {
if r == repoTag && devboxsnapshotter.IsWritableSnapshotter(snapshotter) {
imageLabels = make(map[string]string)
for k, v := range labels {
imageLabels[k] = v
Expand Down
Loading