vendor: github.com/moby/buildkit ae7ff7174f73bcb4df89b97e1623b3fb0bfb0a0c
full diff: 4f4e030675...ae7ff7174f
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
112
vendor/github.com/containerd/containerd/containers/containers.go
generated
vendored
112
vendor/github.com/containerd/containerd/containers/containers.go
generated
vendored
@ -1,112 +0,0 @@
|
||||
/*
|
||||
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 containers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/gogo/protobuf/types"
|
||||
)
|
||||
|
||||
// Container represents the set of data pinned by a container. Unless otherwise
|
||||
// noted, the resources here are considered in use by the container.
|
||||
//
|
||||
// The resources specified in this object are used to create tasks from the container.
|
||||
type Container struct {
|
||||
// ID uniquely identifies the container in a namespace.
|
||||
//
|
||||
// This property is required and cannot be changed after creation.
|
||||
ID string
|
||||
|
||||
// Labels provide metadata extension for a container.
|
||||
//
|
||||
// These are optional and fully mutable.
|
||||
Labels map[string]string
|
||||
|
||||
// Image specifies the image reference used for a container.
|
||||
//
|
||||
// This property is optional and mutable.
|
||||
Image string
|
||||
|
||||
// Runtime specifies which runtime should be used when launching container
|
||||
// tasks.
|
||||
//
|
||||
// This property is required and immutable.
|
||||
Runtime RuntimeInfo
|
||||
|
||||
// Spec should carry the runtime specification used to implement the
|
||||
// container.
|
||||
//
|
||||
// This field is required but mutable.
|
||||
Spec *types.Any
|
||||
|
||||
// SnapshotKey specifies the snapshot key to use for the container's root
|
||||
// filesystem. When starting a task from this container, a caller should
|
||||
// look up the mounts from the snapshot service and include those on the
|
||||
// task create request.
|
||||
//
|
||||
// This field is not required but mutable.
|
||||
SnapshotKey string
|
||||
|
||||
// Snapshotter specifies the snapshotter name used for rootfs
|
||||
//
|
||||
// This field is not required but immutable.
|
||||
Snapshotter string
|
||||
|
||||
// CreatedAt is the time at which the container was created.
|
||||
CreatedAt time.Time
|
||||
|
||||
// UpdatedAt is the time at which the container was updated.
|
||||
UpdatedAt time.Time
|
||||
|
||||
// Extensions stores client-specified metadata
|
||||
Extensions map[string]types.Any
|
||||
}
|
||||
|
||||
// RuntimeInfo holds runtime specific information
|
||||
type RuntimeInfo struct {
|
||||
Name string
|
||||
Options *types.Any
|
||||
}
|
||||
|
||||
// Store interacts with the underlying container storage
|
||||
type Store interface {
|
||||
// Get a container using the id.
|
||||
//
|
||||
// Container object is returned on success. If the id is not known to the
|
||||
// store, an error will be returned.
|
||||
Get(ctx context.Context, id string) (Container, error)
|
||||
|
||||
// List returns containers that match one or more of the provided filters.
|
||||
List(ctx context.Context, filters ...string) ([]Container, error)
|
||||
|
||||
// Create a container in the store from the provided container.
|
||||
Create(ctx context.Context, container Container) (Container, error)
|
||||
|
||||
// Update the container with the provided container object. ID must be set.
|
||||
//
|
||||
// If one or more fieldpaths are provided, only the field corresponding to
|
||||
// the fieldpaths will be mutated.
|
||||
Update(ctx context.Context, container Container, fieldpaths ...string) (Container, error)
|
||||
|
||||
// Delete a container using the id.
|
||||
//
|
||||
// nil will be returned on success. If the container is not known to the
|
||||
// store, ErrNotFound will be returned.
|
||||
Delete(ctx context.Context, id string) error
|
||||
}
|
||||
23
vendor/github.com/containerd/containerd/images/annotations.go
generated
vendored
23
vendor/github.com/containerd/containerd/images/annotations.go
generated
vendored
@ -1,23 +0,0 @@
|
||||
/*
|
||||
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 images
|
||||
|
||||
const (
|
||||
// AnnotationImageName is an annotation on a Descriptor in an index.json
|
||||
// containing the `Name` value as used by an `Image` struct
|
||||
AnnotationImageName = "io.containerd.image.name"
|
||||
)
|
||||
256
vendor/github.com/containerd/containerd/images/handlers.go
generated
vendored
256
vendor/github.com/containerd/containerd/images/handlers.go
generated
vendored
@ -1,256 +0,0 @@
|
||||
/*
|
||||
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 images
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"golang.org/x/sync/semaphore"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrSkipDesc is used to skip processing of a descriptor and
|
||||
// its descendants.
|
||||
ErrSkipDesc = fmt.Errorf("skip descriptor")
|
||||
|
||||
// ErrStopHandler is used to signify that the descriptor
|
||||
// has been handled and should not be handled further.
|
||||
// This applies only to a single descriptor in a handler
|
||||
// chain and does not apply to descendant descriptors.
|
||||
ErrStopHandler = fmt.Errorf("stop handler")
|
||||
)
|
||||
|
||||
// Handler handles image manifests
|
||||
type Handler interface {
|
||||
Handle(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error)
|
||||
}
|
||||
|
||||
// HandlerFunc function implementing the Handler interface
|
||||
type HandlerFunc func(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error)
|
||||
|
||||
// Handle image manifests
|
||||
func (fn HandlerFunc) Handle(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error) {
|
||||
return fn(ctx, desc)
|
||||
}
|
||||
|
||||
// Handlers returns a handler that will run the handlers in sequence.
|
||||
//
|
||||
// A handler may return `ErrStopHandler` to stop calling additional handlers
|
||||
func Handlers(handlers ...Handler) HandlerFunc {
|
||||
return func(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error) {
|
||||
var children []ocispec.Descriptor
|
||||
for _, handler := range handlers {
|
||||
ch, err := handler.Handle(ctx, desc)
|
||||
if err != nil {
|
||||
if errors.Cause(err) == ErrStopHandler {
|
||||
break
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
children = append(children, ch...)
|
||||
}
|
||||
|
||||
return children, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Walk the resources of an image and call the handler for each. If the handler
|
||||
// decodes the sub-resources for each image,
|
||||
//
|
||||
// This differs from dispatch in that each sibling resource is considered
|
||||
// synchronously.
|
||||
func Walk(ctx context.Context, handler Handler, descs ...ocispec.Descriptor) error {
|
||||
for _, desc := range descs {
|
||||
|
||||
children, err := handler.Handle(ctx, desc)
|
||||
if err != nil {
|
||||
if errors.Cause(err) == ErrSkipDesc {
|
||||
continue // don't traverse the children.
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if len(children) > 0 {
|
||||
if err := Walk(ctx, handler, children...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Dispatch runs the provided handler for content specified by the descriptors.
|
||||
// If the handler decode subresources, they will be visited, as well.
|
||||
//
|
||||
// Handlers for siblings are run in parallel on the provided descriptors. A
|
||||
// handler may return `ErrSkipDesc` to signal to the dispatcher to not traverse
|
||||
// any children.
|
||||
//
|
||||
// A concurrency limiter can be passed in to limit the number of concurrent
|
||||
// handlers running. When limiter is nil, there is no limit.
|
||||
//
|
||||
// Typically, this function will be used with `FetchHandler`, often composed
|
||||
// with other handlers.
|
||||
//
|
||||
// If any handler returns an error, the dispatch session will be canceled.
|
||||
func Dispatch(ctx context.Context, handler Handler, limiter *semaphore.Weighted, descs ...ocispec.Descriptor) error {
|
||||
eg, ctx2 := errgroup.WithContext(ctx)
|
||||
for _, desc := range descs {
|
||||
desc := desc
|
||||
|
||||
if limiter != nil {
|
||||
if err := limiter.Acquire(ctx, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
eg.Go(func() error {
|
||||
desc := desc
|
||||
|
||||
children, err := handler.Handle(ctx2, desc)
|
||||
if limiter != nil {
|
||||
limiter.Release(1)
|
||||
}
|
||||
if err != nil {
|
||||
if errors.Cause(err) == ErrSkipDesc {
|
||||
return nil // don't traverse the children.
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if len(children) > 0 {
|
||||
return Dispatch(ctx2, handler, limiter, children...)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
return eg.Wait()
|
||||
}
|
||||
|
||||
// ChildrenHandler decodes well-known manifest types and returns their children.
|
||||
//
|
||||
// This is useful for supporting recursive fetch and other use cases where you
|
||||
// want to do a full walk of resources.
|
||||
//
|
||||
// One can also replace this with another implementation to allow descending of
|
||||
// arbitrary types.
|
||||
func ChildrenHandler(provider content.Provider) HandlerFunc {
|
||||
return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
return Children(ctx, provider, desc)
|
||||
}
|
||||
}
|
||||
|
||||
// SetChildrenLabels is a handler wrapper which sets labels for the content on
|
||||
// the children returned by the handler and passes through the children.
|
||||
// Must follow a handler that returns the children to be labeled.
|
||||
func SetChildrenLabels(manager content.Manager, f HandlerFunc) HandlerFunc {
|
||||
return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
children, err := f(ctx, desc)
|
||||
if err != nil {
|
||||
return children, err
|
||||
}
|
||||
|
||||
if len(children) > 0 {
|
||||
info := content.Info{
|
||||
Digest: desc.Digest,
|
||||
Labels: map[string]string{},
|
||||
}
|
||||
fields := []string{}
|
||||
for i, ch := range children {
|
||||
info.Labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i)] = ch.Digest.String()
|
||||
fields = append(fields, fmt.Sprintf("labels.containerd.io/gc.ref.content.%d", i))
|
||||
}
|
||||
|
||||
_, err := manager.Update(ctx, info, fields...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return children, err
|
||||
}
|
||||
}
|
||||
|
||||
// FilterPlatforms is a handler wrapper which limits the descriptors returned
|
||||
// based on matching the specified platform matcher.
|
||||
func FilterPlatforms(f HandlerFunc, m platforms.Matcher) HandlerFunc {
|
||||
return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
children, err := f(ctx, desc)
|
||||
if err != nil {
|
||||
return children, err
|
||||
}
|
||||
|
||||
var descs []ocispec.Descriptor
|
||||
|
||||
if m == nil {
|
||||
descs = children
|
||||
} else {
|
||||
for _, d := range children {
|
||||
if d.Platform == nil || m.Match(*d.Platform) {
|
||||
descs = append(descs, d)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return descs, nil
|
||||
}
|
||||
}
|
||||
|
||||
// LimitManifests is a handler wrapper which filters the manifest descriptors
|
||||
// returned using the provided platform.
|
||||
// The results will be ordered according to the comparison operator and
|
||||
// use the ordering in the manifests for equal matches.
|
||||
// A limit of 0 or less is considered no limit.
|
||||
func LimitManifests(f HandlerFunc, m platforms.MatchComparer, n int) HandlerFunc {
|
||||
return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
children, err := f(ctx, desc)
|
||||
if err != nil {
|
||||
return children, err
|
||||
}
|
||||
|
||||
switch desc.MediaType {
|
||||
case ocispec.MediaTypeImageIndex, MediaTypeDockerSchema2ManifestList:
|
||||
sort.SliceStable(children, func(i, j int) bool {
|
||||
if children[i].Platform == nil {
|
||||
return false
|
||||
}
|
||||
if children[j].Platform == nil {
|
||||
return true
|
||||
}
|
||||
return m.Less(*children[i].Platform, *children[j].Platform)
|
||||
})
|
||||
|
||||
if n > 0 && len(children) > n {
|
||||
children = children[:n]
|
||||
}
|
||||
default:
|
||||
// only limit manifests from an index
|
||||
}
|
||||
return children, nil
|
||||
}
|
||||
}
|
||||
386
vendor/github.com/containerd/containerd/images/image.go
generated
vendored
386
vendor/github.com/containerd/containerd/images/image.go
generated
vendored
@ -1,386 +0,0 @@
|
||||
/*
|
||||
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 images
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Image provides the model for how containerd views container images.
|
||||
type Image struct {
|
||||
// Name of the image.
|
||||
//
|
||||
// To be pulled, it must be a reference compatible with resolvers.
|
||||
//
|
||||
// This field is required.
|
||||
Name string
|
||||
|
||||
// Labels provide runtime decoration for the image record.
|
||||
//
|
||||
// There is no default behavior for how these labels are propagated. They
|
||||
// only decorate the static metadata object.
|
||||
//
|
||||
// This field is optional.
|
||||
Labels map[string]string
|
||||
|
||||
// Target describes the root content for this image. Typically, this is
|
||||
// a manifest, index or manifest list.
|
||||
Target ocispec.Descriptor
|
||||
|
||||
CreatedAt, UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// DeleteOptions provide options on image delete
|
||||
type DeleteOptions struct {
|
||||
Synchronous bool
|
||||
}
|
||||
|
||||
// DeleteOpt allows configuring a delete operation
|
||||
type DeleteOpt func(context.Context, *DeleteOptions) error
|
||||
|
||||
// SynchronousDelete is used to indicate that an image deletion and removal of
|
||||
// the image resources should occur synchronously before returning a result.
|
||||
func SynchronousDelete() DeleteOpt {
|
||||
return func(ctx context.Context, o *DeleteOptions) error {
|
||||
o.Synchronous = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Store and interact with images
|
||||
type Store interface {
|
||||
Get(ctx context.Context, name string) (Image, error)
|
||||
List(ctx context.Context, filters ...string) ([]Image, error)
|
||||
Create(ctx context.Context, image Image) (Image, error)
|
||||
|
||||
// Update will replace the data in the store with the provided image. If
|
||||
// one or more fieldpaths are provided, only those fields will be updated.
|
||||
Update(ctx context.Context, image Image, fieldpaths ...string) (Image, error)
|
||||
|
||||
Delete(ctx context.Context, name string, opts ...DeleteOpt) error
|
||||
}
|
||||
|
||||
// TODO(stevvooe): Many of these functions make strong platform assumptions,
|
||||
// which are untrue in a lot of cases. More refactoring must be done here to
|
||||
// make this work in all cases.
|
||||
|
||||
// Config resolves the image configuration descriptor.
|
||||
//
|
||||
// The caller can then use the descriptor to resolve and process the
|
||||
// configuration of the image.
|
||||
func (image *Image) Config(ctx context.Context, provider content.Provider, platform platforms.MatchComparer) (ocispec.Descriptor, error) {
|
||||
return Config(ctx, provider, image.Target, platform)
|
||||
}
|
||||
|
||||
// RootFS returns the unpacked diffids that make up and images rootfs.
|
||||
//
|
||||
// These are used to verify that a set of layers unpacked to the expected
|
||||
// values.
|
||||
func (image *Image) RootFS(ctx context.Context, provider content.Provider, platform platforms.MatchComparer) ([]digest.Digest, error) {
|
||||
desc, err := image.Config(ctx, provider, platform)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return RootFS(ctx, provider, desc)
|
||||
}
|
||||
|
||||
// Size returns the total size of an image's packed resources.
|
||||
func (image *Image) Size(ctx context.Context, provider content.Provider, platform platforms.MatchComparer) (int64, error) {
|
||||
var size int64
|
||||
return size, Walk(ctx, Handlers(HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
if desc.Size < 0 {
|
||||
return nil, errors.Errorf("invalid size %v in %v (%v)", desc.Size, desc.Digest, desc.MediaType)
|
||||
}
|
||||
size += desc.Size
|
||||
return nil, nil
|
||||
}), LimitManifests(FilterPlatforms(ChildrenHandler(provider), platform), platform, 1)), image.Target)
|
||||
}
|
||||
|
||||
type platformManifest struct {
|
||||
p *ocispec.Platform
|
||||
m *ocispec.Manifest
|
||||
}
|
||||
|
||||
// Manifest resolves a manifest from the image for the given platform.
|
||||
//
|
||||
// When a manifest descriptor inside of a manifest index does not have
|
||||
// a platform defined, the platform from the image config is considered.
|
||||
//
|
||||
// If the descriptor points to a non-index manifest, then the manifest is
|
||||
// unmarshalled and returned without considering the platform inside of the
|
||||
// config.
|
||||
//
|
||||
// TODO(stevvooe): This violates the current platform agnostic approach to this
|
||||
// package by returning a specific manifest type. We'll need to refactor this
|
||||
// to return a manifest descriptor or decide that we want to bring the API in
|
||||
// this direction because this abstraction is not needed.`
|
||||
func Manifest(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform platforms.MatchComparer) (ocispec.Manifest, error) {
|
||||
var (
|
||||
limit = 1
|
||||
m []platformManifest
|
||||
wasIndex bool
|
||||
)
|
||||
|
||||
if err := Walk(ctx, HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
switch desc.MediaType {
|
||||
case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
|
||||
p, err := content.ReadBlob(ctx, provider, desc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var manifest ocispec.Manifest
|
||||
if err := json.Unmarshal(p, &manifest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if desc.Digest != image.Digest && platform != nil {
|
||||
if desc.Platform != nil && !platform.Match(*desc.Platform) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if desc.Platform == nil {
|
||||
p, err := content.ReadBlob(ctx, provider, manifest.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var image ocispec.Image
|
||||
if err := json.Unmarshal(p, &image); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !platform.Match(platforms.Normalize(ocispec.Platform{OS: image.OS, Architecture: image.Architecture})) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
m = append(m, platformManifest{
|
||||
p: desc.Platform,
|
||||
m: &manifest,
|
||||
})
|
||||
|
||||
return nil, nil
|
||||
case MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
|
||||
p, err := content.ReadBlob(ctx, provider, desc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var idx ocispec.Index
|
||||
if err := json.Unmarshal(p, &idx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if platform == nil {
|
||||
return idx.Manifests, nil
|
||||
}
|
||||
|
||||
var descs []ocispec.Descriptor
|
||||
for _, d := range idx.Manifests {
|
||||
if d.Platform == nil || platform.Match(*d.Platform) {
|
||||
descs = append(descs, d)
|
||||
}
|
||||
}
|
||||
|
||||
sort.SliceStable(descs, func(i, j int) bool {
|
||||
if descs[i].Platform == nil {
|
||||
return false
|
||||
}
|
||||
if descs[j].Platform == nil {
|
||||
return true
|
||||
}
|
||||
return platform.Less(*descs[i].Platform, *descs[j].Platform)
|
||||
})
|
||||
|
||||
wasIndex = true
|
||||
|
||||
if len(descs) > limit {
|
||||
return descs[:limit], nil
|
||||
}
|
||||
return descs, nil
|
||||
}
|
||||
return nil, errors.Wrapf(errdefs.ErrNotFound, "unexpected media type %v for %v", desc.MediaType, desc.Digest)
|
||||
}), image); err != nil {
|
||||
return ocispec.Manifest{}, err
|
||||
}
|
||||
|
||||
if len(m) == 0 {
|
||||
err := errors.Wrapf(errdefs.ErrNotFound, "manifest %v", image.Digest)
|
||||
if wasIndex {
|
||||
err = errors.Wrapf(errdefs.ErrNotFound, "no match for platform in manifest %v", image.Digest)
|
||||
}
|
||||
return ocispec.Manifest{}, err
|
||||
}
|
||||
return *m[0].m, nil
|
||||
}
|
||||
|
||||
// Config resolves the image configuration descriptor using a content provided
|
||||
// to resolve child resources on the image.
|
||||
//
|
||||
// The caller can then use the descriptor to resolve and process the
|
||||
// configuration of the image.
|
||||
func Config(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform platforms.MatchComparer) (ocispec.Descriptor, error) {
|
||||
manifest, err := Manifest(ctx, provider, image, platform)
|
||||
if err != nil {
|
||||
return ocispec.Descriptor{}, err
|
||||
}
|
||||
return manifest.Config, err
|
||||
}
|
||||
|
||||
// Platforms returns one or more platforms supported by the image.
|
||||
func Platforms(ctx context.Context, provider content.Provider, image ocispec.Descriptor) ([]ocispec.Platform, error) {
|
||||
var platformSpecs []ocispec.Platform
|
||||
return platformSpecs, Walk(ctx, Handlers(HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
if desc.Platform != nil {
|
||||
platformSpecs = append(platformSpecs, *desc.Platform)
|
||||
return nil, ErrSkipDesc
|
||||
}
|
||||
|
||||
switch desc.MediaType {
|
||||
case MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig:
|
||||
p, err := content.ReadBlob(ctx, provider, desc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var image ocispec.Image
|
||||
if err := json.Unmarshal(p, &image); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
platformSpecs = append(platformSpecs,
|
||||
platforms.Normalize(ocispec.Platform{OS: image.OS, Architecture: image.Architecture}))
|
||||
}
|
||||
return nil, nil
|
||||
}), ChildrenHandler(provider)), image)
|
||||
}
|
||||
|
||||
// Check returns nil if the all components of an image are available in the
|
||||
// provider for the specified platform.
|
||||
//
|
||||
// If available is true, the caller can assume that required represents the
|
||||
// complete set of content required for the image.
|
||||
//
|
||||
// missing will have the components that are part of required but not avaiiable
|
||||
// in the provider.
|
||||
//
|
||||
// If there is a problem resolving content, an error will be returned.
|
||||
func Check(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform platforms.MatchComparer) (available bool, required, present, missing []ocispec.Descriptor, err error) {
|
||||
mfst, err := Manifest(ctx, provider, image, platform)
|
||||
if err != nil {
|
||||
if errdefs.IsNotFound(err) {
|
||||
return false, []ocispec.Descriptor{image}, nil, []ocispec.Descriptor{image}, nil
|
||||
}
|
||||
|
||||
return false, nil, nil, nil, errors.Wrapf(err, "failed to check image %v", image.Digest)
|
||||
}
|
||||
|
||||
// TODO(stevvooe): It is possible that referenced conponents could have
|
||||
// children, but this is rare. For now, we ignore this and only verify
|
||||
// that manifest components are present.
|
||||
required = append([]ocispec.Descriptor{mfst.Config}, mfst.Layers...)
|
||||
|
||||
for _, desc := range required {
|
||||
ra, err := provider.ReaderAt(ctx, desc)
|
||||
if err != nil {
|
||||
if errdefs.IsNotFound(err) {
|
||||
missing = append(missing, desc)
|
||||
continue
|
||||
} else {
|
||||
return false, nil, nil, nil, errors.Wrapf(err, "failed to check image %v", desc.Digest)
|
||||
}
|
||||
}
|
||||
ra.Close()
|
||||
present = append(present, desc)
|
||||
|
||||
}
|
||||
|
||||
return true, required, present, missing, nil
|
||||
}
|
||||
|
||||
// Children returns the immediate children of content described by the descriptor.
|
||||
func Children(ctx context.Context, provider content.Provider, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
var descs []ocispec.Descriptor
|
||||
switch desc.MediaType {
|
||||
case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
|
||||
p, err := content.ReadBlob(ctx, provider, desc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO(stevvooe): We just assume oci manifest, for now. There may be
|
||||
// subtle differences from the docker version.
|
||||
var manifest ocispec.Manifest
|
||||
if err := json.Unmarshal(p, &manifest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
descs = append(descs, manifest.Config)
|
||||
descs = append(descs, manifest.Layers...)
|
||||
case MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
|
||||
p, err := content.ReadBlob(ctx, provider, desc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var index ocispec.Index
|
||||
if err := json.Unmarshal(p, &index); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
descs = append(descs, index.Manifests...)
|
||||
default:
|
||||
if IsLayerType(desc.MediaType) || IsKnownConfig(desc.MediaType) {
|
||||
// childless data types.
|
||||
return nil, nil
|
||||
}
|
||||
log.G(ctx).Warnf("encountered unknown type %v; children may not be fetched", desc.MediaType)
|
||||
}
|
||||
|
||||
return descs, nil
|
||||
}
|
||||
|
||||
// RootFS returns the unpacked diffids that make up and images rootfs.
|
||||
//
|
||||
// These are used to verify that a set of layers unpacked to the expected
|
||||
// values.
|
||||
func RootFS(ctx context.Context, provider content.Provider, configDesc ocispec.Descriptor) ([]digest.Digest, error) {
|
||||
p, err := content.ReadBlob(ctx, provider, configDesc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var config ocispec.Image
|
||||
if err := json.Unmarshal(p, &config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return config.RootFS.DiffIDs, nil
|
||||
}
|
||||
37
vendor/github.com/containerd/containerd/images/importexport.go
generated
vendored
37
vendor/github.com/containerd/containerd/images/importexport.go
generated
vendored
@ -1,37 +0,0 @@
|
||||
/*
|
||||
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 images
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// Importer is the interface for image importer.
|
||||
type Importer interface {
|
||||
// Import imports an image from a tar stream.
|
||||
Import(ctx context.Context, store content.Store, reader io.Reader) (ocispec.Descriptor, error)
|
||||
}
|
||||
|
||||
// Exporter is the interface for image exporter.
|
||||
type Exporter interface {
|
||||
// Export exports an image to a tar stream.
|
||||
Export(ctx context.Context, store content.Provider, desc ocispec.Descriptor, writer io.Writer) error
|
||||
}
|
||||
126
vendor/github.com/containerd/containerd/images/mediatypes.go
generated
vendored
126
vendor/github.com/containerd/containerd/images/mediatypes.go
generated
vendored
@ -1,126 +0,0 @@
|
||||
/*
|
||||
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 images
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// mediatype definitions for image components handled in containerd.
|
||||
//
|
||||
// oci components are generally referenced directly, although we may centralize
|
||||
// here for clarity.
|
||||
const (
|
||||
MediaTypeDockerSchema2Layer = "application/vnd.docker.image.rootfs.diff.tar"
|
||||
MediaTypeDockerSchema2LayerForeign = "application/vnd.docker.image.rootfs.foreign.diff.tar"
|
||||
MediaTypeDockerSchema2LayerGzip = "application/vnd.docker.image.rootfs.diff.tar.gzip"
|
||||
MediaTypeDockerSchema2LayerForeignGzip = "application/vnd.docker.image.rootfs.foreign.diff.tar.gzip"
|
||||
MediaTypeDockerSchema2Config = "application/vnd.docker.container.image.v1+json"
|
||||
MediaTypeDockerSchema2Manifest = "application/vnd.docker.distribution.manifest.v2+json"
|
||||
MediaTypeDockerSchema2ManifestList = "application/vnd.docker.distribution.manifest.list.v2+json"
|
||||
// Checkpoint/Restore Media Types
|
||||
MediaTypeContainerd1Checkpoint = "application/vnd.containerd.container.criu.checkpoint.criu.tar"
|
||||
MediaTypeContainerd1CheckpointPreDump = "application/vnd.containerd.container.criu.checkpoint.predump.tar"
|
||||
MediaTypeContainerd1Resource = "application/vnd.containerd.container.resource.tar"
|
||||
MediaTypeContainerd1RW = "application/vnd.containerd.container.rw.tar"
|
||||
MediaTypeContainerd1CheckpointConfig = "application/vnd.containerd.container.checkpoint.config.v1+proto"
|
||||
MediaTypeContainerd1CheckpointOptions = "application/vnd.containerd.container.checkpoint.options.v1+proto"
|
||||
MediaTypeContainerd1CheckpointRuntimeName = "application/vnd.containerd.container.checkpoint.runtime.name"
|
||||
MediaTypeContainerd1CheckpointRuntimeOptions = "application/vnd.containerd.container.checkpoint.runtime.options+proto"
|
||||
// Legacy Docker schema1 manifest
|
||||
MediaTypeDockerSchema1Manifest = "application/vnd.docker.distribution.manifest.v1+prettyjws"
|
||||
)
|
||||
|
||||
// DiffCompression returns the compression as defined by the layer diff media
|
||||
// type. For Docker media types without compression, "unknown" is returned to
|
||||
// indicate that the media type may be compressed. If the media type is not
|
||||
// recognized as a layer diff, then it returns errdefs.ErrNotImplemented
|
||||
func DiffCompression(ctx context.Context, mediaType string) (string, error) {
|
||||
base, ext := parseMediaTypes(mediaType)
|
||||
switch base {
|
||||
case MediaTypeDockerSchema2Layer, MediaTypeDockerSchema2LayerForeign:
|
||||
if len(ext) > 0 {
|
||||
// Type is wrapped
|
||||
return "", nil
|
||||
}
|
||||
// These media types may have been compressed but failed to
|
||||
// use the correct media type. The decompression function
|
||||
// should detect and handle this case.
|
||||
return "unknown", nil
|
||||
case MediaTypeDockerSchema2LayerGzip, MediaTypeDockerSchema2LayerForeignGzip:
|
||||
if len(ext) > 0 {
|
||||
// Type is wrapped
|
||||
return "", nil
|
||||
}
|
||||
return "gzip", nil
|
||||
case ocispec.MediaTypeImageLayer, ocispec.MediaTypeImageLayerNonDistributable:
|
||||
if len(ext) > 0 {
|
||||
switch ext[len(ext)-1] {
|
||||
case "gzip":
|
||||
return "gzip", nil
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
default:
|
||||
return "", errdefs.ErrNotImplemented
|
||||
}
|
||||
}
|
||||
|
||||
// parseMediaTypes splits the media type into the base type and
|
||||
// an array of sorted extensions
|
||||
func parseMediaTypes(mt string) (string, []string) {
|
||||
if mt == "" {
|
||||
return "", []string{}
|
||||
}
|
||||
|
||||
s := strings.Split(mt, "+")
|
||||
ext := s[1:]
|
||||
sort.Strings(ext)
|
||||
|
||||
return s[0], ext
|
||||
}
|
||||
|
||||
// IsLayerTypes returns true if the media type is a layer
|
||||
func IsLayerType(mt string) bool {
|
||||
if strings.HasPrefix(mt, "application/vnd.oci.image.layer.") {
|
||||
return true
|
||||
}
|
||||
|
||||
// Parse Docker media types, strip off any + suffixes first
|
||||
base, _ := parseMediaTypes(mt)
|
||||
switch base {
|
||||
case MediaTypeDockerSchema2Layer, MediaTypeDockerSchema2LayerGzip,
|
||||
MediaTypeDockerSchema2LayerForeign, MediaTypeDockerSchema2LayerForeignGzip:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsKnownConfig returns true if the media type is a known config type
|
||||
func IsKnownConfig(mt string) bool {
|
||||
switch mt {
|
||||
case MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig,
|
||||
MediaTypeContainerd1Checkpoint, MediaTypeContainerd1CheckpointConfig:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
53
vendor/github.com/containerd/containerd/mount/lookup_unix.go
generated
vendored
53
vendor/github.com/containerd/containerd/mount/lookup_unix.go
generated
vendored
@ -1,53 +0,0 @@
|
||||
// +build !windows
|
||||
|
||||
/*
|
||||
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 mount
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Lookup returns the mount info corresponds to the path.
|
||||
func Lookup(dir string) (Info, error) {
|
||||
dir = filepath.Clean(dir)
|
||||
|
||||
mounts, err := Self()
|
||||
if err != nil {
|
||||
return Info{}, err
|
||||
}
|
||||
|
||||
// Sort descending order by Info.Mountpoint
|
||||
sort.SliceStable(mounts, func(i, j int) bool {
|
||||
return mounts[j].Mountpoint < mounts[i].Mountpoint
|
||||
})
|
||||
for _, m := range mounts {
|
||||
// Note that m.{Major, Minor} are generally unreliable for our purpose here
|
||||
// https://www.spinics.net/lists/linux-btrfs/msg58908.html
|
||||
// Note that device number is not checked here, because for overlayfs files
|
||||
// may have different device number with the mountpoint.
|
||||
if strings.HasPrefix(dir, m.Mountpoint) {
|
||||
return m, nil
|
||||
}
|
||||
}
|
||||
|
||||
return Info{}, errors.Errorf("failed to find the mount info for %q", dir)
|
||||
}
|
||||
29
vendor/github.com/containerd/containerd/mount/lookup_unsupported.go
generated
vendored
29
vendor/github.com/containerd/containerd/mount/lookup_unsupported.go
generated
vendored
@ -1,29 +0,0 @@
|
||||
// +build windows
|
||||
|
||||
/*
|
||||
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 mount
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Lookup returns the mount info corresponds to the path.
|
||||
func Lookup(dir string) (Info, error) {
|
||||
return Info{}, fmt.Errorf("mount.Lookup is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
40
vendor/github.com/containerd/containerd/mount/mount.go
generated
vendored
40
vendor/github.com/containerd/containerd/mount/mount.go
generated
vendored
@ -1,40 +0,0 @@
|
||||
/*
|
||||
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 mount
|
||||
|
||||
// Mount is the lingua franca of containerd. A mount represents a
|
||||
// serialized mount syscall. Components either emit or consume mounts.
|
||||
type Mount struct {
|
||||
// Type specifies the host-specific of the mount.
|
||||
Type string
|
||||
// Source specifies where to mount from. Depending on the host system, this
|
||||
// can be a source path or device.
|
||||
Source string
|
||||
// Options contains zero or more fstab-style mount options. Typically,
|
||||
// these are platform specific.
|
||||
Options []string
|
||||
}
|
||||
|
||||
// All mounts all the provided mounts to the provided target
|
||||
func All(mounts []Mount, target string) error {
|
||||
for _, m := range mounts {
|
||||
if err := m.Mount(target); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
319
vendor/github.com/containerd/containerd/mount/mount_linux.go
generated
vendored
319
vendor/github.com/containerd/containerd/mount/mount_linux.go
generated
vendored
@ -1,319 +0,0 @@
|
||||
/*
|
||||
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 mount
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/sys"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var pagesize = 4096
|
||||
|
||||
func init() {
|
||||
pagesize = os.Getpagesize()
|
||||
}
|
||||
|
||||
// Mount to the provided target path
|
||||
func (m *Mount) Mount(target string) error {
|
||||
var (
|
||||
chdir string
|
||||
options = m.Options
|
||||
)
|
||||
|
||||
// avoid hitting one page limit of mount argument buffer
|
||||
//
|
||||
// NOTE: 512 is a buffer during pagesize check.
|
||||
if m.Type == "overlay" && optionsSize(options) >= pagesize-512 {
|
||||
chdir, options = compactLowerdirOption(options)
|
||||
}
|
||||
|
||||
flags, data := parseMountOptions(options)
|
||||
if len(data) > pagesize {
|
||||
return errors.Errorf("mount options is too long")
|
||||
}
|
||||
|
||||
// propagation types.
|
||||
const ptypes = unix.MS_SHARED | unix.MS_PRIVATE | unix.MS_SLAVE | unix.MS_UNBINDABLE
|
||||
|
||||
// Ensure propagation type change flags aren't included in other calls.
|
||||
oflags := flags &^ ptypes
|
||||
|
||||
// In the case of remounting with changed data (data != ""), need to call mount (moby/moby#34077).
|
||||
if flags&unix.MS_REMOUNT == 0 || data != "" {
|
||||
// Initial call applying all non-propagation flags for mount
|
||||
// or remount with changed data
|
||||
if err := mountAt(chdir, m.Source, target, m.Type, uintptr(oflags), data); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if flags&ptypes != 0 {
|
||||
// Change the propagation type.
|
||||
const pflags = ptypes | unix.MS_REC | unix.MS_SILENT
|
||||
if err := unix.Mount("", target, "", uintptr(flags&pflags), ""); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
const broflags = unix.MS_BIND | unix.MS_RDONLY
|
||||
if oflags&broflags == broflags {
|
||||
// Remount the bind to apply read only.
|
||||
return unix.Mount("", target, "", uintptr(oflags|unix.MS_REMOUNT), "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unmount the provided mount path with the flags
|
||||
func Unmount(target string, flags int) error {
|
||||
if err := unmount(target, flags); err != nil && err != unix.EINVAL {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func unmount(target string, flags int) error {
|
||||
for i := 0; i < 50; i++ {
|
||||
if err := unix.Unmount(target, flags); err != nil {
|
||||
switch err {
|
||||
case unix.EBUSY:
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
continue
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return errors.Wrapf(unix.EBUSY, "failed to unmount target %s", target)
|
||||
}
|
||||
|
||||
// UnmountAll repeatedly unmounts the given mount point until there
|
||||
// are no mounts remaining (EINVAL is returned by mount), which is
|
||||
// useful for undoing a stack of mounts on the same mount point.
|
||||
// UnmountAll all is noop when the first argument is an empty string.
|
||||
// This is done when the containerd client did not specify any rootfs
|
||||
// mounts (e.g. because the rootfs is managed outside containerd)
|
||||
// UnmountAll is noop when the mount path does not exist.
|
||||
func UnmountAll(mount string, flags int) error {
|
||||
if mount == "" {
|
||||
return nil
|
||||
}
|
||||
if _, err := os.Stat(mount); os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
for {
|
||||
if err := unmount(mount, flags); err != nil {
|
||||
// EINVAL is returned if the target is not a
|
||||
// mount point, indicating that we are
|
||||
// done. It can also indicate a few other
|
||||
// things (such as invalid flags) which we
|
||||
// unfortunately end up squelching here too.
|
||||
if err == unix.EINVAL {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parseMountOptions takes fstab style mount options and parses them for
|
||||
// use with a standard mount() syscall
|
||||
func parseMountOptions(options []string) (int, string) {
|
||||
var (
|
||||
flag int
|
||||
data []string
|
||||
)
|
||||
flags := map[string]struct {
|
||||
clear bool
|
||||
flag int
|
||||
}{
|
||||
"async": {true, unix.MS_SYNCHRONOUS},
|
||||
"atime": {true, unix.MS_NOATIME},
|
||||
"bind": {false, unix.MS_BIND},
|
||||
"defaults": {false, 0},
|
||||
"dev": {true, unix.MS_NODEV},
|
||||
"diratime": {true, unix.MS_NODIRATIME},
|
||||
"dirsync": {false, unix.MS_DIRSYNC},
|
||||
"exec": {true, unix.MS_NOEXEC},
|
||||
"mand": {false, unix.MS_MANDLOCK},
|
||||
"noatime": {false, unix.MS_NOATIME},
|
||||
"nodev": {false, unix.MS_NODEV},
|
||||
"nodiratime": {false, unix.MS_NODIRATIME},
|
||||
"noexec": {false, unix.MS_NOEXEC},
|
||||
"nomand": {true, unix.MS_MANDLOCK},
|
||||
"norelatime": {true, unix.MS_RELATIME},
|
||||
"nostrictatime": {true, unix.MS_STRICTATIME},
|
||||
"nosuid": {false, unix.MS_NOSUID},
|
||||
"rbind": {false, unix.MS_BIND | unix.MS_REC},
|
||||
"relatime": {false, unix.MS_RELATIME},
|
||||
"remount": {false, unix.MS_REMOUNT},
|
||||
"ro": {false, unix.MS_RDONLY},
|
||||
"rw": {true, unix.MS_RDONLY},
|
||||
"strictatime": {false, unix.MS_STRICTATIME},
|
||||
"suid": {true, unix.MS_NOSUID},
|
||||
"sync": {false, unix.MS_SYNCHRONOUS},
|
||||
}
|
||||
for _, o := range options {
|
||||
// If the option does not exist in the flags table or the flag
|
||||
// is not supported on the platform,
|
||||
// then it is a data value for a specific fs type
|
||||
if f, exists := flags[o]; exists && f.flag != 0 {
|
||||
if f.clear {
|
||||
flag &^= f.flag
|
||||
} else {
|
||||
flag |= f.flag
|
||||
}
|
||||
} else {
|
||||
data = append(data, o)
|
||||
}
|
||||
}
|
||||
return flag, strings.Join(data, ",")
|
||||
}
|
||||
|
||||
// compactLowerdirOption updates overlay lowdir option and returns the common
|
||||
// dir among all the lowdirs.
|
||||
func compactLowerdirOption(opts []string) (string, []string) {
|
||||
idx, dirs := findOverlayLowerdirs(opts)
|
||||
if idx == -1 || len(dirs) == 1 {
|
||||
// no need to compact if there is only one lowerdir
|
||||
return "", opts
|
||||
}
|
||||
|
||||
// find out common dir
|
||||
commondir := longestCommonPrefix(dirs)
|
||||
if commondir == "" {
|
||||
return "", opts
|
||||
}
|
||||
|
||||
// NOTE: the snapshot id is based on digits.
|
||||
// in order to avoid to get snapshots/x, should be back to parent dir.
|
||||
// however, there is assumption that the common dir is ${root}/io.containerd.v1.overlayfs/snapshots.
|
||||
commondir = path.Dir(commondir)
|
||||
if commondir == "/" {
|
||||
return "", opts
|
||||
}
|
||||
commondir = commondir + "/"
|
||||
|
||||
newdirs := make([]string, 0, len(dirs))
|
||||
for _, dir := range dirs {
|
||||
newdirs = append(newdirs, dir[len(commondir):])
|
||||
}
|
||||
|
||||
newopts := copyOptions(opts)
|
||||
newopts = append(newopts[:idx], newopts[idx+1:]...)
|
||||
newopts = append(newopts, fmt.Sprintf("lowerdir=%s", strings.Join(newdirs, ":")))
|
||||
return commondir, newopts
|
||||
}
|
||||
|
||||
// findOverlayLowerdirs returns the index of lowerdir in mount's options and
|
||||
// all the lowerdir target.
|
||||
func findOverlayLowerdirs(opts []string) (int, []string) {
|
||||
var (
|
||||
idx = -1
|
||||
prefix = "lowerdir="
|
||||
)
|
||||
|
||||
for i, opt := range opts {
|
||||
if strings.HasPrefix(opt, prefix) {
|
||||
idx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if idx == -1 {
|
||||
return -1, nil
|
||||
}
|
||||
return idx, strings.Split(opts[idx][len(prefix):], ":")
|
||||
}
|
||||
|
||||
// longestCommonPrefix finds the longest common prefix in the string slice.
|
||||
func longestCommonPrefix(strs []string) string {
|
||||
if len(strs) == 0 {
|
||||
return ""
|
||||
} else if len(strs) == 1 {
|
||||
return strs[0]
|
||||
}
|
||||
|
||||
// find out the min/max value by alphabetical order
|
||||
min, max := strs[0], strs[0]
|
||||
for _, str := range strs[1:] {
|
||||
if min > str {
|
||||
min = str
|
||||
}
|
||||
if max < str {
|
||||
max = str
|
||||
}
|
||||
}
|
||||
|
||||
// find out the common part between min and max
|
||||
for i := 0; i < len(min) && i < len(max); i++ {
|
||||
if min[i] != max[i] {
|
||||
return min[:i]
|
||||
}
|
||||
}
|
||||
return min
|
||||
}
|
||||
|
||||
// copyOptions copies the options.
|
||||
func copyOptions(opts []string) []string {
|
||||
if len(opts) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
acopy := make([]string, len(opts))
|
||||
copy(acopy, opts)
|
||||
return acopy
|
||||
}
|
||||
|
||||
// optionsSize returns the byte size of options of mount.
|
||||
func optionsSize(opts []string) int {
|
||||
size := 0
|
||||
for _, opt := range opts {
|
||||
size += len(opt)
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
func mountAt(chdir string, source, target, fstype string, flags uintptr, data string) error {
|
||||
if chdir == "" {
|
||||
return unix.Mount(source, target, fstype, flags, data)
|
||||
}
|
||||
|
||||
f, err := os.Open(chdir)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to mountat")
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fs, err := f.Stat()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to mountat")
|
||||
}
|
||||
|
||||
if !fs.IsDir() {
|
||||
return errors.Wrap(errors.Errorf("%s is not dir", chdir), "failed to mountat")
|
||||
}
|
||||
return errors.Wrap(sys.FMountat(f.Fd(), source, target, fstype, flags, data), "failed to mountat")
|
||||
}
|
||||
41
vendor/github.com/containerd/containerd/mount/mount_unix.go
generated
vendored
41
vendor/github.com/containerd/containerd/mount/mount_unix.go
generated
vendored
@ -1,41 +0,0 @@
|
||||
// +build darwin freebsd openbsd
|
||||
|
||||
/*
|
||||
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 mount
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
|
||||
var (
|
||||
// ErrNotImplementOnUnix is returned for methods that are not implemented
|
||||
ErrNotImplementOnUnix = errors.New("not implemented under unix")
|
||||
)
|
||||
|
||||
// Mount is not implemented on this platform
|
||||
func (m *Mount) Mount(target string) error {
|
||||
return ErrNotImplementOnUnix
|
||||
}
|
||||
|
||||
// Unmount is not implemented on this platform
|
||||
func Unmount(mount string, flags int) error {
|
||||
return ErrNotImplementOnUnix
|
||||
}
|
||||
|
||||
// UnmountAll is not implemented on this platform
|
||||
func UnmountAll(mount string, flags int) error {
|
||||
return ErrNotImplementOnUnix
|
||||
}
|
||||
105
vendor/github.com/containerd/containerd/mount/mount_windows.go
generated
vendored
105
vendor/github.com/containerd/containerd/mount/mount_windows.go
generated
vendored
@ -1,105 +0,0 @@
|
||||
/*
|
||||
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 mount
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/Microsoft/hcsshim"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotImplementOnWindows is returned when an action is not implemented for windows
|
||||
ErrNotImplementOnWindows = errors.New("not implemented under windows")
|
||||
)
|
||||
|
||||
// Mount to the provided target
|
||||
func (m *Mount) Mount(target string) error {
|
||||
if m.Type != "windows-layer" {
|
||||
return errors.Errorf("invalid windows mount type: '%s'", m.Type)
|
||||
}
|
||||
|
||||
home, layerID := filepath.Split(m.Source)
|
||||
|
||||
parentLayerPaths, err := m.GetParentPaths()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var di = hcsshim.DriverInfo{
|
||||
HomeDir: home,
|
||||
}
|
||||
|
||||
if err = hcsshim.ActivateLayer(di, layerID); err != nil {
|
||||
return errors.Wrapf(err, "failed to activate layer %s", m.Source)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
hcsshim.DeactivateLayer(di, layerID)
|
||||
}
|
||||
}()
|
||||
|
||||
if err = hcsshim.PrepareLayer(di, layerID, parentLayerPaths); err != nil {
|
||||
return errors.Wrapf(err, "failed to prepare layer %s", m.Source)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParentLayerPathsFlag is the options flag used to represent the JSON encoded
|
||||
// list of parent layers required to use the layer
|
||||
const ParentLayerPathsFlag = "parentLayerPaths="
|
||||
|
||||
// GetParentPaths of the mount
|
||||
func (m *Mount) GetParentPaths() ([]string, error) {
|
||||
var parentLayerPaths []string
|
||||
for _, option := range m.Options {
|
||||
if strings.HasPrefix(option, ParentLayerPathsFlag) {
|
||||
err := json.Unmarshal([]byte(option[len(ParentLayerPathsFlag):]), &parentLayerPaths)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unmarshal parent layer paths from mount")
|
||||
}
|
||||
}
|
||||
}
|
||||
return parentLayerPaths, nil
|
||||
}
|
||||
|
||||
// Unmount the mount at the provided path
|
||||
func Unmount(mount string, flags int) error {
|
||||
var (
|
||||
home, layerID = filepath.Split(mount)
|
||||
di = hcsshim.DriverInfo{
|
||||
HomeDir: home,
|
||||
}
|
||||
)
|
||||
|
||||
if err := hcsshim.UnprepareLayer(di, layerID); err != nil {
|
||||
return errors.Wrapf(err, "failed to unprepare layer %s", mount)
|
||||
}
|
||||
if err := hcsshim.DeactivateLayer(di, layerID); err != nil {
|
||||
return errors.Wrapf(err, "failed to deactivate layer %s", mount)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmountAll unmounts from the provided path
|
||||
func UnmountAll(mount string, flags int) error {
|
||||
return Unmount(mount, flags)
|
||||
}
|
||||
56
vendor/github.com/containerd/containerd/mount/mountinfo.go
generated
vendored
56
vendor/github.com/containerd/containerd/mount/mountinfo.go
generated
vendored
@ -1,56 +0,0 @@
|
||||
/*
|
||||
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 mount
|
||||
|
||||
// Info reveals information about a particular mounted filesystem. This
|
||||
// struct is populated from the content in the /proc/<pid>/mountinfo file.
|
||||
type Info struct {
|
||||
// ID is a unique identifier of the mount (may be reused after umount).
|
||||
ID int
|
||||
|
||||
// Parent indicates the ID of the mount parent (or of self for the top of the
|
||||
// mount tree).
|
||||
Parent int
|
||||
|
||||
// Major indicates one half of the device ID which identifies the device class.
|
||||
Major int
|
||||
|
||||
// Minor indicates one half of the device ID which identifies a specific
|
||||
// instance of device.
|
||||
Minor int
|
||||
|
||||
// Root of the mount within the filesystem.
|
||||
Root string
|
||||
|
||||
// Mountpoint indicates the mount point relative to the process's root.
|
||||
Mountpoint string
|
||||
|
||||
// Options represents mount-specific options.
|
||||
Options string
|
||||
|
||||
// Optional represents optional fields.
|
||||
Optional string
|
||||
|
||||
// FSType indicates the type of filesystem, such as EXT3.
|
||||
FSType string
|
||||
|
||||
// Source indicates filesystem specific information or "none".
|
||||
Source string
|
||||
|
||||
// VFSOptions represents per super block options.
|
||||
VFSOptions string
|
||||
}
|
||||
63
vendor/github.com/containerd/containerd/mount/mountinfo_bsd.go
generated
vendored
63
vendor/github.com/containerd/containerd/mount/mountinfo_bsd.go
generated
vendored
@ -1,63 +0,0 @@
|
||||
// +build freebsd openbsd
|
||||
|
||||
/*
|
||||
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 mount
|
||||
|
||||
/*
|
||||
#include <sys/param.h>
|
||||
#include <sys/ucred.h>
|
||||
#include <sys/mount.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Self retrieves a list of mounts for the current running process.
|
||||
func Self() ([]Info, error) {
|
||||
var rawEntries *C.struct_statfs
|
||||
|
||||
count := int(C.getmntinfo(&rawEntries, C.MNT_WAIT))
|
||||
if count == 0 {
|
||||
return nil, fmt.Errorf("Failed to call getmntinfo")
|
||||
}
|
||||
|
||||
var entries []C.struct_statfs
|
||||
header := (*reflect.SliceHeader)(unsafe.Pointer(&entries))
|
||||
header.Cap = count
|
||||
header.Len = count
|
||||
header.Data = uintptr(unsafe.Pointer(rawEntries))
|
||||
|
||||
var out []Info
|
||||
for _, entry := range entries {
|
||||
var mountinfo Info
|
||||
mountinfo.Mountpoint = C.GoString(&entry.f_mntonname[0])
|
||||
mountinfo.Source = C.GoString(&entry.f_mntfromname[0])
|
||||
mountinfo.FSType = C.GoString(&entry.f_fstypename[0])
|
||||
out = append(out, mountinfo)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// PID collects the mounts for a specific process ID.
|
||||
func PID(pid int) ([]Info, error) {
|
||||
return nil, fmt.Errorf("mountinfo.PID is not implemented on freebsd")
|
||||
}
|
||||
145
vendor/github.com/containerd/containerd/mount/mountinfo_linux.go
generated
vendored
145
vendor/github.com/containerd/containerd/mount/mountinfo_linux.go
generated
vendored
@ -1,145 +0,0 @@
|
||||
// +build linux
|
||||
|
||||
/*
|
||||
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 mount
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Self retrieves a list of mounts for the current running process.
|
||||
func Self() ([]Info, error) {
|
||||
f, err := os.Open("/proc/self/mountinfo")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return parseInfoFile(f)
|
||||
}
|
||||
|
||||
func parseInfoFile(r io.Reader) ([]Info, error) {
|
||||
s := bufio.NewScanner(r)
|
||||
out := []Info{}
|
||||
var err error
|
||||
for s.Scan() {
|
||||
if err = s.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
/*
|
||||
See http://man7.org/linux/man-pages/man5/proc.5.html
|
||||
|
||||
36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
|
||||
(1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
|
||||
(1) mount ID: unique identifier of the mount (may be reused after umount)
|
||||
(2) parent ID: ID of parent (or of self for the top of the mount tree)
|
||||
(3) major:minor: value of st_dev for files on filesystem
|
||||
(4) root: root of the mount within the filesystem
|
||||
(5) mount point: mount point relative to the process's root
|
||||
(6) mount options: per mount options
|
||||
(7) optional fields: zero or more fields of the form "tag[:value]"
|
||||
(8) separator: marks the end of the optional fields
|
||||
(9) filesystem type: name of filesystem of the form "type[.subtype]"
|
||||
(10) mount source: filesystem specific information or "none"
|
||||
(11) super options: per super block options
|
||||
*/
|
||||
|
||||
text := s.Text()
|
||||
fields := strings.Split(text, " ")
|
||||
numFields := len(fields)
|
||||
if numFields < 10 {
|
||||
// should be at least 10 fields
|
||||
return nil, errors.Errorf("parsing '%s' failed: not enough fields (%d)", text, numFields)
|
||||
}
|
||||
p := Info{}
|
||||
// ignore any numbers parsing errors, as there should not be any
|
||||
p.ID, _ = strconv.Atoi(fields[0])
|
||||
p.Parent, _ = strconv.Atoi(fields[1])
|
||||
mm := strings.Split(fields[2], ":")
|
||||
if len(mm) != 2 {
|
||||
return nil, errors.Errorf("parsing '%s' failed: unexpected minor:major pair %s", text, mm)
|
||||
}
|
||||
p.Major, _ = strconv.Atoi(mm[0])
|
||||
p.Minor, _ = strconv.Atoi(mm[1])
|
||||
|
||||
p.Root, err = strconv.Unquote(`"` + fields[3] + `"`)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "parsing '%s' failed: unable to unquote root field", fields[3])
|
||||
}
|
||||
p.Mountpoint, err = strconv.Unquote(`"` + fields[4] + `"`)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "parsing '%s' failed: unable to unquote mount point field", fields[4])
|
||||
}
|
||||
p.Options = fields[5]
|
||||
|
||||
// one or more optional fields, when a separator (-)
|
||||
i := 6
|
||||
for ; i < numFields && fields[i] != "-"; i++ {
|
||||
switch i {
|
||||
case 6:
|
||||
p.Optional = fields[6]
|
||||
default:
|
||||
/* NOTE there might be more optional fields before the separator
|
||||
such as fields[7]...fields[N] (where N < separatorIndex),
|
||||
although as of Linux kernel 4.15 the only known ones are
|
||||
mount propagation flags in fields[6]. The correct
|
||||
behavior is to ignore any unknown optional fields.
|
||||
*/
|
||||
}
|
||||
}
|
||||
if i == numFields {
|
||||
return nil, errors.Errorf("parsing '%s' failed: missing separator ('-')", text)
|
||||
}
|
||||
// There should be 3 fields after the separator...
|
||||
if i+4 > numFields {
|
||||
return nil, errors.Errorf("parsing '%s' failed: not enough fields after a separator", text)
|
||||
}
|
||||
// ... but in Linux <= 3.9 mounting a cifs with spaces in a share name
|
||||
// (like "//serv/My Documents") _may_ end up having a space in the last field
|
||||
// of mountinfo (like "unc=//serv/My Documents"). Since kernel 3.10-rc1, cifs
|
||||
// option unc= is ignored, so a space should not appear. In here we ignore
|
||||
// those "extra" fields caused by extra spaces.
|
||||
p.FSType = fields[i+1]
|
||||
p.Source = fields[i+2]
|
||||
p.VFSOptions = fields[i+3]
|
||||
|
||||
out = append(out, p)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// PID collects the mounts for a specific process ID. If the process
|
||||
// ID is unknown, it is better to use `Self` which will inspect
|
||||
// "/proc/self/mountinfo" instead.
|
||||
func PID(pid int) ([]Info, error) {
|
||||
f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return parseInfoFile(f)
|
||||
}
|
||||
34
vendor/github.com/containerd/containerd/mount/mountinfo_unsupported.go
generated
vendored
34
vendor/github.com/containerd/containerd/mount/mountinfo_unsupported.go
generated
vendored
@ -1,34 +0,0 @@
|
||||
// +build !linux,!freebsd,!solaris,!openbsd freebsd,!cgo solaris,!cgo openbsd,!cgo
|
||||
|
||||
/*
|
||||
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 mount
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Self retrieves a list of mounts for the current running process.
|
||||
func Self() ([]Info, error) {
|
||||
return nil, fmt.Errorf("mountinfo.Self is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
// PID collects the mounts for a specific process ID.
|
||||
func PID(pid int) ([]Info, error) {
|
||||
return nil, fmt.Errorf("mountinfo.PID is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
73
vendor/github.com/containerd/containerd/mount/temp.go
generated
vendored
73
vendor/github.com/containerd/containerd/mount/temp.go
generated
vendored
@ -1,73 +0,0 @@
|
||||
/*
|
||||
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 mount
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var tempMountLocation = getTempDir()
|
||||
|
||||
// WithTempMount mounts the provided mounts to a temp dir, and pass the temp dir to f.
|
||||
// The mounts are valid during the call to the f.
|
||||
// Finally we will unmount and remove the temp dir regardless of the result of f.
|
||||
func WithTempMount(ctx context.Context, mounts []Mount, f func(root string) error) (err error) {
|
||||
root, uerr := ioutil.TempDir(tempMountLocation, "containerd-mount")
|
||||
if uerr != nil {
|
||||
return errors.Wrapf(uerr, "failed to create temp dir")
|
||||
}
|
||||
// We use Remove here instead of RemoveAll.
|
||||
// The RemoveAll will delete the temp dir and all children it contains.
|
||||
// When the Unmount fails, RemoveAll will incorrectly delete data from
|
||||
// the mounted dir. However, if we use Remove, even though we won't
|
||||
// successfully delete the temp dir and it may leak, we won't loss data
|
||||
// from the mounted dir.
|
||||
// For details, please refer to #1868 #1785.
|
||||
defer func() {
|
||||
if uerr = os.Remove(root); uerr != nil {
|
||||
log.G(ctx).WithError(uerr).WithField("dir", root).Errorf("failed to remove mount temp dir")
|
||||
}
|
||||
}()
|
||||
|
||||
// We should do defer first, if not we will not do Unmount when only a part of Mounts are failed.
|
||||
defer func() {
|
||||
if uerr = UnmountAll(root, 0); uerr != nil {
|
||||
uerr = errors.Wrapf(uerr, "failed to unmount %s", root)
|
||||
if err == nil {
|
||||
err = uerr
|
||||
} else {
|
||||
err = errors.Wrap(err, uerr.Error())
|
||||
}
|
||||
}
|
||||
}()
|
||||
if uerr = All(mounts, root); uerr != nil {
|
||||
return errors.Wrapf(uerr, "failed to mount %s", root)
|
||||
}
|
||||
return errors.Wrapf(f(root), "mount callback failed on %s", root)
|
||||
}
|
||||
|
||||
func getTempDir() string {
|
||||
if xdg := os.Getenv("XDG_RUNTIME_DIR"); xdg != "" {
|
||||
return xdg
|
||||
}
|
||||
return os.TempDir()
|
||||
}
|
||||
64
vendor/github.com/containerd/containerd/mount/temp_unix.go
generated
vendored
64
vendor/github.com/containerd/containerd/mount/temp_unix.go
generated
vendored
@ -1,64 +0,0 @@
|
||||
// +build !windows
|
||||
|
||||
/*
|
||||
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 mount
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SetTempMountLocation sets the temporary mount location
|
||||
func SetTempMountLocation(root string) error {
|
||||
root, err := filepath.Abs(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(root, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
tempMountLocation = root
|
||||
return nil
|
||||
}
|
||||
|
||||
// CleanupTempMounts all temp mounts and remove the directories
|
||||
func CleanupTempMounts(flags int) (warnings []error, err error) {
|
||||
mounts, err := Self()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var toUnmount []string
|
||||
for _, m := range mounts {
|
||||
if strings.HasPrefix(m.Mountpoint, tempMountLocation) {
|
||||
toUnmount = append(toUnmount, m.Mountpoint)
|
||||
}
|
||||
}
|
||||
sort.Sort(sort.Reverse(sort.StringSlice(toUnmount)))
|
||||
for _, path := range toUnmount {
|
||||
if err := UnmountAll(path, flags); err != nil {
|
||||
warnings = append(warnings, err)
|
||||
continue
|
||||
}
|
||||
if err := os.Remove(path); err != nil {
|
||||
warnings = append(warnings, err)
|
||||
}
|
||||
}
|
||||
return warnings, nil
|
||||
}
|
||||
29
vendor/github.com/containerd/containerd/mount/temp_unsupported.go
generated
vendored
29
vendor/github.com/containerd/containerd/mount/temp_unsupported.go
generated
vendored
@ -1,29 +0,0 @@
|
||||
// +build windows
|
||||
|
||||
/*
|
||||
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 mount
|
||||
|
||||
// SetTempMountLocation sets the temporary mount location
|
||||
func SetTempMountLocation(root string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CleanupTempMounts all temp mounts and remove the directories
|
||||
func CleanupTempMounts(flags int) ([]error, error) {
|
||||
return nil, nil
|
||||
}
|
||||
77
vendor/github.com/containerd/containerd/namespaces/context.go
generated
vendored
77
vendor/github.com/containerd/containerd/namespaces/context.go
generated
vendored
@ -1,77 +0,0 @@
|
||||
/*
|
||||
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 namespaces
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// NamespaceEnvVar is the environment variable key name
|
||||
NamespaceEnvVar = "CONTAINERD_NAMESPACE"
|
||||
// Default is the name of the default namespace
|
||||
Default = "default"
|
||||
)
|
||||
|
||||
type namespaceKey struct{}
|
||||
|
||||
// WithNamespace sets a given namespace on the context
|
||||
func WithNamespace(ctx context.Context, namespace string) context.Context {
|
||||
ctx = context.WithValue(ctx, namespaceKey{}, namespace) // set our key for namespace
|
||||
// also store on the grpc and ttrpc headers so it gets picked up by any clients that
|
||||
// are using this.
|
||||
return withTTRPCNamespaceHeader(withGRPCNamespaceHeader(ctx, namespace), namespace)
|
||||
}
|
||||
|
||||
// NamespaceFromEnv uses the namespace defined in CONTAINERD_NAMESPACE or
|
||||
// default
|
||||
func NamespaceFromEnv(ctx context.Context) context.Context {
|
||||
namespace := os.Getenv(NamespaceEnvVar)
|
||||
if namespace == "" {
|
||||
namespace = Default
|
||||
}
|
||||
return WithNamespace(ctx, namespace)
|
||||
}
|
||||
|
||||
// Namespace returns the namespace from the context.
|
||||
//
|
||||
// The namespace is not guaranteed to be valid.
|
||||
func Namespace(ctx context.Context) (string, bool) {
|
||||
namespace, ok := ctx.Value(namespaceKey{}).(string)
|
||||
if !ok {
|
||||
if namespace, ok = fromGRPCHeader(ctx); !ok {
|
||||
return fromTTRPCHeader(ctx)
|
||||
}
|
||||
}
|
||||
return namespace, ok
|
||||
}
|
||||
|
||||
// NamespaceRequired returns the valid namespace from the context or an error.
|
||||
func NamespaceRequired(ctx context.Context) (string, error) {
|
||||
namespace, ok := Namespace(ctx)
|
||||
if !ok || namespace == "" {
|
||||
return "", errors.Wrapf(errdefs.ErrFailedPrecondition, "namespace is required")
|
||||
}
|
||||
if err := Validate(namespace); err != nil {
|
||||
return "", errors.Wrap(err, "namespace validation")
|
||||
}
|
||||
return namespace, nil
|
||||
}
|
||||
61
vendor/github.com/containerd/containerd/namespaces/grpc.go
generated
vendored
61
vendor/github.com/containerd/containerd/namespaces/grpc.go
generated
vendored
@ -1,61 +0,0 @@
|
||||
/*
|
||||
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 namespaces
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
const (
|
||||
// GRPCHeader defines the header name for specifying a containerd namespace.
|
||||
GRPCHeader = "containerd-namespace"
|
||||
)
|
||||
|
||||
// NOTE(stevvooe): We can stub this file out if we don't want a grpc dependency here.
|
||||
|
||||
func withGRPCNamespaceHeader(ctx context.Context, namespace string) context.Context {
|
||||
// also store on the grpc headers so it gets picked up by any clients that
|
||||
// are using this.
|
||||
nsheader := metadata.Pairs(GRPCHeader, namespace)
|
||||
md, ok := metadata.FromOutgoingContext(ctx) // merge with outgoing context.
|
||||
if !ok {
|
||||
md = nsheader
|
||||
} else {
|
||||
// order ensures the latest is first in this list.
|
||||
md = metadata.Join(nsheader, md)
|
||||
}
|
||||
|
||||
return metadata.NewOutgoingContext(ctx, md)
|
||||
}
|
||||
|
||||
func fromGRPCHeader(ctx context.Context) (string, bool) {
|
||||
// try to extract for use in grpc servers.
|
||||
md, ok := metadata.FromIncomingContext(ctx)
|
||||
if !ok {
|
||||
// TODO(stevvooe): Check outgoing context?
|
||||
return "", false
|
||||
}
|
||||
|
||||
values := md[GRPCHeader]
|
||||
if len(values) == 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
return values[0], true
|
||||
}
|
||||
46
vendor/github.com/containerd/containerd/namespaces/store.go
generated
vendored
46
vendor/github.com/containerd/containerd/namespaces/store.go
generated
vendored
@ -1,46 +0,0 @@
|
||||
/*
|
||||
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 namespaces
|
||||
|
||||
import "context"
|
||||
|
||||
// Store provides introspection about namespaces.
|
||||
//
|
||||
// Note that these are slightly different than other objects, which are record
|
||||
// oriented. A namespace is really just a name and a set of labels. Objects
|
||||
// that belong to a namespace are returned when the namespace is assigned to a
|
||||
// given context.
|
||||
//
|
||||
//
|
||||
type Store interface {
|
||||
Create(ctx context.Context, namespace string, labels map[string]string) error
|
||||
Labels(ctx context.Context, namespace string) (map[string]string, error)
|
||||
SetLabel(ctx context.Context, namespace, key, value string) error
|
||||
List(ctx context.Context) ([]string, error)
|
||||
|
||||
// Delete removes the namespace. The namespace must be empty to be deleted.
|
||||
Delete(ctx context.Context, namespace string, opts ...DeleteOpts) error
|
||||
}
|
||||
|
||||
// DeleteInfo specifies information for the deletion of a namespace
|
||||
type DeleteInfo struct {
|
||||
// Name of the namespace
|
||||
Name string
|
||||
}
|
||||
|
||||
// DeleteOpts allows the caller to set options for namespace deletion
|
||||
type DeleteOpts func(context.Context, *DeleteInfo) error
|
||||
51
vendor/github.com/containerd/containerd/namespaces/ttrpc.go
generated
vendored
51
vendor/github.com/containerd/containerd/namespaces/ttrpc.go
generated
vendored
@ -1,51 +0,0 @@
|
||||
/*
|
||||
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 namespaces
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containerd/ttrpc"
|
||||
)
|
||||
|
||||
const (
|
||||
// TTRPCHeader defines the header name for specifying a containerd namespace
|
||||
TTRPCHeader = "containerd-namespace-ttrpc"
|
||||
)
|
||||
|
||||
func copyMetadata(src ttrpc.MD) ttrpc.MD {
|
||||
md := ttrpc.MD{}
|
||||
for k, v := range src {
|
||||
md[k] = append(md[k], v...)
|
||||
}
|
||||
return md
|
||||
}
|
||||
|
||||
func withTTRPCNamespaceHeader(ctx context.Context, namespace string) context.Context {
|
||||
md, ok := ttrpc.GetMetadata(ctx)
|
||||
if !ok {
|
||||
md = ttrpc.MD{}
|
||||
} else {
|
||||
md = copyMetadata(md)
|
||||
}
|
||||
md.Set(TTRPCHeader, namespace)
|
||||
return ttrpc.WithMetadata(ctx, md)
|
||||
}
|
||||
|
||||
func fromTTRPCHeader(ctx context.Context) (string, bool) {
|
||||
return ttrpc.GetMetadataValue(ctx, TTRPCHeader)
|
||||
}
|
||||
83
vendor/github.com/containerd/containerd/namespaces/validate.go
generated
vendored
83
vendor/github.com/containerd/containerd/namespaces/validate.go
generated
vendored
@ -1,83 +0,0 @@
|
||||
/*
|
||||
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 namespaces provides tools for working with namespaces across
|
||||
// containerd.
|
||||
//
|
||||
// Namespaces collect resources such as containers and images, into a unique
|
||||
// identifier space. This means that two applications can use the same
|
||||
// identifiers and not conflict while using containerd.
|
||||
//
|
||||
// This package can be used to ensure that client and server functions
|
||||
// correctly store the namespace on the context.
|
||||
package namespaces
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
maxLength = 76
|
||||
alpha = `[A-Za-z]`
|
||||
alphanum = `[A-Za-z0-9]+`
|
||||
label = alpha + alphanum + `(:?[-]+` + alpha + alphanum + `)*`
|
||||
)
|
||||
|
||||
var (
|
||||
// namespaceRe validates that a namespace matches valid identifiers.
|
||||
//
|
||||
// Rules for domains, defined in RFC 1035, section 2.3.1, are used for
|
||||
// namespaces.
|
||||
namespaceRe = regexp.MustCompile(reAnchor(label + reGroup("[.]"+reGroup(label)) + "*"))
|
||||
)
|
||||
|
||||
// Validate returns nil if the string s is a valid namespace.
|
||||
//
|
||||
// To allow such namespace identifiers to be used across various contexts
|
||||
// safely, the character set has been restricted to that defined for domains in
|
||||
// RFC 1035, section 2.3.1. This will make namespace identifiers safe for use
|
||||
// across networks, filesystems and other media.
|
||||
//
|
||||
// The identifier specification departs from RFC 1035 in that it allows
|
||||
// "labels" to start with number and only enforces a total length restriction
|
||||
// of 76 characters.
|
||||
//
|
||||
// While the character set may be expanded in the future, namespace identifiers
|
||||
// are guaranteed to be safely used as filesystem path components.
|
||||
//
|
||||
// For the most part, this doesn't need to be called directly when using the
|
||||
// context-oriented functions.
|
||||
func Validate(s string) error {
|
||||
if len(s) > maxLength {
|
||||
return errors.Wrapf(errdefs.ErrInvalidArgument, "namespace %q greater than maximum length (%d characters)", s, maxLength)
|
||||
}
|
||||
|
||||
if !namespaceRe.MatchString(s) {
|
||||
return errors.Wrapf(errdefs.ErrInvalidArgument, "namespace %q must match %v", s, namespaceRe)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func reGroup(s string) string {
|
||||
return `(?:` + s + `)`
|
||||
}
|
||||
|
||||
func reAnchor(s string) string {
|
||||
return `^` + s + `$`
|
||||
}
|
||||
38
vendor/github.com/containerd/containerd/oci/client.go
generated
vendored
38
vendor/github.com/containerd/containerd/oci/client.go
generated
vendored
@ -1,38 +0,0 @@
|
||||
/*
|
||||
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 oci
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/snapshots"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// Client interface used by SpecOpt
|
||||
type Client interface {
|
||||
SnapshotService(snapshotterName string) snapshots.Snapshotter
|
||||
}
|
||||
|
||||
// Image interface used by some SpecOpt to query image configuration
|
||||
type Image interface {
|
||||
// Config descriptor for the image.
|
||||
Config(ctx context.Context) (ocispec.Descriptor, error)
|
||||
// ContentStore provides a content store which contains image blob data
|
||||
ContentStore() content.Store
|
||||
}
|
||||
253
vendor/github.com/containerd/containerd/oci/spec.go
generated
vendored
253
vendor/github.com/containerd/containerd/oci/spec.go
generated
vendored
@ -1,253 +0,0 @@
|
||||
/*
|
||||
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 oci
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
|
||||
"github.com/containerd/containerd/containers"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
const (
|
||||
rwm = "rwm"
|
||||
defaultRootfsPath = "rootfs"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultUnixEnv = []string{
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
}
|
||||
)
|
||||
|
||||
// Spec is a type alias to the OCI runtime spec to allow third part SpecOpts
|
||||
// to be created without the "issues" with go vendoring and package imports
|
||||
type Spec = specs.Spec
|
||||
|
||||
// GenerateSpec will generate a default spec from the provided image
|
||||
// for use as a containerd container
|
||||
func GenerateSpec(ctx context.Context, client Client, c *containers.Container, opts ...SpecOpts) (*Spec, error) {
|
||||
return GenerateSpecWithPlatform(ctx, client, platforms.DefaultString(), c, opts...)
|
||||
}
|
||||
|
||||
// GenerateSpecWithPlatform will generate a default spec from the provided image
|
||||
// for use as a containerd container in the platform requested.
|
||||
func GenerateSpecWithPlatform(ctx context.Context, client Client, platform string, c *containers.Container, opts ...SpecOpts) (*Spec, error) {
|
||||
var s Spec
|
||||
if err := generateDefaultSpecWithPlatform(ctx, platform, c.ID, &s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &s, ApplyOpts(ctx, client, c, &s, opts...)
|
||||
}
|
||||
|
||||
func generateDefaultSpecWithPlatform(ctx context.Context, platform, id string, s *Spec) error {
|
||||
plat, err := platforms.Parse(platform)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if plat.OS == "windows" {
|
||||
err = populateDefaultWindowsSpec(ctx, s, id)
|
||||
} else {
|
||||
err = populateDefaultUnixSpec(ctx, s, id)
|
||||
if err == nil && runtime.GOOS == "windows" {
|
||||
// To run LCOW we have a Linux and Windows section. Add an empty one now.
|
||||
s.Windows = &specs.Windows{}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// ApplyOpts applies the options to the given spec, injecting data from the
|
||||
// context, client and container instance.
|
||||
func ApplyOpts(ctx context.Context, client Client, c *containers.Container, s *Spec, opts ...SpecOpts) error {
|
||||
for _, o := range opts {
|
||||
if err := o(ctx, client, c, s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func defaultUnixCaps() []string {
|
||||
return []string{
|
||||
"CAP_CHOWN",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_FSETID",
|
||||
"CAP_FOWNER",
|
||||
"CAP_MKNOD",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_KILL",
|
||||
"CAP_AUDIT_WRITE",
|
||||
}
|
||||
}
|
||||
|
||||
func defaultUnixNamespaces() []specs.LinuxNamespace {
|
||||
return []specs.LinuxNamespace{
|
||||
{
|
||||
Type: specs.PIDNamespace,
|
||||
},
|
||||
{
|
||||
Type: specs.IPCNamespace,
|
||||
},
|
||||
{
|
||||
Type: specs.UTSNamespace,
|
||||
},
|
||||
{
|
||||
Type: specs.MountNamespace,
|
||||
},
|
||||
{
|
||||
Type: specs.NetworkNamespace,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func populateDefaultUnixSpec(ctx context.Context, s *Spec, id string) error {
|
||||
ns, err := namespaces.NamespaceRequired(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*s = Spec{
|
||||
Version: specs.Version,
|
||||
Root: &specs.Root{
|
||||
Path: defaultRootfsPath,
|
||||
},
|
||||
Process: &specs.Process{
|
||||
Cwd: "/",
|
||||
NoNewPrivileges: true,
|
||||
User: specs.User{
|
||||
UID: 0,
|
||||
GID: 0,
|
||||
},
|
||||
Capabilities: &specs.LinuxCapabilities{
|
||||
Bounding: defaultUnixCaps(),
|
||||
Permitted: defaultUnixCaps(),
|
||||
Inheritable: defaultUnixCaps(),
|
||||
Effective: defaultUnixCaps(),
|
||||
},
|
||||
Rlimits: []specs.POSIXRlimit{
|
||||
{
|
||||
Type: "RLIMIT_NOFILE",
|
||||
Hard: uint64(1024),
|
||||
Soft: uint64(1024),
|
||||
},
|
||||
},
|
||||
},
|
||||
Mounts: []specs.Mount{
|
||||
{
|
||||
Destination: "/proc",
|
||||
Type: "proc",
|
||||
Source: "proc",
|
||||
Options: []string{"nosuid", "noexec", "nodev"},
|
||||
},
|
||||
{
|
||||
Destination: "/dev",
|
||||
Type: "tmpfs",
|
||||
Source: "tmpfs",
|
||||
Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
|
||||
},
|
||||
{
|
||||
Destination: "/dev/pts",
|
||||
Type: "devpts",
|
||||
Source: "devpts",
|
||||
Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"},
|
||||
},
|
||||
{
|
||||
Destination: "/dev/shm",
|
||||
Type: "tmpfs",
|
||||
Source: "shm",
|
||||
Options: []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"},
|
||||
},
|
||||
{
|
||||
Destination: "/dev/mqueue",
|
||||
Type: "mqueue",
|
||||
Source: "mqueue",
|
||||
Options: []string{"nosuid", "noexec", "nodev"},
|
||||
},
|
||||
{
|
||||
Destination: "/sys",
|
||||
Type: "sysfs",
|
||||
Source: "sysfs",
|
||||
Options: []string{"nosuid", "noexec", "nodev", "ro"},
|
||||
},
|
||||
{
|
||||
Destination: "/run",
|
||||
Type: "tmpfs",
|
||||
Source: "tmpfs",
|
||||
Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
|
||||
},
|
||||
},
|
||||
Linux: &specs.Linux{
|
||||
MaskedPaths: []string{
|
||||
"/proc/acpi",
|
||||
"/proc/asound",
|
||||
"/proc/kcore",
|
||||
"/proc/keys",
|
||||
"/proc/latency_stats",
|
||||
"/proc/timer_list",
|
||||
"/proc/timer_stats",
|
||||
"/proc/sched_debug",
|
||||
"/sys/firmware",
|
||||
"/proc/scsi",
|
||||
},
|
||||
ReadonlyPaths: []string{
|
||||
"/proc/bus",
|
||||
"/proc/fs",
|
||||
"/proc/irq",
|
||||
"/proc/sys",
|
||||
"/proc/sysrq-trigger",
|
||||
},
|
||||
CgroupsPath: filepath.Join("/", ns, id),
|
||||
Resources: &specs.LinuxResources{
|
||||
Devices: []specs.LinuxDeviceCgroup{
|
||||
{
|
||||
Allow: false,
|
||||
Access: rwm,
|
||||
},
|
||||
},
|
||||
},
|
||||
Namespaces: defaultUnixNamespaces(),
|
||||
},
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func populateDefaultWindowsSpec(ctx context.Context, s *Spec, id string) error {
|
||||
*s = Spec{
|
||||
Version: specs.Version,
|
||||
Root: &specs.Root{},
|
||||
Process: &specs.Process{
|
||||
Cwd: `C:\`,
|
||||
},
|
||||
Windows: &specs.Windows{},
|
||||
}
|
||||
return nil
|
||||
}
|
||||
1263
vendor/github.com/containerd/containerd/oci/spec_opts.go
generated
vendored
1263
vendor/github.com/containerd/containerd/oci/spec_opts.go
generated
vendored
File diff suppressed because it is too large
Load Diff
121
vendor/github.com/containerd/containerd/oci/spec_opts_linux.go
generated
vendored
121
vendor/github.com/containerd/containerd/oci/spec_opts_linux.go
generated
vendored
@ -1,121 +0,0 @@
|
||||
// +build linux
|
||||
|
||||
/*
|
||||
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 oci
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/containerd/containerd/containers"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// WithHostDevices adds all the hosts device nodes to the container's spec
|
||||
func WithHostDevices(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
|
||||
setLinux(s)
|
||||
|
||||
devs, err := getDevices("/dev")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.Linux.Devices = append(s.Linux.Devices, devs...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getDevices(path string) ([]specs.LinuxDevice, error) {
|
||||
files, err := ioutil.ReadDir(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out []specs.LinuxDevice
|
||||
for _, f := range files {
|
||||
switch {
|
||||
case f.IsDir():
|
||||
switch f.Name() {
|
||||
// ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825
|
||||
// ".udev" added to address https://github.com/opencontainers/runc/issues/2093
|
||||
case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts", ".udev":
|
||||
continue
|
||||
default:
|
||||
sub, err := getDevices(filepath.Join(path, f.Name()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out = append(out, sub...)
|
||||
continue
|
||||
}
|
||||
case f.Name() == "console":
|
||||
continue
|
||||
}
|
||||
device, err := deviceFromPath(filepath.Join(path, f.Name()), "rwm")
|
||||
if err != nil {
|
||||
if err == ErrNotADevice {
|
||||
continue
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, *device)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func deviceFromPath(path, permissions string) (*specs.LinuxDevice, error) {
|
||||
var stat unix.Stat_t
|
||||
if err := unix.Lstat(path, &stat); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
// The type is 32bit on mips.
|
||||
devNumber = uint64(stat.Rdev) // nolint: unconvert
|
||||
major = unix.Major(devNumber)
|
||||
minor = unix.Minor(devNumber)
|
||||
)
|
||||
if major == 0 {
|
||||
return nil, ErrNotADevice
|
||||
}
|
||||
|
||||
var (
|
||||
devType string
|
||||
mode = stat.Mode
|
||||
)
|
||||
switch {
|
||||
case mode&unix.S_IFBLK == unix.S_IFBLK:
|
||||
devType = "b"
|
||||
case mode&unix.S_IFCHR == unix.S_IFCHR:
|
||||
devType = "c"
|
||||
}
|
||||
fm := os.FileMode(mode)
|
||||
return &specs.LinuxDevice{
|
||||
Type: devType,
|
||||
Path: path,
|
||||
Major: int64(major),
|
||||
Minor: int64(minor),
|
||||
FileMode: &fm,
|
||||
UID: &stat.Uid,
|
||||
GID: &stat.Gid,
|
||||
}, nil
|
||||
}
|
||||
120
vendor/github.com/containerd/containerd/oci/spec_opts_unix.go
generated
vendored
120
vendor/github.com/containerd/containerd/oci/spec_opts_unix.go
generated
vendored
@ -1,120 +0,0 @@
|
||||
// +build !linux,!windows
|
||||
|
||||
/*
|
||||
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 oci
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/containerd/containerd/containers"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// WithHostDevices adds all the hosts device nodes to the container's spec
|
||||
func WithHostDevices(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
|
||||
setLinux(s)
|
||||
|
||||
devs, err := getDevices("/dev")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.Linux.Devices = append(s.Linux.Devices, devs...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getDevices(path string) ([]specs.LinuxDevice, error) {
|
||||
files, err := ioutil.ReadDir(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out []specs.LinuxDevice
|
||||
for _, f := range files {
|
||||
switch {
|
||||
case f.IsDir():
|
||||
switch f.Name() {
|
||||
// ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825
|
||||
// ".udev" added to address https://github.com/opencontainers/runc/issues/2093
|
||||
case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts", ".udev":
|
||||
continue
|
||||
default:
|
||||
sub, err := getDevices(filepath.Join(path, f.Name()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out = append(out, sub...)
|
||||
continue
|
||||
}
|
||||
case f.Name() == "console":
|
||||
continue
|
||||
}
|
||||
device, err := deviceFromPath(filepath.Join(path, f.Name()), "rwm")
|
||||
if err != nil {
|
||||
if err == ErrNotADevice {
|
||||
continue
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, *device)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func deviceFromPath(path, permissions string) (*specs.LinuxDevice, error) {
|
||||
var stat unix.Stat_t
|
||||
if err := unix.Lstat(path, &stat); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
devNumber = uint64(stat.Rdev)
|
||||
major = unix.Major(devNumber)
|
||||
minor = unix.Minor(devNumber)
|
||||
)
|
||||
if major == 0 {
|
||||
return nil, ErrNotADevice
|
||||
}
|
||||
|
||||
var (
|
||||
devType string
|
||||
mode = stat.Mode
|
||||
)
|
||||
switch {
|
||||
case mode&unix.S_IFBLK == unix.S_IFBLK:
|
||||
devType = "b"
|
||||
case mode&unix.S_IFCHR == unix.S_IFCHR:
|
||||
devType = "c"
|
||||
}
|
||||
fm := os.FileMode(mode)
|
||||
return &specs.LinuxDevice{
|
||||
Type: devType,
|
||||
Path: path,
|
||||
Major: int64(major),
|
||||
Minor: int64(minor),
|
||||
FileMode: &fm,
|
||||
UID: &stat.Uid,
|
||||
GID: &stat.Gid,
|
||||
}, nil
|
||||
}
|
||||
79
vendor/github.com/containerd/containerd/oci/spec_opts_windows.go
generated
vendored
79
vendor/github.com/containerd/containerd/oci/spec_opts_windows.go
generated
vendored
@ -1,79 +0,0 @@
|
||||
// +build windows
|
||||
|
||||
/*
|
||||
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 oci
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containerd/containerd/containers"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// WithWindowsCPUCount sets the `Windows.Resources.CPU.Count` section to the
|
||||
// `count` specified.
|
||||
func WithWindowsCPUCount(count uint64) SpecOpts {
|
||||
return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
|
||||
if s.Windows.Resources == nil {
|
||||
s.Windows.Resources = &specs.WindowsResources{}
|
||||
}
|
||||
if s.Windows.Resources.CPU == nil {
|
||||
s.Windows.Resources.CPU = &specs.WindowsCPUResources{}
|
||||
}
|
||||
s.Windows.Resources.CPU.Count = &count
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithWindowsIgnoreFlushesDuringBoot sets `Windows.IgnoreFlushesDuringBoot`.
|
||||
func WithWindowsIgnoreFlushesDuringBoot() SpecOpts {
|
||||
return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
|
||||
if s.Windows == nil {
|
||||
s.Windows = &specs.Windows{}
|
||||
}
|
||||
s.Windows.IgnoreFlushesDuringBoot = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithWindowNetworksAllowUnqualifiedDNSQuery sets `Windows.IgnoreFlushesDuringBoot`.
|
||||
func WithWindowNetworksAllowUnqualifiedDNSQuery() SpecOpts {
|
||||
return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
|
||||
if s.Windows == nil {
|
||||
s.Windows = &specs.Windows{}
|
||||
}
|
||||
if s.Windows.Network == nil {
|
||||
s.Windows.Network = &specs.WindowsNetwork{}
|
||||
}
|
||||
|
||||
s.Windows.Network.AllowUnqualifiedDNSQuery = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithHostDevices adds all the hosts device nodes to the container's spec
|
||||
//
|
||||
// Not supported on windows
|
||||
func WithHostDevices(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func deviceFromPath(path, permissions string) (*specs.LinuxDevice, error) {
|
||||
return nil, errors.New("device from path not supported on Windows")
|
||||
}
|
||||
339
vendor/github.com/containerd/containerd/snapshots/snapshotter.go
generated
vendored
339
vendor/github.com/containerd/containerd/snapshots/snapshotter.go
generated
vendored
@ -1,339 +0,0 @@
|
||||
/*
|
||||
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 snapshots
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/mount"
|
||||
)
|
||||
|
||||
// Kind identifies the kind of snapshot.
|
||||
type Kind uint8
|
||||
|
||||
// definitions of snapshot kinds
|
||||
const (
|
||||
KindUnknown Kind = iota
|
||||
KindView
|
||||
KindActive
|
||||
KindCommitted
|
||||
)
|
||||
|
||||
// ParseKind parses the provided string into a Kind
|
||||
//
|
||||
// If the string cannot be parsed KindUnknown is returned
|
||||
func ParseKind(s string) Kind {
|
||||
s = strings.ToLower(s)
|
||||
switch s {
|
||||
case "view":
|
||||
return KindView
|
||||
case "active":
|
||||
return KindActive
|
||||
case "committed":
|
||||
return KindCommitted
|
||||
}
|
||||
|
||||
return KindUnknown
|
||||
}
|
||||
|
||||
// String returns the string representation of the Kind
|
||||
func (k Kind) String() string {
|
||||
switch k {
|
||||
case KindView:
|
||||
return "View"
|
||||
case KindActive:
|
||||
return "Active"
|
||||
case KindCommitted:
|
||||
return "Committed"
|
||||
}
|
||||
|
||||
return "Unknown"
|
||||
}
|
||||
|
||||
// MarshalJSON the Kind to JSON
|
||||
func (k Kind) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(k.String())
|
||||
}
|
||||
|
||||
// UnmarshalJSON the Kind from JSON
|
||||
func (k *Kind) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*k = ParseKind(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Info provides information about a particular snapshot.
|
||||
// JSON marshallability is supported for interactive with tools like ctr,
|
||||
type Info struct {
|
||||
Kind Kind // active or committed snapshot
|
||||
Name string // name or key of snapshot
|
||||
Parent string `json:",omitempty"` // name of parent snapshot
|
||||
|
||||
// Labels for a snapshot.
|
||||
//
|
||||
// Note: only labels prefixed with `containerd.io/snapshot/` will be inherited by the
|
||||
// snapshotter's `Prepare`, `View`, or `Commit` calls.
|
||||
Labels map[string]string `json:",omitempty"`
|
||||
Created time.Time `json:",omitempty"` // Created time
|
||||
Updated time.Time `json:",omitempty"` // Last update time
|
||||
}
|
||||
|
||||
// Usage defines statistics for disk resources consumed by the snapshot.
|
||||
//
|
||||
// These resources only include the resources consumed by the snapshot itself
|
||||
// and does not include resources usage by the parent.
|
||||
type Usage struct {
|
||||
Inodes int64 // number of inodes in use.
|
||||
Size int64 // provides usage, in bytes, of snapshot
|
||||
}
|
||||
|
||||
// Add the provided usage to the current usage
|
||||
func (u *Usage) Add(other Usage) {
|
||||
u.Size += other.Size
|
||||
|
||||
// TODO(stevvooe): assumes independent inodes, but provides and upper
|
||||
// bound. This should be pretty close, assuming the inodes for a
|
||||
// snapshot are roughly unique to it. Don't trust this assumption.
|
||||
u.Inodes += other.Inodes
|
||||
}
|
||||
|
||||
// Snapshotter defines the methods required to implement a snapshot snapshotter for
|
||||
// allocating, snapshotting and mounting filesystem changesets. The model works
|
||||
// by building up sets of changes with parent-child relationships.
|
||||
//
|
||||
// A snapshot represents a filesystem state. Every snapshot has a parent, where
|
||||
// the empty parent is represented by the empty string. A diff can be taken
|
||||
// between a parent and its snapshot to generate a classic layer.
|
||||
//
|
||||
// An active snapshot is created by calling `Prepare`. After mounting, changes
|
||||
// can be made to the snapshot. The act of committing creates a committed
|
||||
// snapshot. The committed snapshot will get the parent of active snapshot. The
|
||||
// committed snapshot can then be used as a parent. Active snapshots can never
|
||||
// act as a parent.
|
||||
//
|
||||
// Snapshots are best understood by their lifecycle. Active snapshots are
|
||||
// always created with Prepare or View. Committed snapshots are always created
|
||||
// with Commit. Active snapshots never become committed snapshots and vice
|
||||
// versa. All snapshots may be removed.
|
||||
//
|
||||
// For consistency, we define the following terms to be used throughout this
|
||||
// interface for snapshotter implementations:
|
||||
//
|
||||
// `ctx` - refers to a context.Context
|
||||
// `key` - refers to an active snapshot
|
||||
// `name` - refers to a committed snapshot
|
||||
// `parent` - refers to the parent in relation
|
||||
//
|
||||
// Most methods take various combinations of these identifiers. Typically,
|
||||
// `name` and `parent` will be used in cases where a method *only* takes
|
||||
// committed snapshots. `key` will be used to refer to active snapshots in most
|
||||
// cases, except where noted. All variables used to access snapshots use the
|
||||
// same key space. For example, an active snapshot may not share the same key
|
||||
// with a committed snapshot.
|
||||
//
|
||||
// We cover several examples below to demonstrate the utility of a snapshot
|
||||
// snapshotter.
|
||||
//
|
||||
// Importing a Layer
|
||||
//
|
||||
// To import a layer, we simply have the Snapshotter provide a list of
|
||||
// mounts to be applied such that our dst will capture a changeset. We start
|
||||
// out by getting a path to the layer tar file and creating a temp location to
|
||||
// unpack it to:
|
||||
//
|
||||
// layerPath, tmpDir := getLayerPath(), mkTmpDir() // just a path to layer tar file.
|
||||
//
|
||||
// We start by using a Snapshotter to Prepare a new snapshot transaction, using a
|
||||
// key and descending from the empty parent "". To prevent our layer from being
|
||||
// garbage collected during unpacking, we add the `containerd.io/gc.root` label:
|
||||
//
|
||||
// noGcOpt := snapshots.WithLabels(map[string]string{
|
||||
// "containerd.io/gc.root": time.Now().UTC().Format(time.RFC3339),
|
||||
// })
|
||||
// mounts, err := snapshotter.Prepare(ctx, key, "", noGcOpt)
|
||||
// if err != nil { ... }
|
||||
//
|
||||
// We get back a list of mounts from Snapshotter.Prepare, with the key identifying
|
||||
// the active snapshot. Mount this to the temporary location with the
|
||||
// following:
|
||||
//
|
||||
// if err := mount.All(mounts, tmpDir); err != nil { ... }
|
||||
//
|
||||
// Once the mounts are performed, our temporary location is ready to capture
|
||||
// a diff. In practice, this works similar to a filesystem transaction. The
|
||||
// next step is to unpack the layer. We have a special function unpackLayer
|
||||
// that applies the contents of the layer to target location and calculates the
|
||||
// DiffID of the unpacked layer (this is a requirement for docker
|
||||
// implementation):
|
||||
//
|
||||
// layer, err := os.Open(layerPath)
|
||||
// if err != nil { ... }
|
||||
// digest, err := unpackLayer(tmpLocation, layer) // unpack into layer location
|
||||
// if err != nil { ... }
|
||||
//
|
||||
// When the above completes, we should have a filesystem the represents the
|
||||
// contents of the layer. Careful implementations should verify that digest
|
||||
// matches the expected DiffID. When completed, we unmount the mounts:
|
||||
//
|
||||
// unmount(mounts) // optional, for now
|
||||
//
|
||||
// Now that we've verified and unpacked our layer, we commit the active
|
||||
// snapshot to a name. For this example, we are just going to use the layer
|
||||
// digest, but in practice, this will probably be the ChainID. This also removes
|
||||
// the active snapshot:
|
||||
//
|
||||
// if err := snapshotter.Commit(ctx, digest.String(), key, noGcOpt); err != nil { ... }
|
||||
//
|
||||
// Now, we have a layer in the Snapshotter that can be accessed with the digest
|
||||
// provided during commit.
|
||||
//
|
||||
// Importing the Next Layer
|
||||
//
|
||||
// Making a layer depend on the above is identical to the process described
|
||||
// above except that the parent is provided as parent when calling
|
||||
// Manager.Prepare, assuming a clean, unique key identifier:
|
||||
//
|
||||
// mounts, err := snapshotter.Prepare(ctx, key, parentDigest, noGcOpt)
|
||||
//
|
||||
// We then mount, apply and commit, as we did above. The new snapshot will be
|
||||
// based on the content of the previous one.
|
||||
//
|
||||
// Running a Container
|
||||
//
|
||||
// To run a container, we simply provide Snapshotter.Prepare the committed image
|
||||
// snapshot as the parent. After mounting, the prepared path can
|
||||
// be used directly as the container's filesystem:
|
||||
//
|
||||
// mounts, err := snapshotter.Prepare(ctx, containerKey, imageRootFSChainID)
|
||||
//
|
||||
// The returned mounts can then be passed directly to the container runtime. If
|
||||
// one would like to create a new image from the filesystem, Manager.Commit is
|
||||
// called:
|
||||
//
|
||||
// if err := snapshotter.Commit(ctx, newImageSnapshot, containerKey); err != nil { ... }
|
||||
//
|
||||
// Alternatively, for most container runs, Snapshotter.Remove will be called to
|
||||
// signal the Snapshotter to abandon the changes.
|
||||
type Snapshotter interface {
|
||||
// Stat returns the info for an active or committed snapshot by name or
|
||||
// key.
|
||||
//
|
||||
// Should be used for parent resolution, existence checks and to discern
|
||||
// the kind of snapshot.
|
||||
Stat(ctx context.Context, key string) (Info, error)
|
||||
|
||||
// Update updates the info for a snapshot.
|
||||
//
|
||||
// Only mutable properties of a snapshot may be updated.
|
||||
Update(ctx context.Context, info Info, fieldpaths ...string) (Info, error)
|
||||
|
||||
// Usage returns the resource usage of an active or committed snapshot
|
||||
// excluding the usage of parent snapshots.
|
||||
//
|
||||
// The running time of this call for active snapshots is dependent on
|
||||
// implementation, but may be proportional to the size of the resource.
|
||||
// Callers should take this into consideration. Implementations should
|
||||
// attempt to honer context cancellation and avoid taking locks when making
|
||||
// the calculation.
|
||||
Usage(ctx context.Context, key string) (Usage, error)
|
||||
|
||||
// Mounts returns the mounts for the active snapshot transaction identified
|
||||
// by key. Can be called on an read-write or readonly transaction. This is
|
||||
// available only for active snapshots.
|
||||
//
|
||||
// This can be used to recover mounts after calling View or Prepare.
|
||||
Mounts(ctx context.Context, key string) ([]mount.Mount, error)
|
||||
|
||||
// Prepare creates an active snapshot identified by key descending from the
|
||||
// provided parent. The returned mounts can be used to mount the snapshot
|
||||
// to capture changes.
|
||||
//
|
||||
// If a parent is provided, after performing the mounts, the destination
|
||||
// will start with the content of the parent. The parent must be a
|
||||
// committed snapshot. Changes to the mounted destination will be captured
|
||||
// in relation to the parent. The default parent, "", is an empty
|
||||
// directory.
|
||||
//
|
||||
// The changes may be saved to a committed snapshot by calling Commit. When
|
||||
// one is done with the transaction, Remove should be called on the key.
|
||||
//
|
||||
// Multiple calls to Prepare or View with the same key should fail.
|
||||
Prepare(ctx context.Context, key, parent string, opts ...Opt) ([]mount.Mount, error)
|
||||
|
||||
// View behaves identically to Prepare except the result may not be
|
||||
// committed back to the snapshot snapshotter. View returns a readonly view on
|
||||
// the parent, with the active snapshot being tracked by the given key.
|
||||
//
|
||||
// This method operates identically to Prepare, except that Mounts returned
|
||||
// may have the readonly flag set. Any modifications to the underlying
|
||||
// filesystem will be ignored. Implementations may perform this in a more
|
||||
// efficient manner that differs from what would be attempted with
|
||||
// `Prepare`.
|
||||
//
|
||||
// Commit may not be called on the provided key and will return an error.
|
||||
// To collect the resources associated with key, Remove must be called with
|
||||
// key as the argument.
|
||||
View(ctx context.Context, key, parent string, opts ...Opt) ([]mount.Mount, error)
|
||||
|
||||
// Commit captures the changes between key and its parent into a snapshot
|
||||
// identified by name. The name can then be used with the snapshotter's other
|
||||
// methods to create subsequent snapshots.
|
||||
//
|
||||
// A committed snapshot will be created under name with the parent of the
|
||||
// active snapshot.
|
||||
//
|
||||
// After commit, the snapshot identified by key is removed.
|
||||
Commit(ctx context.Context, name, key string, opts ...Opt) error
|
||||
|
||||
// Remove the committed or active snapshot by the provided key.
|
||||
//
|
||||
// All resources associated with the key will be removed.
|
||||
//
|
||||
// If the snapshot is a parent of another snapshot, its children must be
|
||||
// removed before proceeding.
|
||||
Remove(ctx context.Context, key string) error
|
||||
|
||||
// Walk all snapshots in the snapshotter. For each snapshot in the
|
||||
// snapshotter, the function will be called.
|
||||
Walk(ctx context.Context, fn func(context.Context, Info) error) error
|
||||
|
||||
// Close releases the internal resources.
|
||||
//
|
||||
// Close is expected to be called on the end of the lifecycle of the snapshotter,
|
||||
// but not mandatory.
|
||||
//
|
||||
// Close returns nil when it is already closed.
|
||||
Close() error
|
||||
}
|
||||
|
||||
// Opt allows setting mutable snapshot properties on creation
|
||||
type Opt func(info *Info) error
|
||||
|
||||
// WithLabels adds labels to a created snapshot
|
||||
func WithLabels(labels map[string]string) Opt {
|
||||
return func(info *Info) error {
|
||||
info.Labels = labels
|
||||
return nil
|
||||
}
|
||||
}
|
||||
201
vendor/github.com/containerd/ttrpc/LICENSE
generated
vendored
201
vendor/github.com/containerd/ttrpc/LICENSE
generated
vendored
@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
62
vendor/github.com/containerd/ttrpc/README.md
generated
vendored
62
vendor/github.com/containerd/ttrpc/README.md
generated
vendored
@ -1,62 +0,0 @@
|
||||
# ttrpc
|
||||
|
||||
[](https://travis-ci.org/containerd/ttrpc)
|
||||
|
||||
GRPC for low-memory environments.
|
||||
|
||||
The existing grpc-go project requires a lot of memory overhead for importing
|
||||
packages and at runtime. While this is great for many services with low density
|
||||
requirements, this can be a problem when running a large number of services on
|
||||
a single machine or on a machine with a small amount of memory.
|
||||
|
||||
Using the same GRPC definitions, this project reduces the binary size and
|
||||
protocol overhead required. We do this by eliding the `net/http`, `net/http2`
|
||||
and `grpc` package used by grpc replacing it with a lightweight framing
|
||||
protocol. The result are smaller binaries that use less resident memory with
|
||||
the same ease of use as GRPC.
|
||||
|
||||
Please note that while this project supports generating either end of the
|
||||
protocol, the generated service definitions will be incompatible with regular
|
||||
GRPC services, as they do not speak the same protocol.
|
||||
|
||||
# Usage
|
||||
|
||||
Create a gogo vanity binary (see
|
||||
[`cmd/protoc-gen-gogottrpc/main.go`](cmd/protoc-gen-gogottrpc/main.go) for an
|
||||
example with the ttrpc plugin enabled.
|
||||
|
||||
It's recommended to use [`protobuild`](https://github.com//stevvooe/protobuild)
|
||||
to build the protobufs for this project, but this will work with protoc
|
||||
directly, if required.
|
||||
|
||||
# Differences from GRPC
|
||||
|
||||
- The protocol stack has been replaced with a lighter protocol that doesn't
|
||||
require http, http2 and tls.
|
||||
- The client and server interface are identical whereas in GRPC there is a
|
||||
client and server interface that are different.
|
||||
- The Go stdlib context package is used instead.
|
||||
- No support for streams yet.
|
||||
|
||||
# Status
|
||||
|
||||
Very new. YMMV.
|
||||
|
||||
TODO:
|
||||
|
||||
- [X] Plumb error codes and GRPC status
|
||||
- [X] Remove use of any type and dependency on typeurl package
|
||||
- [X] Ensure that protocol can support streaming in the future
|
||||
- [ ] Document protocol layout
|
||||
- [ ] Add testing under concurrent load to ensure
|
||||
- [ ] Verify connection error handling
|
||||
|
||||
# Project details
|
||||
|
||||
ttrpc is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
|
||||
As a containerd sub-project, you will find the:
|
||||
* [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md),
|
||||
* [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS),
|
||||
* and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md)
|
||||
|
||||
information in our [`containerd/project`](https://github.com/containerd/project) repository.
|
||||
153
vendor/github.com/containerd/ttrpc/channel.go
generated
vendored
153
vendor/github.com/containerd/ttrpc/channel.go
generated
vendored
@ -1,153 +0,0 @@
|
||||
/*
|
||||
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 ttrpc
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
const (
|
||||
messageHeaderLength = 10
|
||||
messageLengthMax = 4 << 20
|
||||
)
|
||||
|
||||
type messageType uint8
|
||||
|
||||
const (
|
||||
messageTypeRequest messageType = 0x1
|
||||
messageTypeResponse messageType = 0x2
|
||||
)
|
||||
|
||||
// messageHeader represents the fixed-length message header of 10 bytes sent
|
||||
// with every request.
|
||||
type messageHeader struct {
|
||||
Length uint32 // length excluding this header. b[:4]
|
||||
StreamID uint32 // identifies which request stream message is a part of. b[4:8]
|
||||
Type messageType // message type b[8]
|
||||
Flags uint8 // reserved b[9]
|
||||
}
|
||||
|
||||
func readMessageHeader(p []byte, r io.Reader) (messageHeader, error) {
|
||||
_, err := io.ReadFull(r, p[:messageHeaderLength])
|
||||
if err != nil {
|
||||
return messageHeader{}, err
|
||||
}
|
||||
|
||||
return messageHeader{
|
||||
Length: binary.BigEndian.Uint32(p[:4]),
|
||||
StreamID: binary.BigEndian.Uint32(p[4:8]),
|
||||
Type: messageType(p[8]),
|
||||
Flags: p[9],
|
||||
}, nil
|
||||
}
|
||||
|
||||
func writeMessageHeader(w io.Writer, p []byte, mh messageHeader) error {
|
||||
binary.BigEndian.PutUint32(p[:4], mh.Length)
|
||||
binary.BigEndian.PutUint32(p[4:8], mh.StreamID)
|
||||
p[8] = byte(mh.Type)
|
||||
p[9] = mh.Flags
|
||||
|
||||
_, err := w.Write(p[:])
|
||||
return err
|
||||
}
|
||||
|
||||
var buffers sync.Pool
|
||||
|
||||
type channel struct {
|
||||
conn net.Conn
|
||||
bw *bufio.Writer
|
||||
br *bufio.Reader
|
||||
hrbuf [messageHeaderLength]byte // avoid alloc when reading header
|
||||
hwbuf [messageHeaderLength]byte
|
||||
}
|
||||
|
||||
func newChannel(conn net.Conn) *channel {
|
||||
return &channel{
|
||||
conn: conn,
|
||||
bw: bufio.NewWriter(conn),
|
||||
br: bufio.NewReader(conn),
|
||||
}
|
||||
}
|
||||
|
||||
// recv a message from the channel. The returned buffer contains the message.
|
||||
//
|
||||
// If a valid grpc status is returned, the message header
|
||||
// returned will be valid and caller should send that along to
|
||||
// the correct consumer. The bytes on the underlying channel
|
||||
// will be discarded.
|
||||
func (ch *channel) recv() (messageHeader, []byte, error) {
|
||||
mh, err := readMessageHeader(ch.hrbuf[:], ch.br)
|
||||
if err != nil {
|
||||
return messageHeader{}, nil, err
|
||||
}
|
||||
|
||||
if mh.Length > uint32(messageLengthMax) {
|
||||
if _, err := ch.br.Discard(int(mh.Length)); err != nil {
|
||||
return mh, nil, errors.Wrapf(err, "failed to discard after receiving oversized message")
|
||||
}
|
||||
|
||||
return mh, nil, status.Errorf(codes.ResourceExhausted, "message length %v exceed maximum message size of %v", mh.Length, messageLengthMax)
|
||||
}
|
||||
|
||||
p := ch.getmbuf(int(mh.Length))
|
||||
if _, err := io.ReadFull(ch.br, p); err != nil {
|
||||
return messageHeader{}, nil, errors.Wrapf(err, "failed reading message")
|
||||
}
|
||||
|
||||
return mh, p, nil
|
||||
}
|
||||
|
||||
func (ch *channel) send(streamID uint32, t messageType, p []byte) error {
|
||||
if err := writeMessageHeader(ch.bw, ch.hwbuf[:], messageHeader{Length: uint32(len(p)), StreamID: streamID, Type: t}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err := ch.bw.Write(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ch.bw.Flush()
|
||||
}
|
||||
|
||||
func (ch *channel) getmbuf(size int) []byte {
|
||||
// we can't use the standard New method on pool because we want to allocate
|
||||
// based on size.
|
||||
b, ok := buffers.Get().(*[]byte)
|
||||
if !ok || cap(*b) < size {
|
||||
// TODO(stevvooe): It may be better to allocate these in fixed length
|
||||
// buckets to reduce fragmentation but its not clear that would help
|
||||
// with performance. An ilogb approach or similar would work well.
|
||||
bb := make([]byte, size)
|
||||
b = &bb
|
||||
} else {
|
||||
*b = (*b)[:size]
|
||||
}
|
||||
return *b
|
||||
}
|
||||
|
||||
func (ch *channel) putmbuf(p []byte) {
|
||||
buffers.Put(&p)
|
||||
}
|
||||
350
vendor/github.com/containerd/ttrpc/client.go
generated
vendored
350
vendor/github.com/containerd/ttrpc/client.go
generated
vendored
@ -1,350 +0,0 @@
|
||||
/*
|
||||
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 ttrpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// ErrClosed is returned by client methods when the underlying connection is
|
||||
// closed.
|
||||
var ErrClosed = errors.New("ttrpc: closed")
|
||||
|
||||
// Client for a ttrpc server
|
||||
type Client struct {
|
||||
codec codec
|
||||
conn net.Conn
|
||||
channel *channel
|
||||
calls chan *callRequest
|
||||
|
||||
ctx context.Context
|
||||
closed func()
|
||||
|
||||
closeOnce sync.Once
|
||||
userCloseFunc func()
|
||||
|
||||
errOnce sync.Once
|
||||
err error
|
||||
interceptor UnaryClientInterceptor
|
||||
}
|
||||
|
||||
// ClientOpts configures a client
|
||||
type ClientOpts func(c *Client)
|
||||
|
||||
// WithOnClose sets the close func whenever the client's Close() method is called
|
||||
func WithOnClose(onClose func()) ClientOpts {
|
||||
return func(c *Client) {
|
||||
c.userCloseFunc = onClose
|
||||
}
|
||||
}
|
||||
|
||||
// WithUnaryClientInterceptor sets the provided client interceptor
|
||||
func WithUnaryClientInterceptor(i UnaryClientInterceptor) ClientOpts {
|
||||
return func(c *Client) {
|
||||
c.interceptor = i
|
||||
}
|
||||
}
|
||||
|
||||
func NewClient(conn net.Conn, opts ...ClientOpts) *Client {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
c := &Client{
|
||||
codec: codec{},
|
||||
conn: conn,
|
||||
channel: newChannel(conn),
|
||||
calls: make(chan *callRequest),
|
||||
closed: cancel,
|
||||
ctx: ctx,
|
||||
userCloseFunc: func() {},
|
||||
interceptor: defaultClientInterceptor,
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(c)
|
||||
}
|
||||
|
||||
go c.run()
|
||||
return c
|
||||
}
|
||||
|
||||
type callRequest struct {
|
||||
ctx context.Context
|
||||
req *Request
|
||||
resp *Response // response will be written back here
|
||||
errs chan error // error written here on completion
|
||||
}
|
||||
|
||||
func (c *Client) Call(ctx context.Context, service, method string, req, resp interface{}) error {
|
||||
payload, err := c.codec.Marshal(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
creq = &Request{
|
||||
Service: service,
|
||||
Method: method,
|
||||
Payload: payload,
|
||||
}
|
||||
|
||||
cresp = &Response{}
|
||||
)
|
||||
|
||||
if metadata, ok := GetMetadata(ctx); ok {
|
||||
metadata.setRequest(creq)
|
||||
}
|
||||
|
||||
if dl, ok := ctx.Deadline(); ok {
|
||||
creq.TimeoutNano = dl.Sub(time.Now()).Nanoseconds()
|
||||
}
|
||||
|
||||
info := &UnaryClientInfo{
|
||||
FullMethod: fullPath(service, method),
|
||||
}
|
||||
if err := c.interceptor(ctx, creq, cresp, info, c.dispatch); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.codec.Unmarshal(cresp.Payload, resp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cresp.Status != nil && cresp.Status.Code != int32(codes.OK) {
|
||||
return status.ErrorProto(cresp.Status)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) dispatch(ctx context.Context, req *Request, resp *Response) error {
|
||||
errs := make(chan error, 1)
|
||||
call := &callRequest{
|
||||
ctx: ctx,
|
||||
req: req,
|
||||
resp: resp,
|
||||
errs: errs,
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case c.calls <- call:
|
||||
case <-c.ctx.Done():
|
||||
return c.error()
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case err := <-errs:
|
||||
return filterCloseErr(err)
|
||||
case <-c.ctx.Done():
|
||||
return c.error()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) Close() error {
|
||||
c.closeOnce.Do(func() {
|
||||
c.closed()
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
type message struct {
|
||||
messageHeader
|
||||
p []byte
|
||||
err error
|
||||
}
|
||||
|
||||
type receiver struct {
|
||||
wg *sync.WaitGroup
|
||||
messages chan *message
|
||||
err error
|
||||
}
|
||||
|
||||
func (r *receiver) run(ctx context.Context, c *channel) {
|
||||
defer r.wg.Done()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
r.err = ctx.Err()
|
||||
return
|
||||
default:
|
||||
mh, p, err := c.recv()
|
||||
if err != nil {
|
||||
_, ok := status.FromError(err)
|
||||
if !ok {
|
||||
// treat all errors that are not an rpc status as terminal.
|
||||
// all others poison the connection.
|
||||
r.err = filterCloseErr(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
select {
|
||||
case r.messages <- &message{
|
||||
messageHeader: mh,
|
||||
p: p[:mh.Length],
|
||||
err: err,
|
||||
}:
|
||||
case <-ctx.Done():
|
||||
r.err = ctx.Err()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) run() {
|
||||
var (
|
||||
streamID uint32 = 1
|
||||
waiters = make(map[uint32]*callRequest)
|
||||
calls = c.calls
|
||||
incoming = make(chan *message)
|
||||
receiversDone = make(chan struct{})
|
||||
wg sync.WaitGroup
|
||||
)
|
||||
|
||||
// broadcast the shutdown error to the remaining waiters.
|
||||
abortWaiters := func(wErr error) {
|
||||
for _, waiter := range waiters {
|
||||
waiter.errs <- wErr
|
||||
}
|
||||
}
|
||||
recv := &receiver{
|
||||
wg: &wg,
|
||||
messages: incoming,
|
||||
}
|
||||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(receiversDone)
|
||||
}()
|
||||
go recv.run(c.ctx, c.channel)
|
||||
|
||||
defer func() {
|
||||
c.conn.Close()
|
||||
c.userCloseFunc()
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case call := <-calls:
|
||||
if err := c.send(streamID, messageTypeRequest, call.req); err != nil {
|
||||
call.errs <- err
|
||||
continue
|
||||
}
|
||||
|
||||
waiters[streamID] = call
|
||||
streamID += 2 // enforce odd client initiated request ids
|
||||
case msg := <-incoming:
|
||||
call, ok := waiters[msg.StreamID]
|
||||
if !ok {
|
||||
logrus.Errorf("ttrpc: received message for unknown channel %v", msg.StreamID)
|
||||
continue
|
||||
}
|
||||
|
||||
call.errs <- c.recv(call.resp, msg)
|
||||
delete(waiters, msg.StreamID)
|
||||
case <-receiversDone:
|
||||
// all the receivers have exited
|
||||
if recv.err != nil {
|
||||
c.setError(recv.err)
|
||||
}
|
||||
// don't return out, let the close of the context trigger the abort of waiters
|
||||
c.Close()
|
||||
case <-c.ctx.Done():
|
||||
abortWaiters(c.error())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) error() error {
|
||||
c.errOnce.Do(func() {
|
||||
if c.err == nil {
|
||||
c.err = ErrClosed
|
||||
}
|
||||
})
|
||||
return c.err
|
||||
}
|
||||
|
||||
func (c *Client) setError(err error) {
|
||||
c.errOnce.Do(func() {
|
||||
c.err = err
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Client) send(streamID uint32, mtype messageType, msg interface{}) error {
|
||||
p, err := c.codec.Marshal(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.channel.send(streamID, mtype, p)
|
||||
}
|
||||
|
||||
func (c *Client) recv(resp *Response, msg *message) error {
|
||||
if msg.err != nil {
|
||||
return msg.err
|
||||
}
|
||||
|
||||
if msg.Type != messageTypeResponse {
|
||||
return errors.New("unknown message type received")
|
||||
}
|
||||
|
||||
defer c.channel.putmbuf(msg.p)
|
||||
return proto.Unmarshal(msg.p, resp)
|
||||
}
|
||||
|
||||
// filterCloseErr rewrites EOF and EPIPE errors to ErrClosed. Use when
|
||||
// returning from call or handling errors from main read loop.
|
||||
//
|
||||
// This purposely ignores errors with a wrapped cause.
|
||||
func filterCloseErr(err error) error {
|
||||
switch {
|
||||
case err == nil:
|
||||
return nil
|
||||
case err == io.EOF:
|
||||
return ErrClosed
|
||||
case errors.Cause(err) == io.EOF:
|
||||
return ErrClosed
|
||||
case strings.Contains(err.Error(), "use of closed network connection"):
|
||||
return ErrClosed
|
||||
default:
|
||||
// if we have an epipe on a write, we cast to errclosed
|
||||
if oerr, ok := err.(*net.OpError); ok && oerr.Op == "write" {
|
||||
if serr, ok := oerr.Err.(*os.SyscallError); ok && serr.Err == syscall.EPIPE {
|
||||
return ErrClosed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
42
vendor/github.com/containerd/ttrpc/codec.go
generated
vendored
42
vendor/github.com/containerd/ttrpc/codec.go
generated
vendored
@ -1,42 +0,0 @@
|
||||
/*
|
||||
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 ttrpc
|
||||
|
||||
import (
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type codec struct{}
|
||||
|
||||
func (c codec) Marshal(msg interface{}) ([]byte, error) {
|
||||
switch v := msg.(type) {
|
||||
case proto.Message:
|
||||
return proto.Marshal(v)
|
||||
default:
|
||||
return nil, errors.Errorf("ttrpc: cannot marshal unknown type: %T", msg)
|
||||
}
|
||||
}
|
||||
|
||||
func (c codec) Unmarshal(p []byte, msg interface{}) error {
|
||||
switch v := msg.(type) {
|
||||
case proto.Message:
|
||||
return proto.Unmarshal(p, v)
|
||||
default:
|
||||
return errors.Errorf("ttrpc: cannot unmarshal into unknown type: %T", msg)
|
||||
}
|
||||
}
|
||||
52
vendor/github.com/containerd/ttrpc/config.go
generated
vendored
52
vendor/github.com/containerd/ttrpc/config.go
generated
vendored
@ -1,52 +0,0 @@
|
||||
/*
|
||||
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 ttrpc
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
|
||||
type serverConfig struct {
|
||||
handshaker Handshaker
|
||||
interceptor UnaryServerInterceptor
|
||||
}
|
||||
|
||||
// ServerOpt for configuring a ttrpc server
|
||||
type ServerOpt func(*serverConfig) error
|
||||
|
||||
// WithServerHandshaker can be passed to NewServer to ensure that the
|
||||
// handshaker is called before every connection attempt.
|
||||
//
|
||||
// Only one handshaker is allowed per server.
|
||||
func WithServerHandshaker(handshaker Handshaker) ServerOpt {
|
||||
return func(c *serverConfig) error {
|
||||
if c.handshaker != nil {
|
||||
return errors.New("only one handshaker allowed per server")
|
||||
}
|
||||
c.handshaker = handshaker
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithUnaryServerInterceptor sets the provided interceptor on the server
|
||||
func WithUnaryServerInterceptor(i UnaryServerInterceptor) ServerOpt {
|
||||
return func(c *serverConfig) error {
|
||||
if c.interceptor != nil {
|
||||
return errors.New("only one interceptor allowed per server")
|
||||
}
|
||||
c.interceptor = i
|
||||
return nil
|
||||
}
|
||||
}
|
||||
50
vendor/github.com/containerd/ttrpc/handshake.go
generated
vendored
50
vendor/github.com/containerd/ttrpc/handshake.go
generated
vendored
@ -1,50 +0,0 @@
|
||||
/*
|
||||
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 ttrpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Handshaker defines the interface for connection handshakes performed on the
|
||||
// server or client when first connecting.
|
||||
type Handshaker interface {
|
||||
// Handshake should confirm or decorate a connection that may be incoming
|
||||
// to a server or outgoing from a client.
|
||||
//
|
||||
// If this returns without an error, the caller should use the connection
|
||||
// in place of the original connection.
|
||||
//
|
||||
// The second return value can contain credential specific data, such as
|
||||
// unix socket credentials or TLS information.
|
||||
//
|
||||
// While we currently only have implementations on the server-side, this
|
||||
// interface should be sufficient to implement similar handshakes on the
|
||||
// client-side.
|
||||
Handshake(ctx context.Context, conn net.Conn) (net.Conn, interface{}, error)
|
||||
}
|
||||
|
||||
type handshakerFunc func(ctx context.Context, conn net.Conn) (net.Conn, interface{}, error)
|
||||
|
||||
func (fn handshakerFunc) Handshake(ctx context.Context, conn net.Conn) (net.Conn, interface{}, error) {
|
||||
return fn(ctx, conn)
|
||||
}
|
||||
|
||||
func noopHandshake(ctx context.Context, conn net.Conn) (net.Conn, interface{}, error) {
|
||||
return conn, nil, nil
|
||||
}
|
||||
50
vendor/github.com/containerd/ttrpc/interceptor.go
generated
vendored
50
vendor/github.com/containerd/ttrpc/interceptor.go
generated
vendored
@ -1,50 +0,0 @@
|
||||
/*
|
||||
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 ttrpc
|
||||
|
||||
import "context"
|
||||
|
||||
// UnaryServerInfo provides information about the server request
|
||||
type UnaryServerInfo struct {
|
||||
FullMethod string
|
||||
}
|
||||
|
||||
// UnaryClientInfo provides information about the client request
|
||||
type UnaryClientInfo struct {
|
||||
FullMethod string
|
||||
}
|
||||
|
||||
// Unmarshaler contains the server request data and allows it to be unmarshaled
|
||||
// into a concrete type
|
||||
type Unmarshaler func(interface{}) error
|
||||
|
||||
// Invoker invokes the client's request and response from the ttrpc server
|
||||
type Invoker func(context.Context, *Request, *Response) error
|
||||
|
||||
// UnaryServerInterceptor specifies the interceptor function for server request/response
|
||||
type UnaryServerInterceptor func(context.Context, Unmarshaler, *UnaryServerInfo, Method) (interface{}, error)
|
||||
|
||||
// UnaryClientInterceptor specifies the interceptor function for client request/response
|
||||
type UnaryClientInterceptor func(context.Context, *Request, *Response, *UnaryClientInfo, Invoker) error
|
||||
|
||||
func defaultServerInterceptor(ctx context.Context, unmarshal Unmarshaler, info *UnaryServerInfo, method Method) (interface{}, error) {
|
||||
return method(ctx, unmarshal)
|
||||
}
|
||||
|
||||
func defaultClientInterceptor(ctx context.Context, req *Request, resp *Response, _ *UnaryClientInfo, invoker Invoker) error {
|
||||
return invoker(ctx, req, resp)
|
||||
}
|
||||
107
vendor/github.com/containerd/ttrpc/metadata.go
generated
vendored
107
vendor/github.com/containerd/ttrpc/metadata.go
generated
vendored
@ -1,107 +0,0 @@
|
||||
/*
|
||||
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 ttrpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// MD is the user type for ttrpc metadata
|
||||
type MD map[string][]string
|
||||
|
||||
// Get returns the metadata for a given key when they exist.
|
||||
// If there is no metadata, a nil slice and false are returned.
|
||||
func (m MD) Get(key string) ([]string, bool) {
|
||||
key = strings.ToLower(key)
|
||||
list, ok := m[key]
|
||||
if !ok || len(list) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return list, true
|
||||
}
|
||||
|
||||
// Set sets the provided values for a given key.
|
||||
// The values will overwrite any existing values.
|
||||
// If no values provided, a key will be deleted.
|
||||
func (m MD) Set(key string, values ...string) {
|
||||
key = strings.ToLower(key)
|
||||
if len(values) == 0 {
|
||||
delete(m, key)
|
||||
return
|
||||
}
|
||||
m[key] = values
|
||||
}
|
||||
|
||||
// Append appends additional values to the given key.
|
||||
func (m MD) Append(key string, values ...string) {
|
||||
key = strings.ToLower(key)
|
||||
if len(values) == 0 {
|
||||
return
|
||||
}
|
||||
current, ok := m[key]
|
||||
if ok {
|
||||
m.Set(key, append(current, values...)...)
|
||||
} else {
|
||||
m.Set(key, values...)
|
||||
}
|
||||
}
|
||||
|
||||
func (m MD) setRequest(r *Request) {
|
||||
for k, values := range m {
|
||||
for _, v := range values {
|
||||
r.Metadata = append(r.Metadata, &KeyValue{
|
||||
Key: k,
|
||||
Value: v,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m MD) fromRequest(r *Request) {
|
||||
for _, kv := range r.Metadata {
|
||||
m[kv.Key] = append(m[kv.Key], kv.Value)
|
||||
}
|
||||
}
|
||||
|
||||
type metadataKey struct{}
|
||||
|
||||
// GetMetadata retrieves metadata from context.Context (previously attached with WithMetadata)
|
||||
func GetMetadata(ctx context.Context) (MD, bool) {
|
||||
metadata, ok := ctx.Value(metadataKey{}).(MD)
|
||||
return metadata, ok
|
||||
}
|
||||
|
||||
// GetMetadataValue gets a specific metadata value by name from context.Context
|
||||
func GetMetadataValue(ctx context.Context, name string) (string, bool) {
|
||||
metadata, ok := GetMetadata(ctx)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
|
||||
if list, ok := metadata.Get(name); ok {
|
||||
return list[0], true
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
||||
// WithMetadata attaches metadata map to a context.Context
|
||||
func WithMetadata(ctx context.Context, md MD) context.Context {
|
||||
return context.WithValue(ctx, metadataKey{}, md)
|
||||
}
|
||||
485
vendor/github.com/containerd/ttrpc/server.go
generated
vendored
485
vendor/github.com/containerd/ttrpc/server.go
generated
vendored
@ -1,485 +0,0 @@
|
||||
/*
|
||||
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 ttrpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrServerClosed = errors.New("ttrpc: server closed")
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
config *serverConfig
|
||||
services *serviceSet
|
||||
codec codec
|
||||
|
||||
mu sync.Mutex
|
||||
listeners map[net.Listener]struct{}
|
||||
connections map[*serverConn]struct{} // all connections to current state
|
||||
done chan struct{} // marks point at which we stop serving requests
|
||||
}
|
||||
|
||||
func NewServer(opts ...ServerOpt) (*Server, error) {
|
||||
config := &serverConfig{}
|
||||
for _, opt := range opts {
|
||||
if err := opt(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if config.interceptor == nil {
|
||||
config.interceptor = defaultServerInterceptor
|
||||
}
|
||||
|
||||
return &Server{
|
||||
config: config,
|
||||
services: newServiceSet(config.interceptor),
|
||||
done: make(chan struct{}),
|
||||
listeners: make(map[net.Listener]struct{}),
|
||||
connections: make(map[*serverConn]struct{}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) Register(name string, methods map[string]Method) {
|
||||
s.services.register(name, methods)
|
||||
}
|
||||
|
||||
func (s *Server) Serve(ctx context.Context, l net.Listener) error {
|
||||
s.addListener(l)
|
||||
defer s.closeListener(l)
|
||||
|
||||
var (
|
||||
backoff time.Duration
|
||||
handshaker = s.config.handshaker
|
||||
)
|
||||
|
||||
if handshaker == nil {
|
||||
handshaker = handshakerFunc(noopHandshake)
|
||||
}
|
||||
|
||||
for {
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
select {
|
||||
case <-s.done:
|
||||
return ErrServerClosed
|
||||
default:
|
||||
}
|
||||
|
||||
if terr, ok := err.(interface {
|
||||
Temporary() bool
|
||||
}); ok && terr.Temporary() {
|
||||
if backoff == 0 {
|
||||
backoff = time.Millisecond
|
||||
} else {
|
||||
backoff *= 2
|
||||
}
|
||||
|
||||
if max := time.Second; backoff > max {
|
||||
backoff = max
|
||||
}
|
||||
|
||||
sleep := time.Duration(rand.Int63n(int64(backoff)))
|
||||
logrus.WithError(err).Errorf("ttrpc: failed accept; backoff %v", sleep)
|
||||
time.Sleep(sleep)
|
||||
continue
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
backoff = 0
|
||||
|
||||
approved, handshake, err := handshaker.Handshake(ctx, conn)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Errorf("ttrpc: refusing connection after handshake")
|
||||
conn.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
sc := s.newConn(approved, handshake)
|
||||
go sc.run(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Shutdown(ctx context.Context) error {
|
||||
s.mu.Lock()
|
||||
select {
|
||||
case <-s.done:
|
||||
default:
|
||||
// protected by mutex
|
||||
close(s.done)
|
||||
}
|
||||
lnerr := s.closeListeners()
|
||||
s.mu.Unlock()
|
||||
|
||||
ticker := time.NewTicker(200 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
if s.closeIdleConns() {
|
||||
return lnerr
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-ticker.C:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close the server without waiting for active connections.
|
||||
func (s *Server) Close() error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
select {
|
||||
case <-s.done:
|
||||
default:
|
||||
// protected by mutex
|
||||
close(s.done)
|
||||
}
|
||||
|
||||
err := s.closeListeners()
|
||||
for c := range s.connections {
|
||||
c.close()
|
||||
delete(s.connections, c)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Server) addListener(l net.Listener) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.listeners[l] = struct{}{}
|
||||
}
|
||||
|
||||
func (s *Server) closeListener(l net.Listener) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
return s.closeListenerLocked(l)
|
||||
}
|
||||
|
||||
func (s *Server) closeListenerLocked(l net.Listener) error {
|
||||
defer delete(s.listeners, l)
|
||||
return l.Close()
|
||||
}
|
||||
|
||||
func (s *Server) closeListeners() error {
|
||||
var err error
|
||||
for l := range s.listeners {
|
||||
if cerr := s.closeListenerLocked(l); cerr != nil && err == nil {
|
||||
err = cerr
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Server) addConnection(c *serverConn) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
s.connections[c] = struct{}{}
|
||||
}
|
||||
|
||||
func (s *Server) closeIdleConns() bool {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
quiescent := true
|
||||
for c := range s.connections {
|
||||
st, ok := c.getState()
|
||||
if !ok || st != connStateIdle {
|
||||
quiescent = false
|
||||
continue
|
||||
}
|
||||
c.close()
|
||||
delete(s.connections, c)
|
||||
}
|
||||
return quiescent
|
||||
}
|
||||
|
||||
type connState int
|
||||
|
||||
const (
|
||||
connStateActive = iota + 1 // outstanding requests
|
||||
connStateIdle // no requests
|
||||
connStateClosed // closed connection
|
||||
)
|
||||
|
||||
func (cs connState) String() string {
|
||||
switch cs {
|
||||
case connStateActive:
|
||||
return "active"
|
||||
case connStateIdle:
|
||||
return "idle"
|
||||
case connStateClosed:
|
||||
return "closed"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) newConn(conn net.Conn, handshake interface{}) *serverConn {
|
||||
c := &serverConn{
|
||||
server: s,
|
||||
conn: conn,
|
||||
handshake: handshake,
|
||||
shutdown: make(chan struct{}),
|
||||
}
|
||||
c.setState(connStateIdle)
|
||||
s.addConnection(c)
|
||||
return c
|
||||
}
|
||||
|
||||
type serverConn struct {
|
||||
server *Server
|
||||
conn net.Conn
|
||||
handshake interface{} // data from handshake, not used for now
|
||||
state atomic.Value
|
||||
|
||||
shutdownOnce sync.Once
|
||||
shutdown chan struct{} // forced shutdown, used by close
|
||||
}
|
||||
|
||||
func (c *serverConn) getState() (connState, bool) {
|
||||
cs, ok := c.state.Load().(connState)
|
||||
return cs, ok
|
||||
}
|
||||
|
||||
func (c *serverConn) setState(newstate connState) {
|
||||
c.state.Store(newstate)
|
||||
}
|
||||
|
||||
func (c *serverConn) close() error {
|
||||
c.shutdownOnce.Do(func() {
|
||||
close(c.shutdown)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *serverConn) run(sctx context.Context) {
|
||||
type (
|
||||
request struct {
|
||||
id uint32
|
||||
req *Request
|
||||
}
|
||||
|
||||
response struct {
|
||||
id uint32
|
||||
resp *Response
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
ch = newChannel(c.conn)
|
||||
ctx, cancel = context.WithCancel(sctx)
|
||||
active int
|
||||
state connState = connStateIdle
|
||||
responses = make(chan response)
|
||||
requests = make(chan request)
|
||||
recvErr = make(chan error, 1)
|
||||
shutdown = c.shutdown
|
||||
done = make(chan struct{})
|
||||
)
|
||||
|
||||
defer c.conn.Close()
|
||||
defer cancel()
|
||||
defer close(done)
|
||||
|
||||
go func(recvErr chan error) {
|
||||
defer close(recvErr)
|
||||
sendImmediate := func(id uint32, st *status.Status) bool {
|
||||
select {
|
||||
case responses <- response{
|
||||
// even though we've had an invalid stream id, we send it
|
||||
// back on the same stream id so the client knows which
|
||||
// stream id was bad.
|
||||
id: id,
|
||||
resp: &Response{
|
||||
Status: st.Proto(),
|
||||
},
|
||||
}:
|
||||
return true
|
||||
case <-c.shutdown:
|
||||
return false
|
||||
case <-done:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-c.shutdown:
|
||||
return
|
||||
case <-done:
|
||||
return
|
||||
default: // proceed
|
||||
}
|
||||
|
||||
mh, p, err := ch.recv()
|
||||
if err != nil {
|
||||
status, ok := status.FromError(err)
|
||||
if !ok {
|
||||
recvErr <- err
|
||||
return
|
||||
}
|
||||
|
||||
// in this case, we send an error for that particular message
|
||||
// when the status is defined.
|
||||
if !sendImmediate(mh.StreamID, status) {
|
||||
return
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if mh.Type != messageTypeRequest {
|
||||
// we must ignore this for future compat.
|
||||
continue
|
||||
}
|
||||
|
||||
var req Request
|
||||
if err := c.server.codec.Unmarshal(p, &req); err != nil {
|
||||
ch.putmbuf(p)
|
||||
if !sendImmediate(mh.StreamID, status.Newf(codes.InvalidArgument, "unmarshal request error: %v", err)) {
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
ch.putmbuf(p)
|
||||
|
||||
if mh.StreamID%2 != 1 {
|
||||
// enforce odd client initiated identifiers.
|
||||
if !sendImmediate(mh.StreamID, status.Newf(codes.InvalidArgument, "StreamID must be odd for client initiated streams")) {
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Forward the request to the main loop. We don't wait on s.done
|
||||
// because we have already accepted the client request.
|
||||
select {
|
||||
case requests <- request{
|
||||
id: mh.StreamID,
|
||||
req: &req,
|
||||
}:
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}(recvErr)
|
||||
|
||||
for {
|
||||
newstate := state
|
||||
switch {
|
||||
case active > 0:
|
||||
newstate = connStateActive
|
||||
shutdown = nil
|
||||
case active == 0:
|
||||
newstate = connStateIdle
|
||||
shutdown = c.shutdown // only enable this branch in idle mode
|
||||
}
|
||||
|
||||
if newstate != state {
|
||||
c.setState(newstate)
|
||||
state = newstate
|
||||
}
|
||||
|
||||
select {
|
||||
case request := <-requests:
|
||||
active++
|
||||
go func(id uint32) {
|
||||
ctx, cancel := getRequestContext(ctx, request.req)
|
||||
defer cancel()
|
||||
|
||||
p, status := c.server.services.call(ctx, request.req.Service, request.req.Method, request.req.Payload)
|
||||
resp := &Response{
|
||||
Status: status.Proto(),
|
||||
Payload: p,
|
||||
}
|
||||
|
||||
select {
|
||||
case responses <- response{
|
||||
id: id,
|
||||
resp: resp,
|
||||
}:
|
||||
case <-done:
|
||||
}
|
||||
}(request.id)
|
||||
case response := <-responses:
|
||||
p, err := c.server.codec.Marshal(response.resp)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("failed marshaling response")
|
||||
return
|
||||
}
|
||||
|
||||
if err := ch.send(response.id, messageTypeResponse, p); err != nil {
|
||||
logrus.WithError(err).Error("failed sending message on channel")
|
||||
return
|
||||
}
|
||||
|
||||
active--
|
||||
case err := <-recvErr:
|
||||
// TODO(stevvooe): Not wildly clear what we should do in this
|
||||
// branch. Basically, it means that we are no longer receiving
|
||||
// requests due to a terminal error.
|
||||
recvErr = nil // connection is now "closing"
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||
// The client went away and we should stop processing
|
||||
// requests, so that the client connection is closed
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("error receiving message")
|
||||
}
|
||||
case <-shutdown:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var noopFunc = func() {}
|
||||
|
||||
func getRequestContext(ctx context.Context, req *Request) (retCtx context.Context, cancel func()) {
|
||||
if len(req.Metadata) > 0 {
|
||||
md := MD{}
|
||||
md.fromRequest(req)
|
||||
ctx = WithMetadata(ctx, md)
|
||||
}
|
||||
|
||||
cancel = noopFunc
|
||||
if req.TimeoutNano == 0 {
|
||||
return ctx, cancel
|
||||
}
|
||||
|
||||
ctx, cancel = context.WithTimeout(ctx, time.Duration(req.TimeoutNano))
|
||||
return ctx, cancel
|
||||
}
|
||||
156
vendor/github.com/containerd/ttrpc/services.go
generated
vendored
156
vendor/github.com/containerd/ttrpc/services.go
generated
vendored
@ -1,156 +0,0 @@
|
||||
/*
|
||||
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 ttrpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
type Method func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error)
|
||||
|
||||
type ServiceDesc struct {
|
||||
Methods map[string]Method
|
||||
|
||||
// TODO(stevvooe): Add stream support.
|
||||
}
|
||||
|
||||
type serviceSet struct {
|
||||
services map[string]ServiceDesc
|
||||
interceptor UnaryServerInterceptor
|
||||
}
|
||||
|
||||
func newServiceSet(interceptor UnaryServerInterceptor) *serviceSet {
|
||||
return &serviceSet{
|
||||
services: make(map[string]ServiceDesc),
|
||||
interceptor: interceptor,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *serviceSet) register(name string, methods map[string]Method) {
|
||||
if _, ok := s.services[name]; ok {
|
||||
panic(errors.Errorf("duplicate service %v registered", name))
|
||||
}
|
||||
|
||||
s.services[name] = ServiceDesc{
|
||||
Methods: methods,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *serviceSet) call(ctx context.Context, serviceName, methodName string, p []byte) ([]byte, *status.Status) {
|
||||
p, err := s.dispatch(ctx, serviceName, methodName, p)
|
||||
st, ok := status.FromError(err)
|
||||
if !ok {
|
||||
st = status.New(convertCode(err), err.Error())
|
||||
}
|
||||
|
||||
return p, st
|
||||
}
|
||||
|
||||
func (s *serviceSet) dispatch(ctx context.Context, serviceName, methodName string, p []byte) ([]byte, error) {
|
||||
method, err := s.resolve(serviceName, methodName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
unmarshal := func(obj interface{}) error {
|
||||
switch v := obj.(type) {
|
||||
case proto.Message:
|
||||
if err := proto.Unmarshal(p, v); err != nil {
|
||||
return status.Errorf(codes.Internal, "ttrpc: error unmarshalling payload: %v", err.Error())
|
||||
}
|
||||
default:
|
||||
return status.Errorf(codes.Internal, "ttrpc: error unsupported request type: %T", v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
info := &UnaryServerInfo{
|
||||
FullMethod: fullPath(serviceName, methodName),
|
||||
}
|
||||
|
||||
resp, err := s.interceptor(ctx, unmarshal, info, method)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch v := resp.(type) {
|
||||
case proto.Message:
|
||||
r, err := proto.Marshal(v)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "ttrpc: error marshaling payload: %v", err.Error())
|
||||
}
|
||||
|
||||
return r, nil
|
||||
default:
|
||||
return nil, status.Errorf(codes.Internal, "ttrpc: error unsupported response type: %T", v)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *serviceSet) resolve(service, method string) (Method, error) {
|
||||
srv, ok := s.services[service]
|
||||
if !ok {
|
||||
return nil, status.Errorf(codes.NotFound, "service %v", service)
|
||||
}
|
||||
|
||||
mthd, ok := srv.Methods[method]
|
||||
if !ok {
|
||||
return nil, status.Errorf(codes.NotFound, "method %v", method)
|
||||
}
|
||||
|
||||
return mthd, nil
|
||||
}
|
||||
|
||||
// convertCode maps stdlib go errors into grpc space.
|
||||
//
|
||||
// This is ripped from the grpc-go code base.
|
||||
func convertCode(err error) codes.Code {
|
||||
switch err {
|
||||
case nil:
|
||||
return codes.OK
|
||||
case io.EOF:
|
||||
return codes.OutOfRange
|
||||
case io.ErrClosedPipe, io.ErrNoProgress, io.ErrShortBuffer, io.ErrShortWrite, io.ErrUnexpectedEOF:
|
||||
return codes.FailedPrecondition
|
||||
case os.ErrInvalid:
|
||||
return codes.InvalidArgument
|
||||
case context.Canceled:
|
||||
return codes.Canceled
|
||||
case context.DeadlineExceeded:
|
||||
return codes.DeadlineExceeded
|
||||
}
|
||||
switch {
|
||||
case os.IsExist(err):
|
||||
return codes.AlreadyExists
|
||||
case os.IsNotExist(err):
|
||||
return codes.NotFound
|
||||
case os.IsPermission(err):
|
||||
return codes.PermissionDenied
|
||||
}
|
||||
return codes.Unknown
|
||||
}
|
||||
|
||||
func fullPath(service, method string) string {
|
||||
return "/" + path.Join(service, method)
|
||||
}
|
||||
63
vendor/github.com/containerd/ttrpc/types.go
generated
vendored
63
vendor/github.com/containerd/ttrpc/types.go
generated
vendored
@ -1,63 +0,0 @@
|
||||
/*
|
||||
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 ttrpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
spb "google.golang.org/genproto/googleapis/rpc/status"
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
Service string `protobuf:"bytes,1,opt,name=service,proto3"`
|
||||
Method string `protobuf:"bytes,2,opt,name=method,proto3"`
|
||||
Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3"`
|
||||
TimeoutNano int64 `protobuf:"varint,4,opt,name=timeout_nano,proto3"`
|
||||
Metadata []*KeyValue `protobuf:"bytes,5,rep,name=metadata,proto3"`
|
||||
}
|
||||
|
||||
func (r *Request) Reset() { *r = Request{} }
|
||||
func (r *Request) String() string { return fmt.Sprintf("%+#v", r) }
|
||||
func (r *Request) ProtoMessage() {}
|
||||
|
||||
type Response struct {
|
||||
Status *spb.Status `protobuf:"bytes,1,opt,name=status,proto3"`
|
||||
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3"`
|
||||
}
|
||||
|
||||
func (r *Response) Reset() { *r = Response{} }
|
||||
func (r *Response) String() string { return fmt.Sprintf("%+#v", r) }
|
||||
func (r *Response) ProtoMessage() {}
|
||||
|
||||
type StringList struct {
|
||||
List []string `protobuf:"bytes,1,rep,name=list,proto3"`
|
||||
}
|
||||
|
||||
func (r *StringList) Reset() { *r = StringList{} }
|
||||
func (r *StringList) String() string { return fmt.Sprintf("%+#v", r) }
|
||||
func (r *StringList) ProtoMessage() {}
|
||||
|
||||
func makeStringList(item ...string) StringList { return StringList{List: item} }
|
||||
|
||||
type KeyValue struct {
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3"`
|
||||
Value string `protobuf:"bytes,2,opt,name=value,proto3"`
|
||||
}
|
||||
|
||||
func (m *KeyValue) Reset() { *m = KeyValue{} }
|
||||
func (*KeyValue) ProtoMessage() {}
|
||||
func (m *KeyValue) String() string { return fmt.Sprintf("%+#v", m) }
|
||||
108
vendor/github.com/containerd/ttrpc/unixcreds_linux.go
generated
vendored
108
vendor/github.com/containerd/ttrpc/unixcreds_linux.go
generated
vendored
@ -1,108 +0,0 @@
|
||||
/*
|
||||
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 ttrpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type UnixCredentialsFunc func(*unix.Ucred) error
|
||||
|
||||
func (fn UnixCredentialsFunc) Handshake(ctx context.Context, conn net.Conn) (net.Conn, interface{}, error) {
|
||||
uc, err := requireUnixSocket(conn)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "ttrpc.UnixCredentialsFunc: require unix socket")
|
||||
}
|
||||
|
||||
rs, err := uc.SyscallConn()
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "ttrpc.UnixCredentialsFunc: (net.UnixConn).SyscallConn failed")
|
||||
}
|
||||
var (
|
||||
ucred *unix.Ucred
|
||||
ucredErr error
|
||||
)
|
||||
if err := rs.Control(func(fd uintptr) {
|
||||
ucred, ucredErr = unix.GetsockoptUcred(int(fd), unix.SOL_SOCKET, unix.SO_PEERCRED)
|
||||
}); err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "ttrpc.UnixCredentialsFunc: (*syscall.RawConn).Control failed")
|
||||
}
|
||||
|
||||
if ucredErr != nil {
|
||||
return nil, nil, errors.Wrapf(err, "ttrpc.UnixCredentialsFunc: failed to retrieve socket peer credentials")
|
||||
}
|
||||
|
||||
if err := fn(ucred); err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "ttrpc.UnixCredentialsFunc: credential check failed")
|
||||
}
|
||||
|
||||
return uc, ucred, nil
|
||||
}
|
||||
|
||||
// UnixSocketRequireUidGid requires specific *effective* UID/GID, rather than the real UID/GID.
|
||||
//
|
||||
// For example, if a daemon binary is owned by the root (UID 0) with SUID bit but running as an
|
||||
// unprivileged user (UID 1001), the effective UID becomes 0, and the real UID becomes 1001.
|
||||
// So calling this function with uid=0 allows a connection from effective UID 0 but rejects
|
||||
// a connection from effective UID 1001.
|
||||
//
|
||||
// See socket(7), SO_PEERCRED: "The returned credentials are those that were in effect at the time of the call to connect(2) or socketpair(2)."
|
||||
func UnixSocketRequireUidGid(uid, gid int) UnixCredentialsFunc {
|
||||
return func(ucred *unix.Ucred) error {
|
||||
return requireUidGid(ucred, uid, gid)
|
||||
}
|
||||
}
|
||||
|
||||
func UnixSocketRequireRoot() UnixCredentialsFunc {
|
||||
return UnixSocketRequireUidGid(0, 0)
|
||||
}
|
||||
|
||||
// UnixSocketRequireSameUser resolves the current effective unix user and returns a
|
||||
// UnixCredentialsFunc that will validate incoming unix connections against the
|
||||
// current credentials.
|
||||
//
|
||||
// This is useful when using abstract sockets that are accessible by all users.
|
||||
func UnixSocketRequireSameUser() UnixCredentialsFunc {
|
||||
euid, egid := os.Geteuid(), os.Getegid()
|
||||
return UnixSocketRequireUidGid(euid, egid)
|
||||
}
|
||||
|
||||
func requireRoot(ucred *unix.Ucred) error {
|
||||
return requireUidGid(ucred, 0, 0)
|
||||
}
|
||||
|
||||
func requireUidGid(ucred *unix.Ucred, uid, gid int) error {
|
||||
if (uid != -1 && uint32(uid) != ucred.Uid) || (gid != -1 && uint32(gid) != ucred.Gid) {
|
||||
return errors.Wrap(syscall.EPERM, "ttrpc: invalid credentials")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func requireUnixSocket(conn net.Conn) (*net.UnixConn, error) {
|
||||
uc, ok := conn.(*net.UnixConn)
|
||||
if !ok {
|
||||
return nil, errors.New("a unix socket connection is required")
|
||||
}
|
||||
|
||||
return uc, nil
|
||||
}
|
||||
Reference in New Issue
Block a user