Revert "cgroups: add pids controller support"
Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
This commit is contained in:
parent
bc465742ac
commit
4124ba9468
|
@ -23,7 +23,6 @@ var (
|
||||||
&MemoryGroup{},
|
&MemoryGroup{},
|
||||||
&CpuGroup{},
|
&CpuGroup{},
|
||||||
&CpuacctGroup{},
|
&CpuacctGroup{},
|
||||||
&PidsGroup{},
|
|
||||||
&BlkioGroup{},
|
&BlkioGroup{},
|
||||||
&HugetlbGroup{},
|
&HugetlbGroup{},
|
||||||
&NetClsGroup{},
|
&NetClsGroup{},
|
||||||
|
@ -180,24 +179,11 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) Set(container *configs.Config) error {
|
func (m *Manager) Set(container *configs.Config) error {
|
||||||
for _, sys := range subsystems {
|
for name, path := range m.Paths {
|
||||||
// We can't set this here, because after being applied, memcg doesn't
|
sys, err := subsystems.Get(name)
|
||||||
// allow a non-empty cgroup from having its limits changed.
|
if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) {
|
||||||
if sys.Name() == "memory" {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate fake cgroup data.
|
|
||||||
d, err := getCgroupData(container.Cgroups, -1)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Get the path, but don't error out if the cgroup wasn't found.
|
|
||||||
path, err := d.path(sys.Name())
|
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := sys.Set(path, container.Cgroups); err != nil {
|
if err := sys.Set(path, container.Cgroups); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,15 @@ func (s *BlkioGroup) Name() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BlkioGroup) Apply(d *cgroupData) error {
|
func (s *BlkioGroup) Apply(d *cgroupData) error {
|
||||||
_, err := d.join("blkio")
|
dir, err := d.join("blkio")
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
if err != nil && !cgroups.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := s.Set(dir, d.config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,10 +22,15 @@ func (s *CpuGroup) Name() string {
|
||||||
func (s *CpuGroup) Apply(d *cgroupData) error {
|
func (s *CpuGroup) Apply(d *cgroupData) error {
|
||||||
// We always want to join the cpu group, to allow fair cpu scheduling
|
// We always want to join the cpu group, to allow fair cpu scheduling
|
||||||
// on a container basis
|
// on a container basis
|
||||||
_, err := d.join("cpu")
|
dir, err := d.join("cpu")
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
if err != nil && !cgroups.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := s.Set(dir, d.config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,11 @@ func (s *CpusetGroup) ApplyDir(dir string, cgroup *configs.Cgroup, pid int) erro
|
||||||
if err := s.ensureParent(dir, root); err != nil {
|
if err := s.ensureParent(dir, root); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// the default values inherit from parent cgroup are already set in
|
||||||
|
// s.ensureParent, cover these if we have our own
|
||||||
|
if err := s.Set(dir, cgroup); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// because we are not using d.join we need to place the pid into the procs file
|
// because we are not using d.join we need to place the pid into the procs file
|
||||||
// unlike the other subsystems
|
// unlike the other subsystems
|
||||||
if err := writeFile(dir, "cgroup.procs", strconv.Itoa(pid)); err != nil {
|
if err := writeFile(dir, "cgroup.procs", strconv.Itoa(pid)); err != nil {
|
||||||
|
|
|
@ -15,12 +15,17 @@ func (s *DevicesGroup) Name() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DevicesGroup) Apply(d *cgroupData) error {
|
func (s *DevicesGroup) Apply(d *cgroupData) error {
|
||||||
_, err := d.join("devices")
|
dir, err := d.join("devices")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// We will return error even it's `not found` error, devices
|
// We will return error even it's `not found` error, devices
|
||||||
// cgroup is hard requirement for container's security.
|
// cgroup is hard requirement for container's security.
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := s.Set(dir, d.config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,10 +19,15 @@ func (s *FreezerGroup) Name() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FreezerGroup) Apply(d *cgroupData) error {
|
func (s *FreezerGroup) Apply(d *cgroupData) error {
|
||||||
_, err := d.join("freezer")
|
dir, err := d.join("freezer")
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
if err != nil && !cgroups.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := s.Set(dir, d.config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,10 +19,15 @@ func (s *HugetlbGroup) Name() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *HugetlbGroup) Apply(d *cgroupData) error {
|
func (s *HugetlbGroup) Apply(d *cgroupData) error {
|
||||||
_, err := d.join("hugetlb")
|
dir, err := d.join("hugetlb")
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
if err != nil && !cgroups.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := s.Set(dir, d.config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ func (s *MemoryGroup) Apply(d *cgroupData) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.Set(path, d.config); err != nil {
|
if err := s.Set(path, d.config); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,15 @@ func (s *NetClsGroup) Name() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NetClsGroup) Apply(d *cgroupData) error {
|
func (s *NetClsGroup) Apply(d *cgroupData) error {
|
||||||
_, err := d.join("net_cls")
|
dir, err := d.join("net_cls")
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
if err != nil && !cgroups.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := s.Set(dir, d.config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,15 @@ func (s *NetPrioGroup) Name() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NetPrioGroup) Apply(d *cgroupData) error {
|
func (s *NetPrioGroup) Apply(d *cgroupData) error {
|
||||||
_, err := d.join("net_prio")
|
dir, err := d.join("net_prio")
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
if err != nil && !cgroups.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := s.Set(dir, d.config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package fs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PidsGroup struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *PidsGroup) Name() string {
|
|
||||||
return "pids"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *PidsGroup) Apply(d *cgroupData) error {
|
|
||||||
_, err := d.join("pids")
|
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *PidsGroup) Set(path string, cgroup *configs.Cgroup) error {
|
|
||||||
if cgroup.Resources.PidsLimit != 0 {
|
|
||||||
// "max" is the fallback value.
|
|
||||||
limit := "max"
|
|
||||||
|
|
||||||
if cgroup.Resources.PidsLimit > 0 {
|
|
||||||
limit = strconv.FormatInt(cgroup.Resources.PidsLimit, 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := writeFile(path, "pids.max", limit); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *PidsGroup) Remove(d *cgroupData) error {
|
|
||||||
return removePath(d.path("pids"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *PidsGroup) GetStats(path string, stats *cgroups.Stats) error {
|
|
||||||
value, err := getCgroupParamUint(path, "pids.current")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to parse pids.current - %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
stats.PidsStats.Current = value
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package fs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
maxUnlimited = -1
|
|
||||||
maxLimited = 1024
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPidsSetMax(t *testing.T) {
|
|
||||||
helper := NewCgroupTestUtil("pids", t)
|
|
||||||
defer helper.cleanup()
|
|
||||||
|
|
||||||
helper.writeFileContents(map[string]string{
|
|
||||||
"pids.max": "max",
|
|
||||||
})
|
|
||||||
|
|
||||||
helper.CgroupData.config.Resources.PidsLimit = maxLimited
|
|
||||||
pids := &PidsGroup{}
|
|
||||||
if err := pids.Set(helper.CgroupPath, helper.CgroupData.config); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
value, err := getCgroupParamUint(helper.CgroupPath, "pids.max")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to parse pids.max - %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if value != maxLimited {
|
|
||||||
t.Fatalf("Expected %d, got %d for setting pids.max - limited", maxLimited, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPidsSetUnlimited(t *testing.T) {
|
|
||||||
helper := NewCgroupTestUtil("pids", t)
|
|
||||||
defer helper.cleanup()
|
|
||||||
|
|
||||||
helper.writeFileContents(map[string]string{
|
|
||||||
"pids.max": strconv.Itoa(maxLimited),
|
|
||||||
})
|
|
||||||
|
|
||||||
helper.CgroupData.config.Resources.PidsLimit = maxUnlimited
|
|
||||||
pids := &PidsGroup{}
|
|
||||||
if err := pids.Set(helper.CgroupPath, helper.CgroupData.config); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
value, err := getCgroupParamString(helper.CgroupPath, "pids.max")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to parse pids.max - %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if value != "max" {
|
|
||||||
t.Fatalf("Expected %s, got %s for setting pids.max - unlimited", "max", value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPidsStats(t *testing.T) {
|
|
||||||
helper := NewCgroupTestUtil("pids", t)
|
|
||||||
defer helper.cleanup()
|
|
||||||
|
|
||||||
helper.writeFileContents(map[string]string{
|
|
||||||
"pids.current": strconv.Itoa(1337),
|
|
||||||
"pids.max": strconv.Itoa(maxLimited),
|
|
||||||
})
|
|
||||||
|
|
||||||
pids := &PidsGroup{}
|
|
||||||
stats := *cgroups.NewStats()
|
|
||||||
if err := pids.GetStats(helper.CgroupPath, &stats); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if stats.PidsStats.Current != 1337 {
|
|
||||||
t.Fatalf("Expected %d, got %d for pids.current", 1337, stats.PidsStats.Current)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -49,11 +49,6 @@ type MemoryStats struct {
|
||||||
Stats map[string]uint64 `json:"stats,omitempty"`
|
Stats map[string]uint64 `json:"stats,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PidsStats struct {
|
|
||||||
// number of pids in the cgroup
|
|
||||||
Current uint64 `json:"current,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type BlkioStatEntry struct {
|
type BlkioStatEntry struct {
|
||||||
Major uint64 `json:"major,omitempty"`
|
Major uint64 `json:"major,omitempty"`
|
||||||
Minor uint64 `json:"minor,omitempty"`
|
Minor uint64 `json:"minor,omitempty"`
|
||||||
|
@ -85,7 +80,6 @@ type HugetlbStats struct {
|
||||||
type Stats struct {
|
type Stats struct {
|
||||||
CpuStats CpuStats `json:"cpu_stats,omitempty"`
|
CpuStats CpuStats `json:"cpu_stats,omitempty"`
|
||||||
MemoryStats MemoryStats `json:"memory_stats,omitempty"`
|
MemoryStats MemoryStats `json:"memory_stats,omitempty"`
|
||||||
PidsStats PidsStats `json:"pids_stats,omitempty"`
|
|
||||||
BlkioStats BlkioStats `json:"blkio_stats,omitempty"`
|
BlkioStats BlkioStats `json:"blkio_stats,omitempty"`
|
||||||
// the map is in the format "size of hugepage: stats of the hugepage"
|
// the map is in the format "size of hugepage: stats of the hugepage"
|
||||||
HugetlbStats map[string]HugetlbStats `json:"hugetlb_stats,omitempty"`
|
HugetlbStats map[string]HugetlbStats `json:"hugetlb_stats,omitempty"`
|
||||||
|
|
|
@ -55,7 +55,6 @@ var subsystems = subsystemSet{
|
||||||
&fs.MemoryGroup{},
|
&fs.MemoryGroup{},
|
||||||
&fs.CpuGroup{},
|
&fs.CpuGroup{},
|
||||||
&fs.CpuacctGroup{},
|
&fs.CpuacctGroup{},
|
||||||
&fs.PidsGroup{},
|
|
||||||
&fs.BlkioGroup{},
|
&fs.BlkioGroup{},
|
||||||
&fs.HugetlbGroup{},
|
&fs.HugetlbGroup{},
|
||||||
&fs.PerfEventGroup{},
|
&fs.PerfEventGroup{},
|
||||||
|
@ -234,7 +233,7 @@ func (m *Manager) Apply(pid int) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need to manually join the freezer, net_cls, net_prio, pids and cpuset cgroup in systemd
|
// we need to manually join the freezer, net_cls, net_prio and cpuset cgroup in systemd
|
||||||
// because it does not currently support it via the dbus api.
|
// because it does not currently support it via the dbus api.
|
||||||
if err := joinFreezer(c, pid); err != nil {
|
if err := joinFreezer(c, pid); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -247,10 +246,6 @@ func (m *Manager) Apply(pid int) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := joinPids(c, pid); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := joinCpuset(c, pid); err != nil {
|
if err := joinCpuset(c, pid); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -335,43 +330,68 @@ func join(c *configs.Cgroup, subsystem string, pid int) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func joinCpu(c *configs.Cgroup, pid int) error {
|
func joinCpu(c *configs.Cgroup, pid int) error {
|
||||||
_, err := getSubsystemPath(c, "cpu")
|
path, err := getSubsystemPath(c, "cpu")
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
if err != nil && !cgroups.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if c.Resources.CpuQuota != 0 {
|
||||||
|
if err = writeFile(path, "cpu.cfs_quota_us", strconv.FormatInt(c.Resources.CpuQuota, 10)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.Resources.CpuPeriod != 0 {
|
||||||
|
if err = writeFile(path, "cpu.cfs_period_us", strconv.FormatInt(c.Resources.CpuPeriod, 10)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.Resources.CpuRtPeriod != 0 {
|
||||||
|
if err = writeFile(path, "cpu.rt_period_us", strconv.FormatInt(c.Resources.CpuRtPeriod, 10)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.Resources.CpuRtRuntime != 0 {
|
||||||
|
if err = writeFile(path, "cpu.rt_runtime_us", strconv.FormatInt(c.Resources.CpuRtRuntime, 10)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func joinFreezer(c *configs.Cgroup, pid int) error {
|
func joinFreezer(c *configs.Cgroup, pid int) error {
|
||||||
_, err := join(c, "freezer", pid)
|
path, err := join(c, "freezer", pid)
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
if err != nil && !cgroups.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
freezer, err := subsystems.Get("freezer")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return freezer.Set(path, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func joinNetPrio(c *configs.Cgroup, pid int) error {
|
func joinNetPrio(c *configs.Cgroup, pid int) error {
|
||||||
_, err := join(c, "net_prio", pid)
|
path, err := join(c, "net_prio", pid)
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
if err != nil && !cgroups.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
netPrio, err := subsystems.Get("net_prio")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return netPrio.Set(path, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func joinNetCls(c *configs.Cgroup, pid int) error {
|
func joinNetCls(c *configs.Cgroup, pid int) error {
|
||||||
_, err := join(c, "net_cls", pid)
|
path, err := join(c, "net_cls", pid)
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
if err != nil && !cgroups.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
netcls, err := subsystems.Get("net_cls")
|
||||||
}
|
if err != nil {
|
||||||
|
|
||||||
func joinPids(c *configs.Cgroup, pid int) error {
|
|
||||||
_, err := join(c, "pids", pid)
|
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return netcls.Set(path, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) {
|
func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) {
|
||||||
|
@ -438,19 +458,11 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) Set(container *configs.Config) error {
|
func (m *Manager) Set(container *configs.Config) error {
|
||||||
for _, sys := range subsystems {
|
for name, path := range m.Paths {
|
||||||
// We can't set this here, because after being applied, memcg doesn't
|
sys, err := subsystems.Get(name)
|
||||||
// allow a non-empty cgroup from having its limits changed.
|
if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) {
|
||||||
if sys.Name() == "memory" {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the subsystem path, but don't error out for not found cgroups.
|
|
||||||
path, err := getSubsystemPath(container.Cgroups, sys.Name())
|
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := sys.Set(path, container.Cgroups); err != nil {
|
if err := sys.Set(path, container.Cgroups); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -475,13 +487,17 @@ func getUnitName(c *configs.Cgroup) string {
|
||||||
// because systemd will re-write the device settings if it needs to re-apply the cgroup context.
|
// because systemd will re-write the device settings if it needs to re-apply the cgroup context.
|
||||||
// This happens at least for v208 when any sibling unit is started.
|
// This happens at least for v208 when any sibling unit is started.
|
||||||
func joinDevices(c *configs.Cgroup, pid int) error {
|
func joinDevices(c *configs.Cgroup, pid int) error {
|
||||||
_, err := join(c, "devices", pid)
|
path, err := join(c, "devices", pid)
|
||||||
// Even if it's `not found` error, we'll return err because devices cgroup
|
// Even if it's `not found` error, we'll return err because devices cgroup
|
||||||
// is hard requirement for container security.
|
// is hard requirement for container security.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
devices, err := subsystems.Get("devices")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return devices.Set(path, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setKernelMemory(c *configs.Cgroup) error {
|
func setKernelMemory(c *configs.Cgroup) error {
|
||||||
|
@ -494,14 +510,52 @@ func setKernelMemory(c *configs.Cgroup) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.Resources.KernelMemory > 0 {
|
||||||
|
err = writeFile(path, "memory.kmem.limit_in_bytes", strconv.FormatInt(c.Resources.KernelMemory, 10))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func joinMemory(c *configs.Cgroup, pid int) error {
|
func joinMemory(c *configs.Cgroup, pid int) error {
|
||||||
_, err := getSubsystemPath(c, "memory")
|
path, err := getSubsystemPath(c, "memory")
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
if err != nil && !cgroups.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -1 disables memoryswap
|
||||||
|
if c.Resources.MemorySwap > 0 {
|
||||||
|
err = writeFile(path, "memory.memsw.limit_in_bytes", strconv.FormatInt(c.Resources.MemorySwap, 10))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.Resources.MemoryReservation > 0 {
|
||||||
|
err = writeFile(path, "memory.soft_limit_in_bytes", strconv.FormatInt(c.Resources.MemoryReservation, 10))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.Resources.OomKillDisable {
|
||||||
|
if err := writeFile(path, "memory.oom_control", "1"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Resources.MemorySwappiness >= 0 && c.Resources.MemorySwappiness <= 100 {
|
||||||
|
err = writeFile(path, "memory.swappiness", strconv.FormatInt(c.Resources.MemorySwappiness, 10))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if c.Resources.MemorySwappiness == -1 {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("invalid value:%d. valid memory swappiness range is 0-100", c.Resources.MemorySwappiness)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -523,25 +577,68 @@ func joinCpuset(c *configs.Cgroup, pid int) error {
|
||||||
// expects device path instead of major minor numbers, which is also confusing
|
// expects device path instead of major minor numbers, which is also confusing
|
||||||
// for users. So we use fs work around for now.
|
// for users. So we use fs work around for now.
|
||||||
func joinBlkio(c *configs.Cgroup, pid int) error {
|
func joinBlkio(c *configs.Cgroup, pid int) error {
|
||||||
_, err := getSubsystemPath(c, "blkio")
|
path, err := getSubsystemPath(c, "blkio")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// systemd doesn't directly support this in the dbus properties
|
||||||
|
if c.Resources.BlkioLeafWeight != 0 {
|
||||||
|
if err := writeFile(path, "blkio.leaf_weight", strconv.FormatUint(uint64(c.Resources.BlkioLeafWeight), 10)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, wd := range c.Resources.BlkioWeightDevice {
|
||||||
|
if err := writeFile(path, "blkio.weight_device", wd.WeightString()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := writeFile(path, "blkio.leaf_weight_device", wd.LeafWeightString()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, td := range c.Resources.BlkioThrottleReadBpsDevice {
|
||||||
|
if err := writeFile(path, "blkio.throttle.read_bps_device", td.String()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, td := range c.Resources.BlkioThrottleWriteBpsDevice {
|
||||||
|
if err := writeFile(path, "blkio.throttle.write_bps_device", td.String()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, td := range c.Resources.BlkioThrottleReadIOPSDevice {
|
||||||
|
if err := writeFile(path, "blkio.throttle.read_iops_device", td.String()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, td := range c.Resources.BlkioThrottleWriteIOPSDevice {
|
||||||
|
if err := writeFile(path, "blkio.throttle.write_iops_device", td.String()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func joinHugetlb(c *configs.Cgroup, pid int) error {
|
func joinHugetlb(c *configs.Cgroup, pid int) error {
|
||||||
_, err := join(c, "hugetlb", pid)
|
path, err := join(c, "hugetlb", pid)
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
if err != nil && !cgroups.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
hugetlb, err := subsystems.Get("hugetlb")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return hugetlb.Set(path, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func joinPerfEvent(c *configs.Cgroup, pid int) error {
|
func joinPerfEvent(c *configs.Cgroup, pid int) error {
|
||||||
_, err := join(c, "perf_event", pid)
|
path, err := join(c, "perf_event", pid)
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
if err != nil && !cgroups.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
perfEvent, err := subsystems.Get("perf_event")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return perfEvent.Set(path, c)
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,9 +64,6 @@ type Resources struct {
|
||||||
// MEM to use
|
// MEM to use
|
||||||
CpusetMems string `json:"cpuset_mems"`
|
CpusetMems string `json:"cpuset_mems"`
|
||||||
|
|
||||||
// Process limit; set <= `0' to disable limit.
|
|
||||||
PidsLimit int64 `json:"pids_limit"`
|
|
||||||
|
|
||||||
// Specifies per cgroup weight, range is from 10 to 1000.
|
// Specifies per cgroup weight, range is from 10 to 1000.
|
||||||
BlkioWeight uint16 `json:"blkio_weight"`
|
BlkioWeight uint16 `json:"blkio_weight"`
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ package libcontainer
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -221,29 +222,21 @@ func (l *LinuxFactory) StartInitialization() (err error) {
|
||||||
// clear the current process's environment to clean any libcontainer
|
// clear the current process's environment to clean any libcontainer
|
||||||
// specific env vars.
|
// specific env vars.
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
var i initer
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// if we have an error during the initialization of the container's init then send it back to the
|
// 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.
|
// parent process in the form of an initError.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := i.(*linuxStandardInit); ok {
|
// ensure that any data sent from the parent is consumed so it doesn't
|
||||||
// Synchronisation only necessary for standard init.
|
// receive ECONNRESET when the child writes to the pipe.
|
||||||
if err := json.NewEncoder(pipe).Encode(procError); err != nil {
|
ioutil.ReadAll(pipe)
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := json.NewEncoder(pipe).Encode(newSystemError(err)); err != nil {
|
if err := json.NewEncoder(pipe).Encode(newSystemError(err)); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if err := json.NewEncoder(pipe).Encode(procStart); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// ensure that this pipe is always closed
|
// ensure that this pipe is always closed
|
||||||
pipe.Close()
|
pipe.Close()
|
||||||
}()
|
}()
|
||||||
i, err = newContainerInit(it, pipe)
|
i, err := newContainerInit(it, pipe)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,15 +9,6 @@ import (
|
||||||
"github.com/opencontainers/runc/libcontainer/stacktrace"
|
"github.com/opencontainers/runc/libcontainer/stacktrace"
|
||||||
)
|
)
|
||||||
|
|
||||||
type syncType uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
procReady syncType = iota
|
|
||||||
procError
|
|
||||||
procStart
|
|
||||||
procRun
|
|
||||||
)
|
|
||||||
|
|
||||||
var errorTemplate = template.Must(template.New("error").Parse(`Timestamp: {{.Timestamp}}
|
var errorTemplate = template.Must(template.New("error").Parse(`Timestamp: {{.Timestamp}}
|
||||||
Code: {{.ECode}}
|
Code: {{.ECode}}
|
||||||
{{if .Message }}
|
{{if .Message }}
|
||||||
|
|
|
@ -5,7 +5,6 @@ package libcontainer
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
@ -74,7 +73,6 @@ func newContainerInit(t initType, pipe *os.File) (initer, error) {
|
||||||
}, nil
|
}, nil
|
||||||
case initStandard:
|
case initStandard:
|
||||||
return &linuxStandardInit{
|
return &linuxStandardInit{
|
||||||
pipe: pipe,
|
|
||||||
parentPid: syscall.Getppid(),
|
parentPid: syscall.Getppid(),
|
||||||
config: config,
|
config: config,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -142,28 +140,6 @@ func finalizeNamespace(config *initConfig) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// syncParentReady sends to the given pipe a JSON payload which indicates that
|
|
||||||
// the init is ready to Exec the child process. It then waits for the parent to
|
|
||||||
// indicate that it is cleared to Exec.
|
|
||||||
func syncParentReady(pipe io.ReadWriter) error {
|
|
||||||
// Tell parent.
|
|
||||||
if err := json.NewEncoder(pipe).Encode(procReady); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for parent to give the all-clear.
|
|
||||||
var procSync syncType
|
|
||||||
if err := json.NewDecoder(pipe).Decode(&procSync); err != nil {
|
|
||||||
if err == io.EOF {
|
|
||||||
return fmt.Errorf("parent closed synchronisation channel")
|
|
||||||
}
|
|
||||||
if procSync != procRun {
|
|
||||||
return fmt.Errorf("invalid synchronisation flag from parent")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// joinExistingNamespaces gets all the namespace paths specified for the container and
|
// joinExistingNamespaces gets all the namespace paths specified for the container and
|
||||||
// does a setns on the namespace fd so that the current process joins the namespace.
|
// does a setns on the namespace fd so that the current process joins the namespace.
|
||||||
func joinExistingNamespaces(namespaces []configs.Namespace) error {
|
func joinExistingNamespaces(namespaces []configs.Namespace) error {
|
||||||
|
|
|
@ -525,96 +525,6 @@ func testCpuShares(t *testing.T, systemd bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPids(t *testing.T) {
|
|
||||||
testPids(t, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPidsSystemd(t *testing.T) {
|
|
||||||
if !systemd.UseSystemd() {
|
|
||||||
t.Skip("Systemd is unsupported")
|
|
||||||
}
|
|
||||||
testPids(t, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testPids(t *testing.T, systemd bool) {
|
|
||||||
if testing.Short() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
rootfs, err := newRootfs()
|
|
||||||
ok(t, err)
|
|
||||||
defer remove(rootfs)
|
|
||||||
|
|
||||||
config := newTemplateConfig(rootfs)
|
|
||||||
if systemd {
|
|
||||||
config.Cgroups.Parent = "system.slice"
|
|
||||||
}
|
|
||||||
config.Cgroups.Resources.PidsLimit = -1
|
|
||||||
|
|
||||||
// Running multiple processes.
|
|
||||||
_, ret, err := runContainer(config, "", "/bin/sh", "-c", "/bin/true | /bin/true | /bin/true | /bin/true")
|
|
||||||
if err != nil && strings.Contains(err.Error(), "no such directory for pids.max") {
|
|
||||||
t.Skip("PIDs cgroup is unsupported")
|
|
||||||
}
|
|
||||||
ok(t, err)
|
|
||||||
|
|
||||||
if ret != 0 {
|
|
||||||
t.Fatalf("expected fork() to succeed with no pids limit")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enforce a permissive limit (shell + 4 * true).
|
|
||||||
config.Cgroups.Resources.PidsLimit = 5
|
|
||||||
_, ret, err = runContainer(config, "", "/bin/sh", "-c", "/bin/true | /bin/true | /bin/true | /bin/true")
|
|
||||||
if err != nil && strings.Contains(err.Error(), "no such directory for pids.max") {
|
|
||||||
t.Skip("PIDs cgroup is unsupported")
|
|
||||||
}
|
|
||||||
ok(t, err)
|
|
||||||
|
|
||||||
if ret != 0 {
|
|
||||||
t.Fatalf("expected fork() to succeed with permissive pids limit")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enforce a restrictive limit limit (shell + 5 * true).
|
|
||||||
config.Cgroups.Resources.PidsLimit = 5
|
|
||||||
out, ret, err := runContainer(config, "", "/bin/sh", "-c", "/bin/true | /bin/true | /bin/true | /bin/true | /bin/true")
|
|
||||||
if err != nil && strings.Contains(err.Error(), "no such directory for pids.max") {
|
|
||||||
t.Skip("PIDs cgroup is unsupported")
|
|
||||||
}
|
|
||||||
if err != nil && !strings.Contains(out.String(), "sh: can't fork") {
|
|
||||||
ok(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("expected fork() to fail with restrictive pids limit")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enforce minimal restrictions.
|
|
||||||
config.Cgroups.Resources.PidsLimit = 1
|
|
||||||
out, ret, err = runContainer(config, "", "/bin/true")
|
|
||||||
if err != nil && strings.Contains(err.Error(), "no such directory for pids.max") {
|
|
||||||
t.Skip("PIDs cgroup is unsupported")
|
|
||||||
}
|
|
||||||
ok(t, err)
|
|
||||||
|
|
||||||
if ret != 0 {
|
|
||||||
t.Fatalf("expected fork() to succeed for very small pids.max")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enforce minimal restrictions.
|
|
||||||
config.Cgroups.Resources.PidsLimit = 1
|
|
||||||
out, ret, err = runContainer(config, "", "/bin/sh", "-c", "/bin/true")
|
|
||||||
if err != nil && strings.Contains(err.Error(), "no such directory for pids.max") {
|
|
||||||
t.Skip("PIDs cgroup is unsupported")
|
|
||||||
}
|
|
||||||
if err != nil && !strings.Contains(out.String(), "sh: can't fork") {
|
|
||||||
ok(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("expected fork() to fail for very small pids.max")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRunWithKernelMemory(t *testing.T) {
|
func TestRunWithKernelMemory(t *testing.T) {
|
||||||
testRunWithKernelMemory(t, false)
|
testRunWithKernelMemory(t, false)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ package libcontainer
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
@ -87,7 +86,6 @@ func (p *setnsProcess) start() (err error) {
|
||||||
if err := json.NewEncoder(p.parentPipe).Encode(p.config); err != nil {
|
if err := json.NewEncoder(p.parentPipe).Encode(p.config); err != nil {
|
||||||
return newSystemError(err)
|
return newSystemError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := syscall.Shutdown(int(p.parentPipe.Fd()), syscall.SHUT_WR); err != nil {
|
if err := syscall.Shutdown(int(p.parentPipe.Fd()), syscall.SHUT_WR); err != nil {
|
||||||
return newSystemError(err)
|
return newSystemError(err)
|
||||||
}
|
}
|
||||||
|
@ -97,7 +95,6 @@ func (p *setnsProcess) start() (err error) {
|
||||||
if err := json.NewDecoder(p.parentPipe).Decode(&ierr); err != nil && err != io.EOF {
|
if err := json.NewDecoder(p.parentPipe).Decode(&ierr); err != nil && err != io.EOF {
|
||||||
return newSystemError(err)
|
return newSystemError(err)
|
||||||
}
|
}
|
||||||
// Must be done after Shutdown so the child will exit and we can wait for it.
|
|
||||||
if ierr != nil {
|
if ierr != nil {
|
||||||
p.wait()
|
p.wait()
|
||||||
return newSystemError(ierr)
|
return newSystemError(ierr)
|
||||||
|
@ -201,6 +198,7 @@ func (p *initProcess) start() (err error) {
|
||||||
return newSystemError(err)
|
return newSystemError(err)
|
||||||
}
|
}
|
||||||
p.setExternalDescriptors(fds)
|
p.setExternalDescriptors(fds)
|
||||||
|
|
||||||
// Do this before syncing with child so that no children
|
// Do this before syncing with child so that no children
|
||||||
// can escape the cgroup
|
// can escape the cgroup
|
||||||
if err := p.manager.Apply(p.pid()); err != nil {
|
if err := p.manager.Apply(p.pid()); err != nil {
|
||||||
|
@ -231,58 +229,13 @@ func (p *initProcess) start() (err error) {
|
||||||
if err := p.sendConfig(); err != nil {
|
if err := p.sendConfig(); err != nil {
|
||||||
return newSystemError(err)
|
return newSystemError(err)
|
||||||
}
|
}
|
||||||
|
// wait for the child process to fully complete and receive an error message
|
||||||
var (
|
// if one was encoutered
|
||||||
procSync syncType
|
var ierr *genericError
|
||||||
sentRun bool
|
if err := json.NewDecoder(p.parentPipe).Decode(&ierr); err != nil && err != io.EOF {
|
||||||
ierr *genericError
|
|
||||||
)
|
|
||||||
|
|
||||||
loop:
|
|
||||||
for {
|
|
||||||
if err := json.NewDecoder(p.parentPipe).Decode(&procSync); err != nil {
|
|
||||||
if err == io.EOF {
|
|
||||||
break loop
|
|
||||||
}
|
|
||||||
return newSystemError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch procSync {
|
|
||||||
case procStart:
|
|
||||||
break loop
|
|
||||||
case procReady:
|
|
||||||
if err := p.manager.Set(p.config.Config); err != nil {
|
|
||||||
return newSystemError(err)
|
|
||||||
}
|
|
||||||
// Sync with child.
|
|
||||||
if err := json.NewEncoder(p.parentPipe).Encode(procRun); err != nil {
|
|
||||||
return newSystemError(err)
|
|
||||||
}
|
|
||||||
sentRun = true
|
|
||||||
case procError:
|
|
||||||
// wait for the child process to fully complete and receive an error message
|
|
||||||
// if one was encoutered
|
|
||||||
if err := json.NewDecoder(p.parentPipe).Decode(&ierr); err != nil && err != io.EOF {
|
|
||||||
return newSystemError(err)
|
|
||||||
}
|
|
||||||
if ierr != nil {
|
|
||||||
break loop
|
|
||||||
}
|
|
||||||
// Programmer error.
|
|
||||||
panic("No error following JSON procError payload.")
|
|
||||||
default:
|
|
||||||
return newSystemError(fmt.Errorf("Invalid JSON synchronisation payload from child."))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !sentRun {
|
|
||||||
return newSystemError(fmt.Errorf("Couldn't synchronise with container process."))
|
|
||||||
}
|
|
||||||
if err := syscall.Shutdown(int(p.parentPipe.Fd()), syscall.SHUT_WR); err != nil {
|
|
||||||
return newSystemError(err)
|
return newSystemError(err)
|
||||||
}
|
}
|
||||||
// Must be done after Shutdown so the child will exit and we can wait for it.
|
|
||||||
if ierr != nil {
|
if ierr != nil {
|
||||||
p.wait()
|
|
||||||
return newSystemError(ierr)
|
return newSystemError(ierr)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -320,7 +273,8 @@ func (p *initProcess) sendConfig() error {
|
||||||
if err := json.NewEncoder(p.parentPipe).Encode(p.config); err != nil {
|
if err := json.NewEncoder(p.parentPipe).Encode(p.config); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
// shutdown writes for the parent side of the pipe
|
||||||
|
return syscall.Shutdown(int(p.parentPipe.Fd()), syscall.SHUT_WR)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *initProcess) createNetworkInterfaces() error {
|
func (p *initProcess) createNetworkInterfaces() error {
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
package libcontainer
|
package libcontainer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
@ -15,7 +14,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type linuxStandardInit struct {
|
type linuxStandardInit struct {
|
||||||
pipe io.ReadWriter
|
|
||||||
parentPid int
|
parentPid int
|
||||||
config *initConfig
|
config *initConfig
|
||||||
}
|
}
|
||||||
|
@ -52,6 +50,7 @@ func (l *linuxStandardInit) Init() error {
|
||||||
if err := setOomScoreAdj(l.config.Config.OomScoreAdj); err != nil {
|
if err := setOomScoreAdj(l.config.Config.OomScoreAdj); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
label.Init()
|
label.Init()
|
||||||
// InitializeMountNamespace() can be executed only for a new mount namespace
|
// InitializeMountNamespace() can be executed only for a new mount namespace
|
||||||
if l.config.Config.Namespaces.Contains(configs.NEWNS) {
|
if l.config.Config.Namespaces.Contains(configs.NEWNS) {
|
||||||
|
@ -76,6 +75,7 @@ func (l *linuxStandardInit) Init() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, path := range l.config.Config.ReadonlyPaths {
|
for _, path := range l.config.Config.ReadonlyPaths {
|
||||||
if err := remountReadonly(path); err != nil {
|
if err := remountReadonly(path); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -90,12 +90,6 @@ func (l *linuxStandardInit) Init() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Tell our parent that we're ready to Execv. This must be done before the
|
|
||||||
// Seccomp rules have been applied, because we need to be able to read and
|
|
||||||
// write to a socket.
|
|
||||||
if err := syncParentReady(l.pipe); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if l.config.Config.Seccomp != nil {
|
if l.config.Config.Seccomp != nil {
|
||||||
if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil {
|
if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
1
spec.go
1
spec.go
|
@ -456,7 +456,6 @@ func createCgroupConfig(name string, spec *specs.LinuxRuntimeSpec, devices []*co
|
||||||
c.Resources.CpuRtPeriod = r.CPU.RealtimePeriod
|
c.Resources.CpuRtPeriod = r.CPU.RealtimePeriod
|
||||||
c.Resources.CpusetCpus = r.CPU.Cpus
|
c.Resources.CpusetCpus = r.CPU.Cpus
|
||||||
c.Resources.CpusetMems = r.CPU.Mems
|
c.Resources.CpusetMems = r.CPU.Mems
|
||||||
c.Resources.PidsLimit = r.Pids.Limit
|
|
||||||
c.Resources.BlkioWeight = r.BlockIO.Weight
|
c.Resources.BlkioWeight = r.BlockIO.Weight
|
||||||
c.Resources.BlkioLeafWeight = r.BlockIO.LeafWeight
|
c.Resources.BlkioLeafWeight = r.BlockIO.LeafWeight
|
||||||
for _, wd := range r.BlockIO.WeightDevice {
|
for _, wd := range r.BlockIO.WeightDevice {
|
||||||
|
|
Loading…
Reference in New Issue