mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 05:40:42 +00:00 
			
		
		
		
	godep restore pushd $GOPATH/src/github.com/appc/spec git co master popd go get go4.org/errorutil rm -rf Godeps godep save ./... git add vendor git add -f $(git ls-files --other vendor/) git co -- Godeps/LICENSES Godeps/.license_file_state Godeps/OWNERS
		
			
				
	
	
		
			286 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			286 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // +build linux
 | |
| 
 | |
| package libcontainer
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"os/exec"
 | |
| 	"path/filepath"
 | |
| 	"regexp"
 | |
| 	"strconv"
 | |
| 	"syscall"
 | |
| 
 | |
| 	"github.com/docker/docker/pkg/mount"
 | |
| 	"github.com/opencontainers/runc/libcontainer/cgroups"
 | |
| 	"github.com/opencontainers/runc/libcontainer/cgroups/fs"
 | |
| 	"github.com/opencontainers/runc/libcontainer/cgroups/systemd"
 | |
| 	"github.com/opencontainers/runc/libcontainer/configs"
 | |
| 	"github.com/opencontainers/runc/libcontainer/configs/validate"
 | |
| 	"github.com/opencontainers/runc/libcontainer/utils"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	stateFilename = "state.json"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	idRegex  = regexp.MustCompile(`^[\w_-]+$`)
 | |
| 	maxIdLen = 1024
 | |
| )
 | |
| 
 | |
| // InitArgs returns an options func to configure a LinuxFactory with the
 | |
| // provided init arguments.
 | |
| func InitArgs(args ...string) func(*LinuxFactory) error {
 | |
| 	return func(l *LinuxFactory) error {
 | |
| 		name := args[0]
 | |
| 		if filepath.Base(name) == name {
 | |
| 			if lp, err := exec.LookPath(name); err == nil {
 | |
| 				name = lp
 | |
| 			}
 | |
| 		} else {
 | |
| 			abs, err := filepath.Abs(name)
 | |
| 			if err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 			name = abs
 | |
| 		}
 | |
| 		l.InitPath = "/proc/self/exe"
 | |
| 		l.InitArgs = append([]string{name}, args[1:]...)
 | |
| 		return nil
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // InitPath returns an options func to configure a LinuxFactory with the
 | |
| // provided absolute path to the init binary and arguements.
 | |
| func InitPath(path string, args ...string) func(*LinuxFactory) error {
 | |
| 	return func(l *LinuxFactory) error {
 | |
| 		l.InitPath = path
 | |
| 		l.InitArgs = args
 | |
| 		return nil
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // SystemdCgroups is an options func to configure a LinuxFactory to return
 | |
| // containers that use systemd to create and manage cgroups.
 | |
| func SystemdCgroups(l *LinuxFactory) error {
 | |
| 	l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
 | |
| 		return &systemd.Manager{
 | |
| 			Cgroups: config,
 | |
| 			Paths:   paths,
 | |
| 		}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Cgroupfs is an options func to configure a LinuxFactory to return
 | |
| // containers that use the native cgroups filesystem implementation to
 | |
| // create and manage cgroups.
 | |
| func Cgroupfs(l *LinuxFactory) error {
 | |
| 	l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
 | |
| 		return &fs.Manager{
 | |
| 			Cgroups: config,
 | |
| 			Paths:   paths,
 | |
| 		}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // TmpfsRoot is an option func to mount LinuxFactory.Root to tmpfs.
 | |
| func TmpfsRoot(l *LinuxFactory) error {
 | |
| 	mounted, err := mount.Mounted(l.Root)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if !mounted {
 | |
| 		if err := syscall.Mount("tmpfs", l.Root, "tmpfs", 0, ""); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // New returns a linux based container factory based in the root directory and
 | |
| // configures the factory with the provided option funcs.
 | |
| func New(root string, options ...func(*LinuxFactory) error) (Factory, error) {
 | |
| 	if root != "" {
 | |
| 		if err := os.MkdirAll(root, 0700); err != nil {
 | |
| 			return nil, newGenericError(err, SystemError)
 | |
| 		}
 | |
| 	}
 | |
| 	l := &LinuxFactory{
 | |
| 		Root:      root,
 | |
| 		Validator: validate.New(),
 | |
| 		CriuPath:  "criu",
 | |
| 	}
 | |
| 	InitArgs(os.Args[0], "init")(l)
 | |
| 	Cgroupfs(l)
 | |
| 	for _, opt := range options {
 | |
| 		if err := opt(l); err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 	}
 | |
| 	return l, nil
 | |
| }
 | |
| 
 | |
| // LinuxFactory implements the default factory interface for linux based systems.
 | |
| type LinuxFactory struct {
 | |
| 	// Root directory for the factory to store state.
 | |
| 	Root string
 | |
| 
 | |
| 	// InitPath is the absolute path to the init binary.
 | |
| 	InitPath string
 | |
| 
 | |
| 	// InitArgs are arguments for calling the init responsibilities for spawning
 | |
| 	// a container.
 | |
| 	InitArgs []string
 | |
| 
 | |
| 	// CriuPath is the path to the criu binary used for checkpoint and restore of
 | |
| 	// containers.
 | |
| 	CriuPath string
 | |
| 
 | |
| 	// Validator provides validation to container configurations.
 | |
| 	Validator validate.Validator
 | |
| 
 | |
| 	// NewCgroupsManager returns an initialized cgroups manager for a single container.
 | |
| 	NewCgroupsManager func(config *configs.Cgroup, paths map[string]string) cgroups.Manager
 | |
| }
 | |
| 
 | |
| func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, error) {
 | |
| 	if l.Root == "" {
 | |
| 		return nil, newGenericError(fmt.Errorf("invalid root"), ConfigInvalid)
 | |
| 	}
 | |
| 	if err := l.validateID(id); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	if err := l.Validator.Validate(config); err != nil {
 | |
| 		return nil, newGenericError(err, ConfigInvalid)
 | |
| 	}
 | |
| 	containerRoot := filepath.Join(l.Root, id)
 | |
| 	if _, err := os.Stat(containerRoot); err == nil {
 | |
| 		return nil, newGenericError(fmt.Errorf("container with id exists: %v", id), IdInUse)
 | |
| 	} else if !os.IsNotExist(err) {
 | |
| 		return nil, newGenericError(err, SystemError)
 | |
| 	}
 | |
| 	if err := os.MkdirAll(containerRoot, 0700); err != nil {
 | |
| 		return nil, newGenericError(err, SystemError)
 | |
| 	}
 | |
| 	c := &linuxContainer{
 | |
| 		id:            id,
 | |
| 		root:          containerRoot,
 | |
| 		config:        config,
 | |
| 		initPath:      l.InitPath,
 | |
| 		initArgs:      l.InitArgs,
 | |
| 		criuPath:      l.CriuPath,
 | |
| 		cgroupManager: l.NewCgroupsManager(config.Cgroups, nil),
 | |
| 	}
 | |
| 	c.state = &stoppedState{c: c}
 | |
| 	return c, nil
 | |
| }
 | |
| 
 | |
| func (l *LinuxFactory) Load(id string) (Container, error) {
 | |
| 	if l.Root == "" {
 | |
| 		return nil, newGenericError(fmt.Errorf("invalid root"), ConfigInvalid)
 | |
| 	}
 | |
| 	containerRoot := filepath.Join(l.Root, id)
 | |
| 	state, err := l.loadState(containerRoot)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	r := &nonChildProcess{
 | |
| 		processPid:       state.InitProcessPid,
 | |
| 		processStartTime: state.InitProcessStartTime,
 | |
| 		fds:              state.ExternalDescriptors,
 | |
| 	}
 | |
| 	c := &linuxContainer{
 | |
| 		initProcess:   r,
 | |
| 		id:            id,
 | |
| 		config:        &state.Config,
 | |
| 		initPath:      l.InitPath,
 | |
| 		initArgs:      l.InitArgs,
 | |
| 		criuPath:      l.CriuPath,
 | |
| 		cgroupManager: l.NewCgroupsManager(state.Config.Cgroups, state.CgroupPaths),
 | |
| 		root:          containerRoot,
 | |
| 	}
 | |
| 	c.state = &createdState{c: c, s: Created}
 | |
| 	if err := c.refreshState(); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return c, nil
 | |
| }
 | |
| 
 | |
| func (l *LinuxFactory) Type() string {
 | |
| 	return "libcontainer"
 | |
| }
 | |
| 
 | |
| // StartInitialization loads a container by opening the pipe fd from the parent to read the configuration and state
 | |
| // This is a low level implementation detail of the reexec and should not be consumed externally
 | |
| func (l *LinuxFactory) StartInitialization() (err error) {
 | |
| 	fdStr := os.Getenv("_LIBCONTAINER_INITPIPE")
 | |
| 	pipefd, err := strconv.Atoi(fdStr)
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("error converting env var _LIBCONTAINER_INITPIPE(%q) to an int: %s", fdStr, err)
 | |
| 	}
 | |
| 	var (
 | |
| 		pipe = os.NewFile(uintptr(pipefd), "pipe")
 | |
| 		it   = initType(os.Getenv("_LIBCONTAINER_INITTYPE"))
 | |
| 	)
 | |
| 	// clear the current process's environment to clean any libcontainer
 | |
| 	// specific env vars.
 | |
| 	os.Clearenv()
 | |
| 	var i initer
 | |
| 	defer func() {
 | |
| 		// if we have an error during the initialization of the container's init then send it back to the
 | |
| 		// parent process in the form of an initError.
 | |
| 		if err != nil {
 | |
| 			if _, ok := i.(*linuxStandardInit); ok {
 | |
| 				//  Synchronisation only necessary for standard init.
 | |
| 				if err := utils.WriteJSON(pipe, syncT{procError}); err != nil {
 | |
| 					panic(err)
 | |
| 				}
 | |
| 			}
 | |
| 			if err := utils.WriteJSON(pipe, newSystemError(err)); err != nil {
 | |
| 				panic(err)
 | |
| 			}
 | |
| 		} else {
 | |
| 			if err := utils.WriteJSON(pipe, syncT{procStart}); err != nil {
 | |
| 				panic(err)
 | |
| 			}
 | |
| 		}
 | |
| 		// ensure that this pipe is always closed
 | |
| 		pipe.Close()
 | |
| 	}()
 | |
| 	i, err = newContainerInit(it, pipe)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return i.Init()
 | |
| }
 | |
| 
 | |
| func (l *LinuxFactory) loadState(root string) (*State, error) {
 | |
| 	f, err := os.Open(filepath.Join(root, stateFilename))
 | |
| 	if err != nil {
 | |
| 		if os.IsNotExist(err) {
 | |
| 			return nil, newGenericError(err, ContainerNotExists)
 | |
| 		}
 | |
| 		return nil, newGenericError(err, SystemError)
 | |
| 	}
 | |
| 	defer f.Close()
 | |
| 	var state *State
 | |
| 	if err := json.NewDecoder(f).Decode(&state); err != nil {
 | |
| 		return nil, newGenericError(err, SystemError)
 | |
| 	}
 | |
| 	return state, nil
 | |
| }
 | |
| 
 | |
| func (l *LinuxFactory) validateID(id string) error {
 | |
| 	if !idRegex.MatchString(id) {
 | |
| 		return newGenericError(fmt.Errorf("invalid id format: %v", id), InvalidIdFormat)
 | |
| 	}
 | |
| 	if len(id) > maxIdLen {
 | |
| 		return newGenericError(fmt.Errorf("invalid id format: %v", id), InvalidIdFormat)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 |