github.com/MaximeAubanel/moby@v1.13.1/libcontainerd/client_unix.go (about)

     1  // +build linux solaris
     2  
     3  package libcontainerd
     4  
     5  import (
     6  	"encoding/json"
     7  	"fmt"
     8  	"os"
     9  	"path/filepath"
    10  	"strings"
    11  	"sync"
    12  
    13  	"github.com/Sirupsen/logrus"
    14  	containerd "github.com/docker/containerd/api/grpc/types"
    15  	"github.com/docker/docker/pkg/idtools"
    16  	specs "github.com/opencontainers/runtime-spec/specs-go"
    17  	"golang.org/x/net/context"
    18  )
    19  
    20  func (clnt *client) prepareBundleDir(uid, gid int) (string, error) {
    21  	root, err := filepath.Abs(clnt.remote.stateDir)
    22  	if err != nil {
    23  		return "", err
    24  	}
    25  	if uid == 0 && gid == 0 {
    26  		return root, nil
    27  	}
    28  	p := string(filepath.Separator)
    29  	for _, d := range strings.Split(root, string(filepath.Separator))[1:] {
    30  		p = filepath.Join(p, d)
    31  		fi, err := os.Stat(p)
    32  		if err != nil && !os.IsNotExist(err) {
    33  			return "", err
    34  		}
    35  		if os.IsNotExist(err) || fi.Mode()&1 == 0 {
    36  			p = fmt.Sprintf("%s.%d.%d", p, uid, gid)
    37  			if err := idtools.MkdirAs(p, 0700, uid, gid); err != nil && !os.IsExist(err) {
    38  				return "", err
    39  			}
    40  		}
    41  	}
    42  	return p, nil
    43  }
    44  
    45  func (clnt *client) Create(containerID string, checkpoint string, checkpointDir string, spec specs.Spec, attachStdio StdioCallback, options ...CreateOption) (err error) {
    46  	clnt.lock(containerID)
    47  	defer clnt.unlock(containerID)
    48  
    49  	if _, err := clnt.getContainer(containerID); err == nil {
    50  		return fmt.Errorf("Container %s is already active", containerID)
    51  	}
    52  
    53  	uid, gid, err := getRootIDs(specs.Spec(spec))
    54  	if err != nil {
    55  		return err
    56  	}
    57  	dir, err := clnt.prepareBundleDir(uid, gid)
    58  	if err != nil {
    59  		return err
    60  	}
    61  
    62  	container := clnt.newContainer(filepath.Join(dir, containerID), options...)
    63  	if err := container.clean(); err != nil {
    64  		return err
    65  	}
    66  
    67  	defer func() {
    68  		if err != nil {
    69  			container.clean()
    70  			clnt.deleteContainer(containerID)
    71  		}
    72  	}()
    73  
    74  	if err := idtools.MkdirAllAs(container.dir, 0700, uid, gid); err != nil && !os.IsExist(err) {
    75  		return err
    76  	}
    77  
    78  	f, err := os.Create(filepath.Join(container.dir, configFilename))
    79  	if err != nil {
    80  		return err
    81  	}
    82  	defer f.Close()
    83  	if err := json.NewEncoder(f).Encode(spec); err != nil {
    84  		return err
    85  	}
    86  
    87  	return container.start(checkpoint, checkpointDir, attachStdio)
    88  }
    89  
    90  func (clnt *client) Signal(containerID string, sig int) error {
    91  	clnt.lock(containerID)
    92  	defer clnt.unlock(containerID)
    93  	_, err := clnt.remote.apiClient.Signal(context.Background(), &containerd.SignalRequest{
    94  		Id:     containerID,
    95  		Pid:    InitFriendlyName,
    96  		Signal: uint32(sig),
    97  	})
    98  	return err
    99  }
   100  
   101  func (clnt *client) newContainer(dir string, options ...CreateOption) *container {
   102  	container := &container{
   103  		containerCommon: containerCommon{
   104  			process: process{
   105  				dir: dir,
   106  				processCommon: processCommon{
   107  					containerID:  filepath.Base(dir),
   108  					client:       clnt,
   109  					friendlyName: InitFriendlyName,
   110  				},
   111  			},
   112  			processes: make(map[string]*process),
   113  		},
   114  	}
   115  	for _, option := range options {
   116  		if err := option.Apply(container); err != nil {
   117  			logrus.Errorf("libcontainerd: newContainer(): %v", err)
   118  		}
   119  	}
   120  	return container
   121  }
   122  
   123  type exitNotifier struct {
   124  	id     string
   125  	client *client
   126  	c      chan struct{}
   127  	once   sync.Once
   128  }
   129  
   130  func (en *exitNotifier) close() {
   131  	en.once.Do(func() {
   132  		close(en.c)
   133  		en.client.mapMutex.Lock()
   134  		if en == en.client.exitNotifiers[en.id] {
   135  			delete(en.client.exitNotifiers, en.id)
   136  		}
   137  		en.client.mapMutex.Unlock()
   138  	})
   139  }
   140  func (en *exitNotifier) wait() <-chan struct{} {
   141  	return en.c
   142  }