Remove unused pkg/storage code

This code was refactored into libpod, so no need to keep the old
version around

Signed-off-by: Matthew Heon <matthew.heon@gmail.com>
This commit is contained in:
Matthew Heon 2018-01-11 18:44:05 -05:00
parent dd0d35deb0
commit 0e52d43962
4 changed files with 0 additions and 1133 deletions

View File

@ -1,5 +0,0 @@
// Package storage provides helper functions for creating and managing CRI pod
// sandboxes and containers and metadata associated with them in the format
// that crio understands. The API it provides should be considered to be
// unstable.
package storage

View File

@ -1,551 +0,0 @@
package storage
import (
"errors"
"fmt"
"net"
"path"
"regexp"
"strings"
"github.com/containers/image/copy"
"github.com/containers/image/docker/reference"
"github.com/containers/image/image"
"github.com/containers/image/signature"
istorage "github.com/containers/image/storage"
"github.com/containers/image/transports/alltransports"
"github.com/containers/image/types"
"github.com/containers/storage"
distreference "github.com/docker/distribution/reference"
)
// ImageResult wraps a subset of information about an image: its ID, its names,
// and the size, if known, or nil if it isn't.
type ImageResult struct {
ID string
Names []string
Digests []string
Size *uint64
ImageRef string
}
type indexInfo struct {
name string
secure bool
}
type imageService struct {
store storage.Store
defaultTransport string
insecureRegistryCIDRs []*net.IPNet
indexConfigs map[string]*indexInfo
registries []string
}
// ImageServer wraps up various CRI-related activities into a reusable
// implementation.
type ImageServer interface {
// ListImages returns list of all images which match the filter.
ListImages(systemContext *types.SystemContext, filter string) ([]ImageResult, error)
// ImageStatus returns status of an image which matches the filter.
ImageStatus(systemContext *types.SystemContext, filter string) (*ImageResult, error)
// PullImage imports an image from the specified location.
PullImage(systemContext *types.SystemContext, imageName string, options *copy.Options) (types.ImageReference, error)
// UntagImage removes a name from the specified image, and if it was
// the only name the image had, removes the image.
UntagImage(systemContext *types.SystemContext, imageName string) error
// RemoveImage deletes the specified image.
RemoveImage(systemContext *types.SystemContext, imageName string) error
// GetStore returns the reference to the storage library Store which
// the image server uses to hold images, and is the destination used
// when it's asked to pull an image.
GetStore() storage.Store
// CanPull preliminary checks whether we're allowed to pull an image
CanPull(imageName string, options *copy.Options) (bool, error)
// ResolveNames takes an image reference and if it's unqualified (w/o hostname),
// it uses crio's default registries to qualify it.
ResolveNames(imageName string) ([]string, error)
}
func (svc *imageService) getRef(name string) (types.ImageReference, error) {
ref, err := alltransports.ParseImageName(name)
if err != nil {
ref2, err2 := istorage.Transport.ParseStoreReference(svc.store, "@"+name)
if err2 != nil {
ref3, err3 := istorage.Transport.ParseStoreReference(svc.store, name)
if err3 != nil {
return nil, err
}
ref2 = ref3
}
ref = ref2
}
return ref, nil
}
func (svc *imageService) ListImages(systemContext *types.SystemContext, filter string) ([]ImageResult, error) {
results := []ImageResult{}
if filter != "" {
ref, err := svc.getRef(filter)
if err != nil {
return nil, err
}
if image, err := istorage.Transport.GetStoreImage(svc.store, ref); err == nil {
img, err := ref.NewImage(systemContext)
if err != nil {
return nil, err
}
size := imageSize(img)
img.Close()
results = append(results, ImageResult{
ID: image.ID,
Names: image.Names,
Size: size,
})
}
} else {
images, err := svc.store.Images()
if err != nil {
return nil, err
}
for _, image := range images {
ref, err := istorage.Transport.ParseStoreReference(svc.store, "@"+image.ID)
if err != nil {
return nil, err
}
img, err := ref.NewImage(systemContext)
if err != nil {
return nil, err
}
size := imageSize(img)
img.Close()
results = append(results, ImageResult{
ID: image.ID,
Names: image.Names,
Size: size,
})
}
}
return results, nil
}
func (svc *imageService) ImageStatus(systemContext *types.SystemContext, nameOrID string) (*ImageResult, error) {
ref, err := alltransports.ParseImageName(nameOrID)
if err != nil {
ref2, err2 := istorage.Transport.ParseStoreReference(svc.store, "@"+nameOrID)
if err2 != nil {
ref3, err3 := istorage.Transport.ParseStoreReference(svc.store, nameOrID)
if err3 != nil {
return nil, err
}
ref2 = ref3
}
ref = ref2
}
image, err := istorage.Transport.GetStoreImage(svc.store, ref)
if err != nil {
return nil, err
}
img, err := ref.NewImage(systemContext)
if err != nil {
return nil, err
}
size := imageSize(img)
img.Close()
result := ImageResult{
ID: image.ID,
Names: image.Names,
Size: size,
}
if len(image.Names) > 0 {
result.ImageRef = image.Names[0]
if ref2, err2 := istorage.Transport.ParseStoreReference(svc.store, image.Names[0]); err2 == nil {
if dref := ref2.DockerReference(); dref != nil {
result.ImageRef = reference.FamiliarString(dref)
}
}
}
return &result, nil
}
func imageSize(img types.Image) *uint64 {
if sum, err := img.Size(); err == nil {
usum := uint64(sum)
return &usum
}
return nil
}
func (svc *imageService) CanPull(imageName string, options *copy.Options) (bool, error) {
srcRef, err := svc.prepareImage(imageName, options)
if err != nil {
return false, err
}
rawSource, err := srcRef.NewImageSource(options.SourceCtx)
if err != nil {
return false, err
}
src, err := image.FromSource(options.SourceCtx, rawSource)
if err != nil {
rawSource.Close()
return false, err
}
src.Close()
return true, nil
}
// prepareImage creates an image reference from an image string and set options
// for the source context
func (svc *imageService) prepareImage(imageName string, options *copy.Options) (types.ImageReference, error) {
if imageName == "" {
return nil, storage.ErrNotAnImage
}
srcRef, err := alltransports.ParseImageName(imageName)
if err != nil {
if svc.defaultTransport == "" {
return nil, err
}
srcRef2, err2 := alltransports.ParseImageName(svc.defaultTransport + imageName)
if err2 != nil {
return nil, err
}
srcRef = srcRef2
}
if options.SourceCtx == nil {
options.SourceCtx = &types.SystemContext{}
}
hostname := reference.Domain(srcRef.DockerReference())
if secure := svc.isSecureIndex(hostname); !secure {
options.SourceCtx.DockerInsecureSkipTLSVerify = !secure
}
return srcRef, nil
}
func (svc *imageService) PullImage(systemContext *types.SystemContext, imageName string, options *copy.Options) (types.ImageReference, error) {
policy, err := signature.DefaultPolicy(systemContext)
if err != nil {
return nil, err
}
policyContext, err := signature.NewPolicyContext(policy)
if err != nil {
return nil, err
}
if options == nil {
options = &copy.Options{}
}
srcRef, err := svc.prepareImage(imageName, options)
if err != nil {
return nil, err
}
dest := imageName
if srcRef.DockerReference() != nil {
dest = srcRef.DockerReference().Name()
if tagged, ok := srcRef.DockerReference().(reference.NamedTagged); ok {
dest = dest + ":" + tagged.Tag()
}
if canonical, ok := srcRef.DockerReference().(reference.Canonical); ok {
dest = dest + "@" + canonical.Digest().String()
}
}
destRef, err := istorage.Transport.ParseStoreReference(svc.store, dest)
if err != nil {
return nil, err
}
err = copy.Image(policyContext, destRef, srcRef, options)
if err != nil {
return nil, err
}
return destRef, nil
}
func (svc *imageService) UntagImage(systemContext *types.SystemContext, nameOrID string) error {
ref, err := alltransports.ParseImageName(nameOrID)
if err != nil {
ref2, err2 := istorage.Transport.ParseStoreReference(svc.store, "@"+nameOrID)
if err2 != nil {
ref3, err3 := istorage.Transport.ParseStoreReference(svc.store, nameOrID)
if err3 != nil {
return err
}
ref2 = ref3
}
ref = ref2
}
img, err := istorage.Transport.GetStoreImage(svc.store, ref)
if err != nil {
return err
}
if nameOrID != img.ID {
namedRef, err := svc.prepareImage(nameOrID, &copy.Options{})
if err != nil {
return err
}
name := nameOrID
if namedRef.DockerReference() != nil {
name = namedRef.DockerReference().Name()
if tagged, ok := namedRef.DockerReference().(reference.NamedTagged); ok {
name = name + ":" + tagged.Tag()
}
if canonical, ok := namedRef.DockerReference().(reference.Canonical); ok {
name = name + "@" + canonical.Digest().String()
}
}
prunedNames := make([]string, 0, len(img.Names))
for _, imgName := range img.Names {
if imgName != name && imgName != nameOrID {
prunedNames = append(prunedNames, imgName)
}
}
if len(prunedNames) > 0 {
return svc.store.SetNames(img.ID, prunedNames)
}
}
return ref.DeleteImage(systemContext)
}
func (svc *imageService) RemoveImage(systemContext *types.SystemContext, nameOrID string) error {
ref, err := alltransports.ParseImageName(nameOrID)
if err != nil {
ref2, err2 := istorage.Transport.ParseStoreReference(svc.store, "@"+nameOrID)
if err2 != nil {
ref3, err3 := istorage.Transport.ParseStoreReference(svc.store, nameOrID)
if err3 != nil {
return err
}
ref2 = ref3
}
ref = ref2
}
return ref.DeleteImage(systemContext)
}
func (svc *imageService) GetStore() storage.Store {
return svc.store
}
func (svc *imageService) isSecureIndex(indexName string) bool {
if index, ok := svc.indexConfigs[indexName]; ok {
return index.secure
}
host, _, err := net.SplitHostPort(indexName)
if err != nil {
// assume indexName is of the form `host` without the port and go on.
host = indexName
}
addrs, err := net.LookupIP(host)
if err != nil {
ip := net.ParseIP(host)
if ip != nil {
addrs = []net.IP{ip}
}
// if ip == nil, then `host` is neither an IP nor it could be looked up,
// either because the index is unreachable, or because the index is behind an HTTP proxy.
// So, len(addrs) == 0 and we're not aborting.
}
// Try CIDR notation only if addrs has any elements, i.e. if `host`'s IP could be determined.
for _, addr := range addrs {
for _, ipnet := range svc.insecureRegistryCIDRs {
// check if the addr falls in the subnet
if ipnet.Contains(addr) {
return false
}
}
}
return true
}
func isValidHostname(hostname string) bool {
return hostname != "" && !strings.Contains(hostname, "/") &&
(strings.Contains(hostname, ".") ||
strings.Contains(hostname, ":") || hostname == "localhost")
}
func isReferenceFullyQualified(reposName reference.Named) bool {
indexName, _, _ := splitReposName(reposName)
return indexName != ""
}
const (
// defaultHostname is the default built-in hostname
defaultHostname = "docker.io"
// legacyDefaultHostname is automatically converted to DefaultHostname
legacyDefaultHostname = "index.docker.io"
// defaultRepoPrefix is the prefix used for default repositories in default host
defaultRepoPrefix = "library/"
)
// splitReposName breaks a reposName into an index name and remote name
func splitReposName(reposName reference.Named) (indexName string, remoteName reference.Named, err error) {
var remoteNameStr string
indexName, remoteNameStr = distreference.SplitHostname(reposName)
if !isValidHostname(indexName) {
// This is a Docker Index repos (ex: samalba/hipache or ubuntu)
// 'docker.io'
indexName = ""
remoteName = reposName
} else {
remoteName, err = withName(remoteNameStr)
}
return
}
func validateName(name string) error {
if err := validateID(strings.TrimPrefix(name, defaultHostname+"/")); err == nil {
return fmt.Errorf("Invalid repository name (%s), cannot specify 64-byte hexadecimal strings", name)
}
return nil
}
var validHex = regexp.MustCompile(`^([a-f0-9]{64})$`)
// validateID checks whether an ID string is a valid image ID.
func validateID(id string) error {
if ok := validHex.MatchString(id); !ok {
return fmt.Errorf("image ID %q is invalid", id)
}
return nil
}
// withName returns a named object representing the given string. If the input
// is invalid ErrReferenceInvalidFormat will be returned.
func withName(name string) (reference.Named, error) {
name, err := normalize(name)
if err != nil {
return nil, err
}
if err := validateName(name); err != nil {
return nil, err
}
r, err := distreference.WithName(name)
return r, err
}
// splitHostname splits a repository name to hostname and remotename string.
// If no valid hostname is found, empty string will be returned as a resulting
// hostname. Repository name needs to be already validated before.
func splitHostname(name string) (hostname, remoteName string) {
i := strings.IndexRune(name, '/')
if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") {
hostname, remoteName = "", name
} else {
hostname, remoteName = name[:i], name[i+1:]
}
if hostname == legacyDefaultHostname {
hostname = defaultHostname
}
if hostname == defaultHostname && !strings.ContainsRune(remoteName, '/') {
remoteName = defaultRepoPrefix + remoteName
}
return
}
// normalize returns a repository name in its normalized form, meaning it
// will contain library/ prefix for official images.
func normalize(name string) (string, error) {
host, remoteName := splitHostname(name)
if strings.ToLower(remoteName) != remoteName {
return "", errors.New("invalid reference format: repository name must be lowercase")
}
if host == defaultHostname {
if strings.HasPrefix(remoteName, defaultRepoPrefix) {
remoteName = strings.TrimPrefix(remoteName, defaultRepoPrefix)
}
return host + "/" + remoteName, nil
}
return name, nil
}
func (svc *imageService) ResolveNames(imageName string) ([]string, error) {
r, err := reference.ParseNormalizedNamed(imageName)
if err != nil {
return nil, err
}
if isReferenceFullyQualified(r) {
// this means the image is already fully qualified
return []string{imageName}, nil
}
// we got an unqualified image here, we can't go ahead w/o registries configured
// properly.
if len(svc.registries) == 0 {
return nil, errors.New("no registries configured while trying to pull an unqualified image")
}
// this means we got an image in the form of "busybox"
// we need to use additional registries...
// normalize the unqualified image to be domain/repo/image...
_, rest := splitDomain(r.Name())
images := []string{}
for _, r := range svc.registries {
images = append(images, path.Join(r, rest))
}
return images, nil
}
// GetImageService returns an ImageServer that uses the passed-in store, and
// which will prepend the passed-in defaultTransport value to an image name if
// a name that's passed to its PullImage() method can't be resolved to an image
// in the store and can't be resolved to a source on its own.
func GetImageService(store storage.Store, defaultTransport string, insecureRegistries []string, registries []string) (ImageServer, error) {
if store == nil {
var err error
store, err = storage.GetStore(storage.DefaultStoreOptions)
if err != nil {
return nil, err
}
}
seenRegistries := make(map[string]bool, len(registries))
cleanRegistries := []string{}
for _, r := range registries {
if seenRegistries[r] {
continue
}
cleanRegistries = append(cleanRegistries, r)
seenRegistries[r] = true
}
is := &imageService{
store: store,
defaultTransport: defaultTransport,
indexConfigs: make(map[string]*indexInfo),
insecureRegistryCIDRs: make([]*net.IPNet, 0),
registries: cleanRegistries,
}
insecureRegistries = append(insecureRegistries, "127.0.0.0/8")
// Split --insecure-registry into CIDR and registry-specific settings.
for _, r := range insecureRegistries {
// Check if CIDR was passed to --insecure-registry
_, ipnet, err := net.ParseCIDR(r)
if err == nil {
// Valid CIDR.
is.insecureRegistryCIDRs = append(is.insecureRegistryCIDRs, ipnet)
} else {
// Assume `host:port` if not CIDR.
is.indexConfigs[r] = &indexInfo{
name: r,
secure: false,
}
}
}
return is, nil
}

View File

@ -1,125 +0,0 @@
package storage
// This is a fork of docker/distribution code to be used when manipulating image
// references.
// DO NOT EDIT THIS FILE.
import "regexp"
var (
// alphaNumericRegexp defines the alpha numeric atom, typically a
// component of names. This only allows lower case characters and digits.
alphaNumericRegexp = match(`[a-z0-9]+`)
// separatorRegexp defines the separators allowed to be embedded in name
// components. This allow one period, one or two underscore and multiple
// dashes.
separatorRegexp = match(`(?:[._]|__|[-]*)`)
// nameComponentRegexp restricts registry path component names to start
// with at least one letter or number, with following parts able to be
// separated by one period, one or two underscore and multiple dashes.
nameComponentRegexp = expression(
alphaNumericRegexp,
optional(repeated(separatorRegexp, alphaNumericRegexp)))
// domainComponentRegexp restricts the registry domain component of a
// repository name to start with a component as defined by domainRegexp
// and followed by an optional port.
domainComponentRegexp = match(`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`)
// domainRegexp defines the structure of potential domain components
// that may be part of image names. This is purposely a subset of what is
// allowed by DNS to ensure backwards compatibility with Docker image
// names.
domainRegexp = expression(
domainComponentRegexp,
optional(repeated(literal(`.`), domainComponentRegexp)),
optional(literal(`:`), match(`[0-9]+`)))
// NameRegexp is the format for the name component of references. The
// regexp has capturing groups for the domain and name part omitting
// the separating forward slash from either.
NameRegexp = expression(
optional(domainRegexp, literal(`/`)),
nameComponentRegexp,
optional(repeated(literal(`/`), nameComponentRegexp)))
// anchoredNameRegexp is used to parse a name value, capturing the
// domain and trailing components.
anchoredNameRegexp = anchored(
optional(capture(domainRegexp), literal(`/`)),
capture(nameComponentRegexp,
optional(repeated(literal(`/`), nameComponentRegexp))))
// IdentifierRegexp is the format for string identifier used as a
// content addressable identifier using sha256. These identifiers
// are like digests without the algorithm, since sha256 is used.
IdentifierRegexp = match(`([a-f0-9]{64})`)
// ShortIdentifierRegexp is the format used to represent a prefix
// of an identifier. A prefix may be used to match a sha256 identifier
// within a list of trusted identifiers.
ShortIdentifierRegexp = match(`([a-f0-9]{6,64})`)
)
// match compiles the string to a regular expression.
var match = regexp.MustCompile
// literal compiles s into a literal regular expression, escaping any regexp
// reserved characters.
func literal(s string) *regexp.Regexp {
re := match(regexp.QuoteMeta(s))
if _, complete := re.LiteralPrefix(); !complete {
panic("must be a literal")
}
return re
}
func splitDomain(name string) (string, string) {
match := anchoredNameRegexp.FindStringSubmatch(name)
if len(match) != 3 {
return "", name
}
return match[1], match[2]
}
// expression defines a full expression, where each regular expression must
// follow the previous.
func expression(res ...*regexp.Regexp) *regexp.Regexp {
var s string
for _, re := range res {
s += re.String()
}
return match(s)
}
// optional wraps the expression in a non-capturing group and makes the
// production optional.
func optional(res ...*regexp.Regexp) *regexp.Regexp {
return match(group(expression(res...)).String() + `?`)
}
// repeated wraps the regexp in a non-capturing group to get one or more
// matches.
func repeated(res ...*regexp.Regexp) *regexp.Regexp {
return match(group(expression(res...)).String() + `+`)
}
// group wraps the regexp in a non-capturing group.
func group(res ...*regexp.Regexp) *regexp.Regexp {
return match(`(?:` + expression(res...).String() + `)`)
}
// capture wraps the expression in a capturing group.
func capture(res ...*regexp.Regexp) *regexp.Regexp {
return match(`(` + expression(res...).String() + `)`)
}
// anchored anchors the regular expression by adding start and end delimiters.
func anchored(res ...*regexp.Regexp) *regexp.Regexp {
return match(`^` + expression(res...).String() + `$`)
}

View File

@ -1,452 +0,0 @@
package storage
import (
"encoding/json"
"fmt"
"time"
"github.com/containers/image/copy"
istorage "github.com/containers/image/storage"
"github.com/containers/image/transports/alltransports"
"github.com/containers/image/types"
"github.com/containers/storage"
"github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
var (
// ErrInvalidPodName is returned when a pod name specified to a
// function call is found to be invalid (most often, because it's
// empty).
ErrInvalidPodName = errors.New("invalid pod name")
// ErrInvalidImageName is returned when an image name specified to a
// function call is found to be invalid (most often, because it's
// empty).
ErrInvalidImageName = errors.New("invalid image name")
// ErrInvalidContainerName is returned when a container name specified
// to a function call is found to be invalid (most often, because it's
// empty).
ErrInvalidContainerName = errors.New("invalid container name")
// ErrInvalidSandboxID is returned when a sandbox ID specified to a
// function call is found to be invalid (because it's either
// empty or doesn't match a valid sandbox).
ErrInvalidSandboxID = errors.New("invalid sandbox ID")
// ErrInvalidContainerID is returned when a container ID specified to a
// function call is found to be invalid (because it's either
// empty or doesn't match a valid container).
ErrInvalidContainerID = errors.New("invalid container ID")
)
type runtimeService struct {
storageImageServer ImageServer
pauseImage string
}
// ContainerInfo wraps a subset of information about a container: its ID and
// the locations of its nonvolatile and volatile per-container directories,
// along with a copy of the configuration blob from the image that was used to
// create the container, if the image had a configuration.
type ContainerInfo struct {
ID string
Dir string
RunDir string
Config *v1.Image
}
// RuntimeServer wraps up various CRI-related activities into a reusable
// implementation.
type RuntimeServer interface {
// CreatePodSandbox creates a pod infrastructure container, using the
// specified PodID for the infrastructure container's ID. In the CRI
// view of things, a sandbox is distinct from its containers, including
// its infrastructure container, but at this level the sandbox is
// essentially the same as its infrastructure container, with a
// container's membership in a pod being signified by it listing the
// same pod ID in its metadata that the pod's other members do, and
// with the pod's infrastructure container having the same value for
// both its pod's ID and its container ID.
// Pointer arguments can be nil. Either the image name or ID can be
// omitted, but not both. All other arguments are required.
CreatePodSandbox(systemContext *types.SystemContext, podName, podID, imageName, imageID, containerName, metadataName, uid, namespace string, attempt uint32, copyOptions *copy.Options) (ContainerInfo, error)
// RemovePodSandbox deletes a pod sandbox's infrastructure container.
// The CRI expects that a sandbox can't be removed unless its only
// container is its infrastructure container, but we don't enforce that
// here, since we're just keeping track of it for higher level APIs.
RemovePodSandbox(idOrName string) error
// GetContainerMetadata returns the metadata we've stored for a container.
GetContainerMetadata(idOrName string) (RuntimeContainerMetadata, error)
// SetContainerMetadata updates the metadata we've stored for a container.
SetContainerMetadata(idOrName string, metadata RuntimeContainerMetadata) error
// CreateContainer creates a container with the specified ID.
// Pointer arguments can be nil. Either the image name or ID can be
// omitted, but not both. All other arguments are required.
CreateContainer(systemContext *types.SystemContext, podName, podID, imageName, imageID, containerName, containerID, metadataName string, attempt uint32, mountLabel string, copyOptions *copy.Options) (ContainerInfo, error)
// DeleteContainer deletes a container, unmounting it first if need be.
DeleteContainer(idOrName string) error
// StartContainer makes sure a container's filesystem is mounted, and
// returns the location of its root filesystem, which is not guaranteed
// by lower-level drivers to never change.
StartContainer(idOrName string) (string, error)
// StopContainer attempts to unmount a container's root filesystem,
// freeing up any kernel resources which may be limited.
StopContainer(idOrName string) error
// GetWorkDir returns the path of a nonvolatile directory on the
// filesystem (somewhere under the Store's Root directory) which can be
// used to store arbitrary data that is specific to the container. It
// will be removed automatically when the container is deleted.
GetWorkDir(id string) (string, error)
// GetRunDir returns the path of a volatile directory (does not survive
// the host rebooting, somewhere under the Store's RunRoot directory)
// on the filesystem which can be used to store arbitrary data that is
// specific to the container. It will be removed automatically when
// the container is deleted.
GetRunDir(id string) (string, error)
}
// RuntimeContainerMetadata is the structure that we encode as JSON and store
// in the metadata field of storage.Container objects. It is used for
// specifying attributes of pod sandboxes and containers when they are being
// created, and allows a container's MountLabel, and possibly other values, to
// be modified in one read/write cycle via calls to
// RuntimeServer.ContainerMetadata, RuntimeContainerMetadata.SetMountLabel,
// and RuntimeServer.SetContainerMetadata.
type RuntimeContainerMetadata struct {
// Pod is true if this is the pod's infrastructure container.
Pod bool `json:"pod,omitempty"` // Applicable to both PodSandboxes and Containers
// The pod's name and ID, kept for use by upper layers in determining
// which containers belong to which pods.
PodName string `json:"pod-name"` // Applicable to both PodSandboxes and Containers, mandatory
PodID string `json:"pod-id"` // Applicable to both PodSandboxes and Containers, mandatory
// The provided name and the ID of the image that was used to
// instantiate the container.
ImageName string `json:"image-name"` // Applicable to both PodSandboxes and Containers
ImageID string `json:"image-id"` // Applicable to both PodSandboxes and Containers
// The container's name, which for an infrastructure container is usually PodName + "-infra".
ContainerName string `json:"name"` // Applicable to both PodSandboxes and Containers, mandatory
// The name as originally specified in PodSandbox or Container CRI metadata.
MetadataName string `json:"metadata-name"` // Applicable to both PodSandboxes and Containers, mandatory
UID string `json:"uid,omitempty"` // Only applicable to pods
Namespace string `json:"namespace,omitempty"` // Only applicable to pods
Attempt uint32 `json:"attempt,omitempty"` // Applicable to both PodSandboxes and Containers
CreatedAt int64 `json:"created-at"` // Applicable to both PodSandboxes and Containers
MountLabel string `json:"mountlabel,omitempty"` // Applicable to both PodSandboxes and Containers
}
// SetMountLabel updates the mount label held by a RuntimeContainerMetadata
// object.
func (metadata *RuntimeContainerMetadata) SetMountLabel(mountLabel string) {
metadata.MountLabel = mountLabel
}
func (r *runtimeService) createContainerOrPodSandbox(systemContext *types.SystemContext, podName, podID, imageName, imageID, containerName, containerID, metadataName, uid, namespace string, attempt uint32, mountLabel string, options *copy.Options) (ContainerInfo, error) {
var ref types.ImageReference
if podName == "" || podID == "" {
return ContainerInfo{}, ErrInvalidPodName
}
if imageName == "" && imageID == "" {
return ContainerInfo{}, ErrInvalidImageName
}
if containerName == "" {
return ContainerInfo{}, ErrInvalidContainerName
}
if metadataName == "" {
metadataName = containerName
}
// Check if we have the specified image.
ref, err := istorage.Transport.ParseStoreReference(r.storageImageServer.GetStore(), imageName)
if err != nil {
// Maybe it's some other transport's copy of the image?
otherRef, err2 := alltransports.ParseImageName(imageName)
if err2 == nil && otherRef.DockerReference() != nil {
ref, err = istorage.Transport.ParseStoreReference(r.storageImageServer.GetStore(), otherRef.DockerReference().Name())
}
if err != nil {
// Maybe the image ID is sufficient?
ref, err = istorage.Transport.ParseStoreReference(r.storageImageServer.GetStore(), "@"+imageID)
if err != nil {
return ContainerInfo{}, err
}
}
}
img, err := istorage.Transport.GetStoreImage(r.storageImageServer.GetStore(), ref)
if img == nil && errors.Cause(err) == storage.ErrImageUnknown && imageName == r.pauseImage {
image := imageID
if imageName != "" {
image = imageName
}
if image == "" {
return ContainerInfo{}, ErrInvalidImageName
}
logrus.Debugf("couldn't find image %q, retrieving it", image)
ref, err = r.storageImageServer.PullImage(systemContext, image, options)
if err != nil {
return ContainerInfo{}, err
}
img, err = istorage.Transport.GetStoreImage(r.storageImageServer.GetStore(), ref)
if err != nil {
return ContainerInfo{}, err
}
logrus.Debugf("successfully pulled image %q", image)
}
if img == nil && errors.Cause(err) == storage.ErrImageUnknown {
if imageID == "" {
return ContainerInfo{}, fmt.Errorf("image %q not present in image store", imageName)
}
if imageName == "" {
return ContainerInfo{}, fmt.Errorf("image with ID %q not present in image store", imageID)
}
return ContainerInfo{}, fmt.Errorf("image %q with ID %q not present in image store", imageName, imageID)
}
// Pull out a copy of the image's configuration.
image, err := ref.NewImage(systemContext)
if err != nil {
return ContainerInfo{}, err
}
defer image.Close()
imageConfig, err := image.OCIConfig()
if err != nil {
return ContainerInfo{}, err
}
// Update the image name and ID.
if imageName == "" && len(img.Names) > 0 {
imageName = img.Names[0]
}
imageID = img.ID
// Build metadata to store with the container.
metadata := RuntimeContainerMetadata{
Pod: containerID == podID,
PodName: podName,
PodID: podID,
ImageName: imageName,
ImageID: imageID,
ContainerName: containerName,
MetadataName: metadataName,
UID: uid,
Namespace: namespace,
Attempt: attempt,
CreatedAt: time.Now().Unix(),
MountLabel: mountLabel,
}
mdata, err := json.Marshal(&metadata)
if err != nil {
return ContainerInfo{}, err
}
// Build the container.
names := []string{metadata.ContainerName}
if metadata.Pod {
names = append(names, metadata.PodName)
}
container, err := r.storageImageServer.GetStore().CreateContainer(containerID, names, img.ID, "", string(mdata), nil)
if err != nil {
if metadata.Pod {
logrus.Debugf("failed to create pod sandbox %s(%s): %v", metadata.PodName, metadata.PodID, err)
} else {
logrus.Debugf("failed to create container %s(%s): %v", metadata.ContainerName, containerID, err)
}
return ContainerInfo{}, err
}
if metadata.Pod {
logrus.Debugf("created pod sandbox %q", container.ID)
} else {
logrus.Debugf("created container %q", container.ID)
}
// If anything fails after this point, we need to delete the incomplete
// container before returning.
defer func() {
if err != nil {
if err2 := r.storageImageServer.GetStore().DeleteContainer(container.ID); err2 != nil {
if metadata.Pod {
logrus.Infof("%v deleting partially-created pod sandbox %q", err2, container.ID)
} else {
logrus.Infof("%v deleting partially-created container %q", err2, container.ID)
}
return
}
logrus.Infof("deleted partially-created container %q", container.ID)
}
}()
// Add a name to the container's layer so that it's easier to follow
// what's going on if we're just looking at the storage-eye view of things.
layerName := metadata.ContainerName + "-layer"
names, err = r.storageImageServer.GetStore().Names(container.LayerID)
if err != nil {
return ContainerInfo{}, err
}
names = append(names, layerName)
err = r.storageImageServer.GetStore().SetNames(container.LayerID, names)
if err != nil {
return ContainerInfo{}, err
}
// Find out where the container work directories are, so that we can return them.
containerDir, err := r.storageImageServer.GetStore().ContainerDirectory(container.ID)
if err != nil {
return ContainerInfo{}, err
}
if metadata.Pod {
logrus.Debugf("pod sandbox %q has work directory %q", container.ID, containerDir)
} else {
logrus.Debugf("container %q has work directory %q", container.ID, containerDir)
}
containerRunDir, err := r.storageImageServer.GetStore().ContainerRunDirectory(container.ID)
if err != nil {
return ContainerInfo{}, err
}
if metadata.Pod {
logrus.Debugf("pod sandbox %q has run directory %q", container.ID, containerRunDir)
} else {
logrus.Debugf("container %q has run directory %q", container.ID, containerRunDir)
}
return ContainerInfo{
ID: container.ID,
Dir: containerDir,
RunDir: containerRunDir,
Config: imageConfig,
}, nil
}
func (r *runtimeService) CreatePodSandbox(systemContext *types.SystemContext, podName, podID, imageName, imageID, containerName, metadataName, uid, namespace string, attempt uint32, copyOptions *copy.Options) (ContainerInfo, error) {
return r.createContainerOrPodSandbox(systemContext, podName, podID, imageName, imageID, containerName, podID, metadataName, uid, namespace, attempt, "", copyOptions)
}
func (r *runtimeService) CreateContainer(systemContext *types.SystemContext, podName, podID, imageName, imageID, containerName, containerID, metadataName string, attempt uint32, mountLabel string, copyOptions *copy.Options) (ContainerInfo, error) {
return r.createContainerOrPodSandbox(systemContext, podName, podID, imageName, imageID, containerName, containerID, metadataName, "", "", attempt, mountLabel, copyOptions)
}
func (r *runtimeService) RemovePodSandbox(idOrName string) error {
container, err := r.storageImageServer.GetStore().Container(idOrName)
if err != nil {
if errors.Cause(err) == storage.ErrContainerUnknown {
return ErrInvalidSandboxID
}
return err
}
err = r.storageImageServer.GetStore().DeleteContainer(container.ID)
if err != nil {
logrus.Debugf("failed to delete pod sandbox %q: %v", container.ID, err)
return err
}
return nil
}
func (r *runtimeService) DeleteContainer(idOrName string) error {
if idOrName == "" {
return ErrInvalidContainerID
}
container, err := r.storageImageServer.GetStore().Container(idOrName)
if err != nil {
return err
}
err = r.storageImageServer.GetStore().DeleteContainer(container.ID)
if err != nil {
logrus.Debugf("failed to delete container %q: %v", container.ID, err)
return err
}
return nil
}
func (r *runtimeService) SetContainerMetadata(idOrName string, metadata RuntimeContainerMetadata) error {
mdata, err := json.Marshal(&metadata)
if err != nil {
logrus.Debugf("failed to encode metadata for %q: %v", idOrName, err)
return err
}
return r.storageImageServer.GetStore().SetMetadata(idOrName, string(mdata))
}
func (r *runtimeService) GetContainerMetadata(idOrName string) (RuntimeContainerMetadata, error) {
metadata := RuntimeContainerMetadata{}
mdata, err := r.storageImageServer.GetStore().Metadata(idOrName)
if err != nil {
return metadata, err
}
if err = json.Unmarshal([]byte(mdata), &metadata); err != nil {
return metadata, err
}
return metadata, nil
}
func (r *runtimeService) StartContainer(idOrName string) (string, error) {
container, err := r.storageImageServer.GetStore().Container(idOrName)
if err != nil {
if errors.Cause(err) == storage.ErrContainerUnknown {
return "", ErrInvalidContainerID
}
return "", err
}
metadata := RuntimeContainerMetadata{}
if err = json.Unmarshal([]byte(container.Metadata), &metadata); err != nil {
return "", err
}
mountPoint, err := r.storageImageServer.GetStore().Mount(container.ID, metadata.MountLabel)
if err != nil {
logrus.Debugf("failed to mount container %q: %v", container.ID, err)
return "", err
}
logrus.Debugf("mounted container %q at %q", container.ID, mountPoint)
return mountPoint, nil
}
func (r *runtimeService) StopContainer(idOrName string) error {
if idOrName == "" {
return ErrInvalidContainerID
}
container, err := r.storageImageServer.GetStore().Container(idOrName)
if err != nil {
return err
}
err = r.storageImageServer.GetStore().Unmount(container.ID)
if err != nil {
logrus.Debugf("failed to unmount container %q: %v", container.ID, err)
return err
}
logrus.Debugf("unmounted container %q", container.ID)
return nil
}
func (r *runtimeService) GetWorkDir(id string) (string, error) {
container, err := r.storageImageServer.GetStore().Container(id)
if err != nil {
if errors.Cause(err) == storage.ErrContainerUnknown {
return "", ErrInvalidContainerID
}
return "", err
}
return r.storageImageServer.GetStore().ContainerDirectory(container.ID)
}
func (r *runtimeService) GetRunDir(id string) (string, error) {
container, err := r.storageImageServer.GetStore().Container(id)
if err != nil {
if errors.Cause(err) == storage.ErrContainerUnknown {
return "", ErrInvalidContainerID
}
return "", err
}
return r.storageImageServer.GetStore().ContainerRunDirectory(container.ID)
}
// GetRuntimeService returns a RuntimeServer that uses the passed-in image
// service to pull and manage images, and its store to manage containers based
// on those images.
func GetRuntimeService(storageImageServer ImageServer, pauseImage string) RuntimeServer {
return &runtimeService{
storageImageServer: storageImageServer,
pauseImage: pauseImage,
}
}