Add factory configuration via functional api

This allows you to set certian configuration options such as what cgroup
implementation to use on the factory at create time.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
Michael Crosby
2015-02-13 15:43:14 -08:00
parent 4c43b0f498
commit b21b19e060
9 changed files with 93 additions and 84 deletions

View File

@@ -1,39 +0,0 @@
package manager
import (
"github.com/docker/libcontainer/cgroups"
"github.com/docker/libcontainer/cgroups/fs"
"github.com/docker/libcontainer/cgroups/systemd"
"github.com/docker/libcontainer/configs"
)
// Create a new cgroup manager with specified configuration
// TODO this object is not really initialized until Apply() is called.
// Maybe make this to the equivalent of Apply() at some point?
// @vmarmol
func NewCgroupManager(cgroups *configs.Cgroup) cgroups.Manager {
if systemd.UseSystemd() {
return &systemd.Manager{
Cgroups: cgroups,
}
}
return &fs.Manager{
Cgroups: cgroups,
}
}
// Restore a cgroup manager with specified configuration and state
func LoadCgroupManager(cgroups *configs.Cgroup, paths map[string]string) cgroups.Manager {
if systemd.UseSystemd() {
return &systemd.Manager{
Cgroups: cgroups,
Paths: paths,
}
}
return &fs.Manager{
Cgroups: cgroups,
Paths: paths,
}
}

View File

@@ -236,7 +236,7 @@ func TestEnter(t *testing.T) {
config := newTemplateConfig(rootfs)
factory, err := libcontainer.New(root, []string{os.Args[0], "init", "--"})
factory, err := libcontainer.New(root, libcontainer.InitArgs(os.Args[0], "init", "--"), libcontainer.Cgroupfs)
if err != nil {
t.Fatal(err)
}
@@ -340,7 +340,7 @@ func TestFreeze(t *testing.T) {
config := newTemplateConfig(rootfs)
factory, err := libcontainer.New(root, []string{os.Args[0], "init", "--"})
factory, err := libcontainer.New(root, libcontainer.InitArgs(os.Args[0], "init", "--"), libcontainer.Cgroupfs)
if err != nil {
t.Fatal(err)
}

View File

@@ -17,7 +17,7 @@ func init() {
}
runtime.GOMAXPROCS(1)
runtime.LockOSThread()
factory, err := libcontainer.New("", nil)
factory, err := libcontainer.New("")
if err != nil {
log.Fatalf("unable to initialize for container: %s", err)
}

View File

@@ -81,7 +81,7 @@ func runContainer(config *configs.Config, console string, args ...string) (buffe
Stderr: buffers.Stderr,
}
factory, err := libcontainer.New(".", []string{os.Args[0], "init", "--"})
factory, err := libcontainer.New(".", libcontainer.InitArgs(os.Args[0], "init", "--"), libcontainer.Cgroupfs)
if err != nil {
return nil, -1, err
}

View File

@@ -10,9 +10,9 @@ import (
"path/filepath"
"regexp"
"github.com/golang/glog"
cgroups "github.com/docker/libcontainer/cgroups/manager"
"github.com/docker/libcontainer/cgroups"
"github.com/docker/libcontainer/cgroups/fs"
"github.com/docker/libcontainer/cgroups/systemd"
"github.com/docker/libcontainer/configs"
"github.com/docker/libcontainer/configs/validate"
)
@@ -26,39 +26,89 @@ var (
maxIdLen = 1024
)
// New returns a linux based container factory based in the root directory.
func New(root string, initArgs []string) (Factory, error) {
// 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 {
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
}
// 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)
}
}
return &linuxFactory{
root: root,
initArgs: initArgs,
validator: validate.New(),
}, nil
l := &LinuxFactory{
Root: root,
InitArgs: []string{os.Args[0], "init"},
Validator: validate.New(),
}
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 is the root directory
root string
initArgs []string
validator validate.Validator
// LinuxFactory implements the default factory interface for linux based systems.
type LinuxFactory struct {
// Root directory for the factory to store state.
Root string
// InitArgs are arguments for calling the init responsibilities for spawning
// a container.
InitArgs []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 == "" {
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 {
if err := l.Validator.Validate(config); err != nil {
return nil, newGenericError(err, ConfigInvalid)
}
containerRoot := filepath.Join(l.root, id)
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) {
@@ -71,16 +121,16 @@ func (l *linuxFactory) Create(id string, config *configs.Config) (Container, err
id: id,
root: containerRoot,
config: config,
initArgs: l.initArgs,
cgroupManager: cgroups.NewCgroupManager(config.Cgroups),
initArgs: l.InitArgs,
cgroupManager: l.NewCgroupsManager(config.Cgroups, nil),
}, nil
}
func (l *linuxFactory) Load(id string) (Container, error) {
if l.root == "" {
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)
containerRoot := filepath.Join(l.Root, id)
state, err := l.loadState(containerRoot)
if err != nil {
return nil, err
@@ -89,21 +139,19 @@ func (l *linuxFactory) Load(id string) (Container, error) {
processPid: state.InitProcessPid,
processStartTime: state.InitProcessStartTime,
}
cgroupManager := cgroups.LoadCgroupManager(state.Config.Cgroups, state.CgroupPaths)
glog.Infof("using %s as cgroup manager", cgroupManager)
return &linuxContainer{
initProcess: r,
id: id,
config: &state.Config,
initArgs: l.initArgs,
cgroupManager: cgroupManager,
initArgs: l.InitArgs,
cgroupManager: l.NewCgroupsManager(state.Config.Cgroups, state.CgroupPaths),
root: containerRoot,
}, nil
}
// 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(pipefd uintptr) (err error) {
func (l *LinuxFactory) StartInitialization(pipefd uintptr) (err error) {
var (
pipe = os.NewFile(uintptr(pipefd), "pipe")
it = initType(os.Getenv("_LIBCONTAINER_INITTYPE"))
@@ -134,7 +182,7 @@ func (l *linuxFactory) StartInitialization(pipefd uintptr) (err error) {
return i.Init()
}
func (l *linuxFactory) loadState(root string) (*State, error) {
func (l *LinuxFactory) loadState(root string) (*State, error) {
f, err := os.Open(filepath.Join(root, stateFilename))
if err != nil {
if os.IsNotExist(err) {
@@ -150,7 +198,7 @@ func (l *linuxFactory) loadState(root string) (*State, error) {
return state, nil
}
func (l *linuxFactory) validateID(id string) error {
func (l *LinuxFactory) validateID(id string) error {
if !idRegex.MatchString(id) {
return newGenericError(fmt.Errorf("Invalid id format: %v", id), InvalidIdFormat)
}

View File

@@ -29,19 +29,19 @@ func TestFactoryNew(t *testing.T) {
t.Fatal(rerr)
}
defer os.RemoveAll(root)
factory, err := New(root, nil)
factory, err := New(root, Cgroupfs)
if err != nil {
t.Fatal(err)
}
if factory == nil {
t.Fatal("factory should not be nil")
}
lfactory, ok := factory.(*linuxFactory)
lfactory, ok := factory.(*LinuxFactory)
if !ok {
t.Fatal("expected linux factory returned on linux based systems")
}
if lfactory.root != root {
t.Fatalf("expected factory root to be %q but received %q", root, lfactory.root)
if lfactory.Root != root {
t.Fatalf("expected factory root to be %q but received %q", root, lfactory.Root)
}
}
@@ -51,7 +51,7 @@ func TestFactoryLoadNotExists(t *testing.T) {
t.Fatal(rerr)
}
defer os.RemoveAll(root)
factory, err := New(root, nil)
factory, err := New(root, Cgroupfs)
if err != nil {
t.Fatal(err)
}
@@ -91,7 +91,7 @@ func TestFactoryLoadContainer(t *testing.T) {
if err := marshal(filepath.Join(root, id, stateFilename), expectedState); err != nil {
t.Fatal(err)
}
factory, err := New(root, nil)
factory, err := New(root, Cgroupfs)
if err != nil {
t.Fatal(err)
}

View File

@@ -15,7 +15,7 @@ var initCommand = cli.Command{
Action: func(context *cli.Context) {
runtime.GOMAXPROCS(1)
runtime.LockOSThread()
factory, err := libcontainer.New("", nil)
factory, err := libcontainer.New("")
if err != nil {
log.Fatal(err)
}

View File

@@ -10,7 +10,7 @@ import (
func main() {
app := cli.NewApp()
app.Name = "nsinit"
app.Version = "1"
app.Version = "2"
app.Author = "libcontainer maintainers"
app.Flags = []cli.Flag{
cli.StringFlag{Name: "nspid"},

View File

@@ -29,7 +29,7 @@ func loadConfig(context *cli.Context) (*configs.Config, error) {
}
func loadFactory(context *cli.Context) (libcontainer.Factory, error) {
return libcontainer.New(context.GlobalString("root"), []string{os.Args[0], "init"})
return libcontainer.New(context.GlobalString("root"), libcontainer.Cgroupfs)
}
func getContainer(context *cli.Context) (libcontainer.Container, error) {