<commit_before>package containerd

import (
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/containerd/containerd"
	"github.com/containerd/containerd/api/services/execution"
	"github.com/containerd/containerd/api/types/task"
	dockermount "github.com/docker/docker/pkg/mount"
	"github.com/docker/swarmkit/agent/exec"
	"github.com/docker/swarmkit/api"
	"github.com/docker/swarmkit/api/naming"
	"github.com/docker/swarmkit/log"
	"github.com/opencontainers/runtime-spec/specs-go"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
)

var (
	devNull                    *os.File
	errAdapterNotPrepared      = errors.New("container adapter not prepared")
	mountPropagationReverseMap = map[api.Mount_BindOptions_MountPropagation]string{
		api.MountPropagationPrivate:  "private",
		api.MountPropagationRPrivate: "rprivate",
		api.MountPropagationShared:   "shared",
		api.MountPropagationRShared:  "rshared",
		api.MountPropagationRSlave:   "slave",
		api.MountPropagationSlave:    "rslave",
	}
)

// containerAdapter conducts remote operations for a container. All calls
// are mostly naked calls to the client API, seeded with information from
// containerConfig.
type containerAdapter struct {
	client         *containerd.Client
	spec           *api.ContainerSpec
	secrets        exec.SecretGetter
	name           string
	image          containerd.Image // Pulled image
	container      containerd.Container
	task           containerd.Task
	deleteResponse *execution.DeleteResponse
}

func newContainerAdapter(client *containerd.Client, task *api.Task, secrets exec.SecretGetter) (*containerAdapter, error) {
	spec := task.Spec.GetContainer()
	if spec == nil {
		return nil, exec.ErrRuntimeUnsupported
	}

	c := &containerAdapter{
		client:  client,
		spec:    spec,
		secrets: secrets,
		name:    naming.Task(task),
	}

	if err := c.reattach(context.Background()); err != nil {
		return nil, err
	}

	return c, nil
}

// reattaches to an existing container. If the container is found but
// the task is missing then still succeeds, allowing subsequent use of
// c.delete()
func (c *containerAdapter) reattach(ctx context.Context) error {
	container, err := c.client.LoadContainer(ctx, c.name)
	if err != nil {
		if grpc.Code(err) == codes.NotFound {
			c.log(ctx).Debug("reattach: container not found")
			return nil
		}

		return errors.Wrap(err, "reattach: loading container")
	}
	c.log(ctx).Debug("reattach: loaded container")
	c.container = container

	// TODO(ijc) Consider an addition to container library which
	// directly attaches stdin to /dev/null.
	if devNull == nil {
		if devNull, err = os.Open(os.DevNull); err != nil {
			return errors.Wrap(err, "reattach: opening null device")
		}
	}

	task, err := container.Task(ctx, containerd.WithAttach(devNull, os.Stdout, os.Stderr))
	if err != nil {
		if err == containerd.ErrNoRunningTask {
			c.log(ctx).WithError(err).Info("reattach: no running task")
			return nil
		}
		return errors.Wrap(err, "reattach: reattaching task")
	}
	c.task = task
	c.log(ctx).Debug("reattach: successful")
	return nil
}

func (c *containerAdapter) log(ctx context.Context) *logrus.Entry {
	return log.G(ctx).WithFields(logrus.Fields{
		"ID": c.name,
	})
}

func (c *containerAdapter) pullImage(ctx context.Context) error {
	image, err := c.client.Pull(ctx, c.spec.Image, containerd.WithPullUnpack)
	if err != nil {
		return errors.Wrap(err, "pulling container image")
	}
	c.image = image

	return nil
}

func withMounts(ctx context.Context, ms []api.Mount) containerd.SpecOpts {
	sort.Sort(mounts(ms))

	return func(s *specs.Spec) error {
		for _, m := range ms {
			if !filepath.IsAbs(m.Target) {
				return errors.Errorf("mount %s is not absolute", m.Target)
			}

			switch m.Type {
			case api.MountTypeTmpfs:
				opts := []string{"noexec", "nosuid", "nodev", "rprivate"}
				if m.TmpfsOptions != nil {
					if m.TmpfsOptions.SizeBytes <= 0 {<commit_msg>containerd: log tag which fits in with the others<commit_after>package containerd

import (
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/containerd/containerd"
	"github.com/containerd/containerd/api/services/execution"
	"github.com/containerd/containerd/api/types/task"
	dockermount "github.com/docker/docker/pkg/mount"
	"github.com/docker/swarmkit/agent/exec"
	"github.com/docker/swarmkit/api"
	"github.com/docker/swarmkit/api/naming"
	"github.com/docker/swarmkit/log"
	"github.com/opencontainers/runtime-spec/specs-go"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
)

var (
	devNull                    *os.File
	errAdapterNotPrepared      = errors.New("container adapter not prepared")
	mountPropagationReverseMap = map[api.Mount_BindOptions_MountPropagation]string{
		api.MountPropagationPrivate:  "private",
		api.MountPropagationRPrivate: "rprivate",
		api.MountPropagationShared:   "shared",
		api.MountPropagationRShared:  "rshared",
		api.MountPropagationRSlave:   "slave",
		api.MountPropagationSlave:    "rslave",
	}
)

// containerAdapter conducts remote operations for a container. All calls
// are mostly naked calls to the client API, seeded with information from
// containerConfig.
type containerAdapter struct {
	client         *containerd.Client
	spec           *api.ContainerSpec
	secrets        exec.SecretGetter
	name           string
	image          containerd.Image // Pulled image
	container      containerd.Container
	task           containerd.Task
	deleteResponse *execution.DeleteResponse
}

func newContainerAdapter(client *containerd.Client, task *api.Task, secrets exec.SecretGetter) (*containerAdapter, error) {
	spec := task.Spec.GetContainer()
	if spec == nil {
		return nil, exec.ErrRuntimeUnsupported
	}

	c := &containerAdapter{
		client:  client,
		spec:    spec,
		secrets: secrets,
		name:    naming.Task(task),
	}

	if err := c.reattach(context.Background()); err != nil {
		return nil, err
	}

	return c, nil
}

// reattaches to an existing container. If the container is found but
// the task is missing then still succeeds, allowing subsequent use of
// c.delete()
func (c *containerAdapter) reattach(ctx context.Context) error {
	container, err := c.client.LoadContainer(ctx, c.name)
	if err != nil {
		if grpc.Code(err) == codes.NotFound {
			c.log(ctx).Debug("reattach: container not found")
			return nil
		}

		return errors.Wrap(err, "reattach: loading container")
	}
	c.log(ctx).Debug("reattach: loaded container")
	c.container = container

	// TODO(ijc) Consider an addition to container library which
	// directly attaches stdin to /dev/null.
	if devNull == nil {
		if devNull, err = os.Open(os.DevNull); err != nil {
			return errors.Wrap(err, "reattach: opening null device")
		}
	}

	task, err := container.Task(ctx, containerd.WithAttach(devNull, os.Stdout, os.Stderr))
	if err != nil {
		if err == containerd.ErrNoRunningTask {
			c.log(ctx).WithError(err).Info("reattach: no running task")
			return nil
		}
		return errors.Wrap(err, "reattach: reattaching task")
	}
	c.task = task
	c.log(ctx).Debug("reattach: successful")
	return nil
}

func (c *containerAdapter) log(ctx context.Context) *logrus.Entry {
	return log.G(ctx).WithFields(logrus.Fields{
		"container.id": c.name,
	})
}

func (c *containerAdapter) pullImage(ctx context.Context) error {
	image, err := c.client.Pull(ctx, c.spec.Image, containerd.WithPullUnpack)
	if err != nil {
		return errors.Wrap(err, "pulling container image")
	}
	c.image = image

	return nil
}

func withMounts(ctx context.Context, ms []api.Mount) containerd.SpecOpts {
	sort.Sort(mounts(ms))

	return func(s *specs.Spec) error {
		for _, m := range ms {
			if !filepath.IsAbs(m.Target) {
				return errors.Errorf("mount %s is not absolute", m.Target)
			}

			switch m.Type {
			case api.MountTypeTmpfs:
				opts := []string{"noexec", "nosuid", "nodev", "rprivate"}
				if m.TmpfsOptions != nil {
					if m.TmpfsOptions.SizeBytes <= 0 {
{'fraction_non_alphanumeric': 0.12630532073595227, 'fraction_numerical': 0.0002486325211337643, 'mean_word_length': 3.8522316043425815, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3606011', 'n_tokens_mistral': 2873, 'n_tokens_neox': 2726, 'n_words': 628}