func NewDriver(root, initPath string) (*driver, error) { meminfo, err := sysinfo.ReadMemInfo() if err != nil { return nil, err } if err := os.MkdirAll(root, 0700); err != nil { return nil, err } // native driver root is at docker_root/execdriver/native. Put apparmor at docker_root if err := apparmor.InstallDefaultProfile(); err != nil { return nil, err } cgm := libcontainer.Cgroupfs if systemd.UseSystemd() { cgm = libcontainer.SystemdCgroups } f, err := libcontainer.New( root, cgm, libcontainer.InitPath(reexec.Self(), DriverName), ) if err != nil { return nil, err } return &driver{ root: root, initPath: initPath, activeContainers: make(map[string]libcontainer.Container), machineMemory: meminfo.MemTotal, factory: f, }, nil }
func TestMain(m *testing.M) { var ( err error ret int = 0 ) log.SetOutput(os.Stderr) log.SetLevel(log.InfoLevel) factory, err = libcontainer.New(".", libcontainer.Cgroupfs) if err != nil { log.Error(err) os.Exit(1) } if systemd.UseSystemd() { systemdFactory, err = libcontainer.New(".", libcontainer.SystemdCgroups) if err != nil { log.Error(err) os.Exit(1) } } ret = m.Run() os.Exit(ret) }
// Register root container before running this function! func Register(factory info.MachineInfoFactory) error { client, err := docker.NewClient(*ArgDockerEndpoint) if err != nil { return fmt.Errorf("unable to communicate with docker daemon: %v", err) } if version, err := client.Version(); err != nil { return fmt.Errorf("unable to communicate with docker daemon: %v", err) } else { expected_version := []int{0, 11, 1} version_string := version.Get("Version") version, err := parseDockerVersion(version_string) if err != nil { return fmt.Errorf("Couldn't parse docker version: %v", err) } for index, number := range version { if number > expected_version[index] { break } else if number < expected_version[index] { return fmt.Errorf("cAdvisor requires docker version above %v but we have found version %v reported as \"%v\"", expected_version, version, version_string) } } } f := &dockerFactory{ machineInfoFactory: factory, useSystemd: systemd.UseSystemd(), client: client, } if f.useSystemd { log.Printf("System is using systemd") } log.Printf("Registering Docker factory") container.RegisterContainerHandlerFactory(f) return nil }
// killAllPids itterates over all of the container's processes // sending a SIGKILL to each process. func killAllPids(container *libcontainer.Config) error { var ( procs []*os.Process freeze = fs.Freeze getPids = fs.GetPids ) if systemd.UseSystemd() { freeze = systemd.Freeze getPids = systemd.GetPids } freeze(container.Cgroups, cgroups.Frozen) pids, err := getPids(container.Cgroups) if err != nil { return err } for _, pid := range pids { // TODO: log err without aborting if we are unable to find // a single PID if p, err := os.FindProcess(pid); err == nil { procs = append(procs, p) p.Kill() } } freeze(container.Cgroups, cgroups.Thawed) for _, p := range procs { p.Wait() } return err }
func (self *dockerContainerHandler) GetStats() (stats *info.ContainerStats, err error) { if !self.isDockerContainer() { // Return empty stats for root containers. stats = new(info.ContainerStats) stats.Timestamp = time.Now() return } mi, err := self.machineInfoFactory.GetMachineInfo() if err != nil { return } parent, id, err := self.splitName() if err != nil { return } cg := &cgroups.Cgroup{ Parent: parent, Name: id, } // TODO(vmarmol): Use libcontainer's Stats() in the new API when that is ready. // Use systemd paths if systemd is being used. var s *cgroups.Stats if systemd.UseSystemd() { s, err = systemd.GetStats(cg) } else { s, err = fs.GetStats(cg) } if err != nil { return } stats = libcontainerToContainerStats(s, mi) return }
// SetupCgroups applies the cgroup restrictions to the process running in the container based // on the container's configuration func SetupCgroups(container *libcontainer.Config, nspid int) (map[string]string, error) { if container.Cgroups != nil { c := container.Cgroups if systemd.UseSystemd() { return systemd.Apply(c, nspid) } return fs.Apply(c, nspid) } return map[string]string{}, nil }
// SetupCgroups applies the cgroup restrictions to the process running in the container based // on the container's configuration func SetupCgroups(container *libcontainer.Config, nspid int) (cgroups.ActiveCgroup, error) { if container.Cgroups != nil { c := container.Cgroups if systemd.UseSystemd() { return systemd.Apply(c, nspid) } return fs.Apply(c, nspid) } return nil, nil }
func loadFactory(context *cli.Context) (libcontainer.Factory, error) { cgm := libcontainer.Cgroupfs if context.Bool("systemd") { if systemd.UseSystemd() { cgm = libcontainer.SystemdCgroups } else { logrus.Warn("systemd cgroup flag passed, but systemd support for managing cgroups is not available.") } } return libcontainer.New(context.GlobalString("root"), cgm) }
func (d *driver) Unpause(c *execdriver.Command) error { active := d.activeContainers[c.ID] if active == nil { return fmt.Errorf("active container for %s does not exist", c.ID) } active.container.Cgroups.Freezer = "THAWED" if systemd.UseSystemd() { return systemd.Freeze(active.container.Cgroups, active.container.Cgroups.Freezer) } return fs.Freeze(active.container.Cgroups, active.container.Cgroups.Freezer) }
func init() { useSystemd = systemd.UseSystemd() if !useSystemd { // Second attempt at checking for systemd, check for a "name=systemd" cgroup. mnt, err := cgroups.FindCgroupMountpoint("cpu") if err == nil { // systemd presence does not mean systemd controls cgroups. // If system.slice cgroup exists, then systemd is taking control. // This breaks if user creates system.slice manually :) useSystemd = utils.FileExists(mnt + "/system.slice") } } }
// Register root container before running this function! func Register(factory info.MachineInfoFactory) error { client, err := docker.NewClient(*ArgDockerEndpoint) if err != nil { return fmt.Errorf("unable to communicate with docker daemon: %v", err) } if version, err := client.Version(); err != nil { return fmt.Errorf("unable to communicate with docker daemon: %v", err) } else { expected_version := []int{0, 11, 1} version_string := version.Get("Version") version, err := parseDockerVersion(version_string) if err != nil { return fmt.Errorf("Couldn't parse docker version: %v", err) } for index, number := range version { if number > expected_version[index] { break } else if number < expected_version[index] { return fmt.Errorf("cAdvisor requires docker version above %v but we have found version %v reported as \"%v\"", expected_version, version, version_string) } } } // Check that the libcontainer execdriver is used. information, err := client.Info() if err != nil { return fmt.Errorf("failed to detect Docker info: %v", err) } usesNativeDriver := false for _, val := range *information { if strings.Contains(val, "ExecutionDriver=") && strings.Contains(val, "native") { usesNativeDriver = true break } } if !usesNativeDriver { return fmt.Errorf("Docker found, but not using native exec driver") } f := &dockerFactory{ machineInfoFactory: factory, useSystemd: systemd.UseSystemd(), client: client, } if f.useSystemd { glog.Infof("System is using systemd") } glog.Infof("Registering Docker factory") container.RegisterContainerHandlerFactory(f) return nil }
func toggle(state cgroups.FreezerState) error { container, err := loadConfig() if err != nil { return err } if systemd.UseSystemd() { err = systemd.Freeze(container.Cgroups, state) } else { err = fs.Freeze(container.Cgroups, state) } return err }
func destroyAction(context *cli.Context) { config, err := getConfig(context) if err != nil { log.Fatal(err) } killAll(config) // Systemd will clean up cgroup state for empty container. if !systemd.UseSystemd() { err := fs.Cleanup(config) if err != nil { log.Fatal(err) } } }
func setFreezerState(context *cli.Context, state cgroups.FreezerState) { config, err := getConfig(context) if err != nil { log.Fatal(err) } if systemd.UseSystemd() { err = systemd.Freeze(config, state) } else { err = fs.Freeze(config, state) } if err != nil { log.Fatal(err) } }
func (d *driver) GetPidsForContainer(id string) ([]int, error) { d.Lock() active := d.activeContainers[id] d.Unlock() if active == nil { return nil, fmt.Errorf("active container for %s does not exist", id) } c := active.container.Cgroups if systemd.UseSystemd() { return systemd.GetPids(c) } return fs.GetPids(c) }
func loadFactory(context *cli.Context) (libcontainer.Factory, error) { cgm := libcontainer.Cgroupfs if context.Bool("systemd") { if systemd.UseSystemd() { cgm = libcontainer.SystemdCgroups } else { logrus.Warn("systemd cgroup flag passed, but systemd support for managing cgroups is not available.") } } root := context.GlobalString("root") abs, err := filepath.Abs(root) if err != nil { return nil, err } return libcontainer.New(abs, cgm, func(l *libcontainer.LinuxFactory) error { l.CriuPath = context.GlobalString("criu") return nil }) }
// TODO(vmarmol): Complete Stats() in final libcontainer API and move users to that. // DEPRECATED: The below portions are only to be used during the transition to the official API. // Returns all available stats for the given container. func GetStats(container *Config, state *State) (*ContainerStats, error) { var ( err error stats = &ContainerStats{} ) if systemd.UseSystemd() { stats.CgroupStats, err = systemd.GetStats(container.Cgroups) } else { stats.CgroupStats, err = fs.GetStats(container.Cgroups) } if err != nil { return stats, err } stats.NetworkStats, err = network.GetStats(&state.NetworkState) return stats, err }
func createAction(context *cli.Context) { config, err := getConfigFromFile(context) if err != nil { log.Fatal(err) } pid := context.Int("pid") if pid <= 0 { log.Fatal(fmt.Errorf("Invalid pid : %d", pid)) } if systemd.UseSystemd() { _, err := systemd.Apply(config, pid) if err != nil { log.Fatal(err) } } else { _, err := fs.Apply(config, pid) if err != nil { log.Fatal(err) } } }
func NewDriver(root, initPath string, options []string) (*driver, error) { meminfo, err := sysinfo.ReadMemInfo() if err != nil { return nil, err } if err := sysinfo.MkdirAll(root, 0700); err != nil { return nil, err } // native driver root is at docker_root/execdriver/native. Put apparmor at docker_root if err := apparmor.InstallDefaultProfile(); err != nil { return nil, err } // choose cgroup manager // this makes sure there are no breaking changes to people // who upgrade from versions without native.cgroupdriver opt cgm := libcontainer.Cgroupfs if systemd.UseSystemd() { cgm = libcontainer.SystemdCgroups } // parse the options for _, option := range options { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil { return nil, err } key = strings.ToLower(key) switch key { case "native.cgroupdriver": // override the default if they set options switch val { case "systemd": if systemd.UseSystemd() { cgm = libcontainer.SystemdCgroups } else { // warn them that they chose the wrong driver logrus.Warn("You cannot use systemd as native.cgroupdriver, using cgroupfs instead") } case "cgroupfs": cgm = libcontainer.Cgroupfs default: return nil, fmt.Errorf("Unknown native.cgroupdriver given %q. try cgroupfs or systemd", val) } default: return nil, fmt.Errorf("Unknown option %s\n", key) } } logrus.Debugf("Using %v as native.cgroupdriver", cgm) f, err := libcontainer.New( root, cgm, libcontainer.InitPath(reexec.Self(), DriverName), ) if err != nil { return nil, err } return &driver{ root: root, initPath: initPath, activeContainers: make(map[string]libcontainer.Container), machineMemory: meminfo.MemTotal, factory: f, }, nil }
func init() { useSystemd = systemd.UseSystemd() if useSystemd { glog.Infof("System is using systemd") } }
func TestRunWithKernelMemorySystemd(t *testing.T) { if !systemd.UseSystemd() { t.Skip("Systemd is unsupported") } testRunWithKernelMemory(t, true) }
func TestCpuSharesSystemd(t *testing.T) { if !systemd.UseSystemd() { t.Skip("Systemd is unsupported") } testCpuShares(t, true) }
func TestSystemdFreeze(t *testing.T) { if !systemd.UseSystemd() { t.Skip("Systemd is unsupported") } testFreeze(t, true) }