228 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			228 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
|    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 podsandbox
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 	"path"
 | |
| 	"path/filepath"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/containerd/containerd"
 | |
| 	"github.com/containerd/containerd/containers"
 | |
| 	clabels "github.com/containerd/containerd/labels"
 | |
| 	"github.com/containerd/containerd/log"
 | |
| 	"github.com/containerd/containerd/oci"
 | |
| 	criconfig "github.com/containerd/containerd/pkg/cri/config"
 | |
| 	imagestore "github.com/containerd/containerd/pkg/cri/store/image"
 | |
| 	ctrdutil "github.com/containerd/containerd/pkg/cri/util"
 | |
| 	"github.com/containerd/containerd/reference/docker"
 | |
| 	runtimespec "github.com/opencontainers/runtime-spec/specs-go"
 | |
| 	"github.com/sirupsen/logrus"
 | |
| 
 | |
| 	imagedigest "github.com/opencontainers/go-digest"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 
 | |
| 	// sandboxesDir contains all sandbox root. A sandbox root is the running
 | |
| 	// directory of the sandbox, all files created for the sandbox will be
 | |
| 	// placed under this directory.
 | |
| 	sandboxesDir = "sandboxes"
 | |
| 	// criContainerdPrefix is common prefix for cri-containerd
 | |
| 	criContainerdPrefix = "io.cri-containerd"
 | |
| 	// containerKindLabel is a label key indicating container is sandbox container or application container
 | |
| 	containerKindLabel = criContainerdPrefix + ".kind"
 | |
| 	// containerKindSandbox is a label value indicating container is sandbox container
 | |
| 	containerKindSandbox = "sandbox"
 | |
| 	// sandboxMetadataExtension is an extension name that identify metadata of sandbox in CreateContainerRequest
 | |
| 	sandboxMetadataExtension = criContainerdPrefix + ".sandbox.metadata"
 | |
| 	// MetadataKey is the key used for storing metadata in the sandbox extensions
 | |
| 	MetadataKey = "metadata"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	// unknownExitCode is the exit code when exit reason is unknown.
 | |
| 	unknownExitCode = 255
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	handleEventTimeout = 10 * time.Second
 | |
| )
 | |
| 
 | |
| // getSandboxRootDir returns the root directory for managing sandbox files,
 | |
| // e.g. hosts files.
 | |
| func (c *Controller) getSandboxRootDir(id string) string {
 | |
| 	return filepath.Join(c.config.RootDir, sandboxesDir, id)
 | |
| }
 | |
| 
 | |
| // getVolatileSandboxRootDir returns the root directory for managing volatile sandbox files,
 | |
| // e.g. named pipes.
 | |
| func (c *Controller) getVolatileSandboxRootDir(id string) string {
 | |
| 	return filepath.Join(c.config.StateDir, sandboxesDir, id)
 | |
| }
 | |
| 
 | |
| // getRepoDigestAngTag returns image repoDigest and repoTag of the named image reference.
 | |
| func getRepoDigestAndTag(namedRef docker.Named, digest imagedigest.Digest, schema1 bool) (string, string) {
 | |
| 	var repoTag, repoDigest string
 | |
| 	if _, ok := namedRef.(docker.NamedTagged); ok {
 | |
| 		repoTag = namedRef.String()
 | |
| 	}
 | |
| 	if _, ok := namedRef.(docker.Canonical); ok {
 | |
| 		repoDigest = namedRef.String()
 | |
| 	} else if !schema1 {
 | |
| 		// digest is not actual repo digest for schema1 image.
 | |
| 		repoDigest = namedRef.Name() + "@" + digest.String()
 | |
| 	}
 | |
| 	return repoDigest, repoTag
 | |
| }
 | |
| 
 | |
| // toContainerdImage converts an image object in image store to containerd image handler.
 | |
| func (c *Controller) toContainerdImage(ctx context.Context, image imagestore.Image) (containerd.Image, error) {
 | |
| 	// image should always have at least one reference.
 | |
| 	if len(image.References) == 0 {
 | |
| 		return nil, fmt.Errorf("invalid image with no reference %q", image.ID)
 | |
| 	}
 | |
| 	return c.client.GetImage(ctx, image.References[0])
 | |
| }
 | |
| 
 | |
| // getUserFromImage gets uid or user name of the image user.
 | |
| // If user is numeric, it will be treated as uid; or else, it is treated as user name.
 | |
| func getUserFromImage(user string) (*int64, string) {
 | |
| 	// return both empty if user is not specified in the image.
 | |
| 	if user == "" {
 | |
| 		return nil, ""
 | |
| 	}
 | |
| 	// split instances where the id may contain user:group
 | |
| 	user = strings.Split(user, ":")[0]
 | |
| 	// user could be either uid or user name. Try to interpret as numeric uid.
 | |
| 	uid, err := strconv.ParseInt(user, 10, 64)
 | |
| 	if err != nil {
 | |
| 		// If user is non numeric, assume it's user name.
 | |
| 		return nil, user
 | |
| 	}
 | |
| 	// If user is a numeric uid.
 | |
| 	return &uid, ""
 | |
| }
 | |
| 
 | |
| // buildLabel builds the labels from config to be passed to containerd
 | |
| func buildLabels(configLabels, imageConfigLabels map[string]string, containerType string) map[string]string {
 | |
| 	labels := make(map[string]string)
 | |
| 
 | |
| 	for k, v := range imageConfigLabels {
 | |
| 		if err := clabels.Validate(k, v); err == nil {
 | |
| 			labels[k] = v
 | |
| 		} else {
 | |
| 			// In case the image label is invalid, we output a warning and skip adding it to the
 | |
| 			// container.
 | |
| 			logrus.WithError(err).Warnf("unable to add image label with key %s to the container", k)
 | |
| 		}
 | |
| 	}
 | |
| 	// labels from the CRI request (config) will override labels in the image config
 | |
| 	for k, v := range configLabels {
 | |
| 		labels[k] = v
 | |
| 	}
 | |
| 	labels[containerKindLabel] = containerType
 | |
| 	return labels
 | |
| }
 | |
| 
 | |
| // parseImageReferences parses a list of arbitrary image references and returns
 | |
| // the repotags and repodigests
 | |
| func parseImageReferences(refs []string) ([]string, []string) {
 | |
| 	var tags, digests []string
 | |
| 	for _, ref := range refs {
 | |
| 		parsed, err := docker.ParseAnyReference(ref)
 | |
| 		if err != nil {
 | |
| 			continue
 | |
| 		}
 | |
| 		if _, ok := parsed.(docker.Canonical); ok {
 | |
| 			digests = append(digests, parsed.String())
 | |
| 		} else if _, ok := parsed.(docker.Tagged); ok {
 | |
| 			tags = append(tags, parsed.String())
 | |
| 		}
 | |
| 	}
 | |
| 	return tags, digests
 | |
| }
 | |
| 
 | |
| // getPassthroughAnnotations filters requested pod annotations by comparing
 | |
| // against permitted annotations for the given runtime.
 | |
| func getPassthroughAnnotations(podAnnotations map[string]string,
 | |
| 	runtimePodAnnotations []string) (passthroughAnnotations map[string]string) {
 | |
| 	passthroughAnnotations = make(map[string]string)
 | |
| 
 | |
| 	for podAnnotationKey, podAnnotationValue := range podAnnotations {
 | |
| 		for _, pattern := range runtimePodAnnotations {
 | |
| 			// Use path.Match instead of filepath.Match here.
 | |
| 			// filepath.Match treated `\\` as path separator
 | |
| 			// on windows, which is not what we want.
 | |
| 			if ok, _ := path.Match(pattern, podAnnotationKey); ok {
 | |
| 				passthroughAnnotations[podAnnotationKey] = podAnnotationValue
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return passthroughAnnotations
 | |
| }
 | |
| 
 | |
| // runtimeSpec returns a default runtime spec used in cri-containerd.
 | |
| func (c *Controller) runtimeSpec(id string, baseSpecFile string, opts ...oci.SpecOpts) (*runtimespec.Spec, error) {
 | |
| 	// GenerateSpec needs namespace.
 | |
| 	ctx := ctrdutil.NamespacedContext()
 | |
| 	container := &containers.Container{ID: id}
 | |
| 
 | |
| 	if baseSpecFile != "" {
 | |
| 		baseSpec, ok := c.baseOCISpecs[baseSpecFile]
 | |
| 		if !ok {
 | |
| 			return nil, fmt.Errorf("can't find base OCI spec %q", baseSpecFile)
 | |
| 		}
 | |
| 
 | |
| 		spec := oci.Spec{}
 | |
| 		if err := ctrdutil.DeepCopy(&spec, &baseSpec); err != nil {
 | |
| 			return nil, fmt.Errorf("failed to clone OCI spec: %w", err)
 | |
| 		}
 | |
| 
 | |
| 		// Fix up cgroups path
 | |
| 		applyOpts := append([]oci.SpecOpts{oci.WithNamespacedCgroup()}, opts...)
 | |
| 
 | |
| 		if err := oci.ApplyOpts(ctx, nil, container, &spec, applyOpts...); err != nil {
 | |
| 			return nil, fmt.Errorf("failed to apply OCI options: %w", err)
 | |
| 		}
 | |
| 
 | |
| 		return &spec, nil
 | |
| 	}
 | |
| 
 | |
| 	spec, err := oci.GenerateSpec(ctx, nil, container, opts...)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("failed to generate spec: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	return spec, nil
 | |
| }
 | |
| 
 | |
| // Overrides the default snapshotter if Snapshotter is set for this runtime.
 | |
| // See https://github.com/containerd/containerd/issues/6657
 | |
| func (c *Controller) runtimeSnapshotter(ctx context.Context, ociRuntime criconfig.Runtime) string {
 | |
| 	if ociRuntime.Snapshotter == "" {
 | |
| 		return c.config.ContainerdConfig.Snapshotter
 | |
| 	}
 | |
| 
 | |
| 	log.G(ctx).Debugf("Set snapshotter for runtime %s to %s", ociRuntime.Type, ociRuntime.Snapshotter)
 | |
| 	return ociRuntime.Snapshotter
 | |
| }
 | 
