diff --git a/api/grpc/server/server.go b/api/grpc/server/server.go index fb72324..b30081c 100644 --- a/api/grpc/server/server.go +++ b/api/grpc/server/server.go @@ -73,7 +73,7 @@ func (s *apiServer) AddProcess(ctx context.Context, r *types.AddProcessRequest) Env: r.Env, Cwd: r.Cwd, } - setPlatformRuntimeProcessSpecUserFields(r.User, process) + setPlatformRuntimeProcessSpecUserFields(r, process) if r.Id == "" { return nil, fmt.Errorf("container id cannot be empty") @@ -174,6 +174,40 @@ func (s *apiServer) UpdateContainer(ctx context.Context, r *types.UpdateContaine e := &supervisor.UpdateTask{} e.ID = r.Id e.State = runtime.State(r.Status) + if r.Resources != nil { + rs := r.Resources + e.Resources = &runtime.Resource{} + if rs.CpuShares != 0 { + e.Resources.CPUShares = int64(rs.CpuShares) + } + if rs.BlkioWeight != 0 { + e.Resources.BlkioWeight = uint16(rs.BlkioWeight) + } + if rs.CpuPeriod != 0 { + e.Resources.CPUPeriod = int64(rs.CpuPeriod) + } + if rs.CpuQuota != 0 { + e.Resources.CPUQuota = int64(rs.CpuQuota) + } + if rs.CpusetCpus != "" { + e.Resources.CpusetCpus = rs.CpusetCpus + } + if rs.CpusetMems != "" { + e.Resources.CpusetMems = rs.CpusetMems + } + if rs.KernelMemoryLimit != 0 { + e.Resources.KernelMemory = int64(rs.KernelMemoryLimit) + } + if rs.MemoryLimit != 0 { + e.Resources.Memory = int64(rs.MemoryLimit) + } + if rs.MemoryReservation != 0 { + e.Resources.MemoryReservation = int64(rs.MemoryReservation) + } + if rs.MemorySwap != 0 { + e.Resources.MemorySwap = int64(rs.MemorySwap) + } + } s.sv.SendTask(e) if err := <-e.ErrorCh(); err != nil { return nil, err diff --git a/api/grpc/server/server_linux.go b/api/grpc/server/server_linux.go index 087d2e9..53cb6a1 100644 --- a/api/grpc/server/server_linux.go +++ b/api/grpc/server/server_linux.go @@ -248,12 +248,20 @@ func setUserFieldsInProcess(p *types.Process, oldProc specs.ProcessSpec) { Gid: oldProc.User.GID, AdditionalGids: oldProc.User.AdditionalGids, } + p.Capabilities = oldProc.Capabilities + p.ApparmorProfile = oldProc.ApparmorProfile + p.SelinuxLabel = oldProc.SelinuxLabel + p.NoNewPrivileges = oldProc.NoNewPrivileges } -func setPlatformRuntimeProcessSpecUserFields(r *types.User, process *specs.ProcessSpec) { +func setPlatformRuntimeProcessSpecUserFields(r *types.AddProcessRequest, process *specs.ProcessSpec) { process.User = ocs.User{ - UID: r.Uid, - GID: r.Gid, - AdditionalGids: r.AdditionalGids, + UID: r.User.Uid, + GID: r.User.Gid, + AdditionalGids: r.User.AdditionalGids, } + process.Capabilities = r.Capabilities + process.ApparmorProfile = r.ApparmorProfile + process.SelinuxLabel = r.SelinuxLabel + process.NoNewPrivileges = r.NoNewPrivileges } diff --git a/api/grpc/types/api.pb.go b/api/grpc/types/api.pb.go index 10f4c38..dc77d86 100644 --- a/api/grpc/types/api.pb.go +++ b/api/grpc/types/api.pb.go @@ -32,6 +32,7 @@ It has these top-level messages: Machine StateResponse UpdateContainerRequest + UpdateResource UpdateContainerResponse EventsRequest Event @@ -136,16 +137,20 @@ func (*SignalResponse) ProtoMessage() {} func (*SignalResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } type AddProcessRequest struct { - Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` - Terminal bool `protobuf:"varint,2,opt,name=terminal" json:"terminal,omitempty"` - User *User `protobuf:"bytes,3,opt,name=user" json:"user,omitempty"` - Args []string `protobuf:"bytes,4,rep,name=args" json:"args,omitempty"` - Env []string `protobuf:"bytes,5,rep,name=env" json:"env,omitempty"` - Cwd string `protobuf:"bytes,6,opt,name=cwd" json:"cwd,omitempty"` - Pid string `protobuf:"bytes,7,opt,name=pid" json:"pid,omitempty"` - Stdin string `protobuf:"bytes,8,opt,name=stdin" json:"stdin,omitempty"` - Stdout string `protobuf:"bytes,9,opt,name=stdout" json:"stdout,omitempty"` - Stderr string `protobuf:"bytes,10,opt,name=stderr" json:"stderr,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` + Terminal bool `protobuf:"varint,2,opt,name=terminal" json:"terminal,omitempty"` + User *User `protobuf:"bytes,3,opt,name=user" json:"user,omitempty"` + Args []string `protobuf:"bytes,4,rep,name=args" json:"args,omitempty"` + Env []string `protobuf:"bytes,5,rep,name=env" json:"env,omitempty"` + Cwd string `protobuf:"bytes,6,opt,name=cwd" json:"cwd,omitempty"` + Pid string `protobuf:"bytes,7,opt,name=pid" json:"pid,omitempty"` + Stdin string `protobuf:"bytes,8,opt,name=stdin" json:"stdin,omitempty"` + Stdout string `protobuf:"bytes,9,opt,name=stdout" json:"stdout,omitempty"` + Stderr string `protobuf:"bytes,10,opt,name=stderr" json:"stderr,omitempty"` + Capabilities []string `protobuf:"bytes,11,rep,name=capabilities" json:"capabilities,omitempty"` + ApparmorProfile string `protobuf:"bytes,12,opt,name=apparmorProfile" json:"apparmorProfile,omitempty"` + SelinuxLabel string `protobuf:"bytes,13,opt,name=selinuxLabel" json:"selinuxLabel,omitempty"` + NoNewPrivileges bool `protobuf:"varint,14,opt,name=noNewPrivileges" json:"noNewPrivileges,omitempty"` } func (m *AddProcessRequest) Reset() { *m = AddProcessRequest{} } @@ -279,16 +284,20 @@ func (*ContainerState) ProtoMessage() {} func (*ContainerState) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} } type Process struct { - Pid string `protobuf:"bytes,1,opt,name=pid" json:"pid,omitempty"` - Terminal bool `protobuf:"varint,2,opt,name=terminal" json:"terminal,omitempty"` - User *User `protobuf:"bytes,3,opt,name=user" json:"user,omitempty"` - Args []string `protobuf:"bytes,4,rep,name=args" json:"args,omitempty"` - Env []string `protobuf:"bytes,5,rep,name=env" json:"env,omitempty"` - Cwd string `protobuf:"bytes,6,opt,name=cwd" json:"cwd,omitempty"` - SystemPid uint32 `protobuf:"varint,7,opt,name=systemPid" json:"systemPid,omitempty"` - Stdin string `protobuf:"bytes,8,opt,name=stdin" json:"stdin,omitempty"` - Stdout string `protobuf:"bytes,9,opt,name=stdout" json:"stdout,omitempty"` - Stderr string `protobuf:"bytes,10,opt,name=stderr" json:"stderr,omitempty"` + Pid string `protobuf:"bytes,1,opt,name=pid" json:"pid,omitempty"` + Terminal bool `protobuf:"varint,2,opt,name=terminal" json:"terminal,omitempty"` + User *User `protobuf:"bytes,3,opt,name=user" json:"user,omitempty"` + Args []string `protobuf:"bytes,4,rep,name=args" json:"args,omitempty"` + Env []string `protobuf:"bytes,5,rep,name=env" json:"env,omitempty"` + Cwd string `protobuf:"bytes,6,opt,name=cwd" json:"cwd,omitempty"` + SystemPid uint32 `protobuf:"varint,7,opt,name=systemPid" json:"systemPid,omitempty"` + Stdin string `protobuf:"bytes,8,opt,name=stdin" json:"stdin,omitempty"` + Stdout string `protobuf:"bytes,9,opt,name=stdout" json:"stdout,omitempty"` + Stderr string `protobuf:"bytes,10,opt,name=stderr" json:"stderr,omitempty"` + Capabilities []string `protobuf:"bytes,11,rep,name=capabilities" json:"capabilities,omitempty"` + ApparmorProfile string `protobuf:"bytes,12,opt,name=apparmorProfile" json:"apparmorProfile,omitempty"` + SelinuxLabel string `protobuf:"bytes,13,opt,name=selinuxLabel" json:"selinuxLabel,omitempty"` + NoNewPrivileges bool `protobuf:"varint,14,opt,name=noNewPrivileges" json:"noNewPrivileges,omitempty"` } func (m *Process) Reset() { *m = Process{} } @@ -362,9 +371,10 @@ func (m *StateResponse) GetMachine() *Machine { } type UpdateContainerRequest struct { - Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` - Pid string `protobuf:"bytes,2,opt,name=pid" json:"pid,omitempty"` - Status string `protobuf:"bytes,3,opt,name=status" json:"status,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` + Pid string `protobuf:"bytes,2,opt,name=pid" json:"pid,omitempty"` + Status string `protobuf:"bytes,3,opt,name=status" json:"status,omitempty"` + Resources *UpdateResource `protobuf:"bytes,4,opt,name=resources" json:"resources,omitempty"` } func (m *UpdateContainerRequest) Reset() { *m = UpdateContainerRequest{} } @@ -372,13 +382,38 @@ func (m *UpdateContainerRequest) String() string { return proto.Compa func (*UpdateContainerRequest) ProtoMessage() {} func (*UpdateContainerRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{22} } +func (m *UpdateContainerRequest) GetResources() *UpdateResource { + if m != nil { + return m.Resources + } + return nil +} + +type UpdateResource struct { + BlkioWeight uint32 `protobuf:"varint,1,opt,name=blkioWeight" json:"blkioWeight,omitempty"` + CpuShares uint32 `protobuf:"varint,2,opt,name=cpuShares" json:"cpuShares,omitempty"` + CpuPeriod uint32 `protobuf:"varint,3,opt,name=cpuPeriod" json:"cpuPeriod,omitempty"` + CpuQuota uint32 `protobuf:"varint,4,opt,name=cpuQuota" json:"cpuQuota,omitempty"` + CpusetCpus string `protobuf:"bytes,5,opt,name=cpusetCpus" json:"cpusetCpus,omitempty"` + CpusetMems string `protobuf:"bytes,6,opt,name=cpusetMems" json:"cpusetMems,omitempty"` + MemoryLimit uint32 `protobuf:"varint,7,opt,name=memoryLimit" json:"memoryLimit,omitempty"` + MemorySwap uint32 `protobuf:"varint,8,opt,name=memorySwap" json:"memorySwap,omitempty"` + MemoryReservation uint32 `protobuf:"varint,9,opt,name=memoryReservation" json:"memoryReservation,omitempty"` + KernelMemoryLimit uint32 `protobuf:"varint,10,opt,name=kernelMemoryLimit" json:"kernelMemoryLimit,omitempty"` +} + +func (m *UpdateResource) Reset() { *m = UpdateResource{} } +func (m *UpdateResource) String() string { return proto.CompactTextString(m) } +func (*UpdateResource) ProtoMessage() {} +func (*UpdateResource) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{23} } + type UpdateContainerResponse struct { } func (m *UpdateContainerResponse) Reset() { *m = UpdateContainerResponse{} } func (m *UpdateContainerResponse) String() string { return proto.CompactTextString(m) } func (*UpdateContainerResponse) ProtoMessage() {} -func (*UpdateContainerResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{23} } +func (*UpdateContainerResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{24} } type EventsRequest struct { Timestamp uint64 `protobuf:"varint,1,opt,name=timestamp" json:"timestamp,omitempty"` @@ -387,7 +422,7 @@ type EventsRequest struct { func (m *EventsRequest) Reset() { *m = EventsRequest{} } func (m *EventsRequest) String() string { return proto.CompactTextString(m) } func (*EventsRequest) ProtoMessage() {} -func (*EventsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{24} } +func (*EventsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{25} } type Event struct { Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` @@ -400,7 +435,7 @@ type Event struct { func (m *Event) Reset() { *m = Event{} } func (m *Event) String() string { return proto.CompactTextString(m) } func (*Event) ProtoMessage() {} -func (*Event) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{25} } +func (*Event) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{26} } type NetworkStats struct { Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` @@ -417,7 +452,7 @@ type NetworkStats struct { func (m *NetworkStats) Reset() { *m = NetworkStats{} } func (m *NetworkStats) String() string { return proto.CompactTextString(m) } func (*NetworkStats) ProtoMessage() {} -func (*NetworkStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{26} } +func (*NetworkStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{27} } type CpuUsage struct { TotalUsage uint64 `protobuf:"varint,1,opt,name=total_usage" json:"total_usage,omitempty"` @@ -429,7 +464,7 @@ type CpuUsage struct { func (m *CpuUsage) Reset() { *m = CpuUsage{} } func (m *CpuUsage) String() string { return proto.CompactTextString(m) } func (*CpuUsage) ProtoMessage() {} -func (*CpuUsage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{27} } +func (*CpuUsage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{28} } type ThrottlingData struct { Periods uint64 `protobuf:"varint,1,opt,name=periods" json:"periods,omitempty"` @@ -440,7 +475,7 @@ type ThrottlingData struct { func (m *ThrottlingData) Reset() { *m = ThrottlingData{} } func (m *ThrottlingData) String() string { return proto.CompactTextString(m) } func (*ThrottlingData) ProtoMessage() {} -func (*ThrottlingData) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{28} } +func (*ThrottlingData) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{29} } type CpuStats struct { CpuUsage *CpuUsage `protobuf:"bytes,1,opt,name=cpu_usage" json:"cpu_usage,omitempty"` @@ -451,7 +486,7 @@ type CpuStats struct { func (m *CpuStats) Reset() { *m = CpuStats{} } func (m *CpuStats) String() string { return proto.CompactTextString(m) } func (*CpuStats) ProtoMessage() {} -func (*CpuStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{29} } +func (*CpuStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{30} } func (m *CpuStats) GetCpuUsage() *CpuUsage { if m != nil { @@ -477,7 +512,7 @@ type MemoryData struct { func (m *MemoryData) Reset() { *m = MemoryData{} } func (m *MemoryData) String() string { return proto.CompactTextString(m) } func (*MemoryData) ProtoMessage() {} -func (*MemoryData) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{30} } +func (*MemoryData) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{31} } type MemoryStats struct { Cache uint64 `protobuf:"varint,1,opt,name=cache" json:"cache,omitempty"` @@ -490,7 +525,7 @@ type MemoryStats struct { func (m *MemoryStats) Reset() { *m = MemoryStats{} } func (m *MemoryStats) String() string { return proto.CompactTextString(m) } func (*MemoryStats) ProtoMessage() {} -func (*MemoryStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{31} } +func (*MemoryStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{32} } func (m *MemoryStats) GetUsage() *MemoryData { if m != nil { @@ -530,7 +565,7 @@ type BlkioStatsEntry struct { func (m *BlkioStatsEntry) Reset() { *m = BlkioStatsEntry{} } func (m *BlkioStatsEntry) String() string { return proto.CompactTextString(m) } func (*BlkioStatsEntry) ProtoMessage() {} -func (*BlkioStatsEntry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{32} } +func (*BlkioStatsEntry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{33} } type BlkioStats struct { IoServiceBytesRecursive []*BlkioStatsEntry `protobuf:"bytes,1,rep,name=io_service_bytes_recursive" json:"io_service_bytes_recursive,omitempty"` @@ -546,7 +581,7 @@ type BlkioStats struct { func (m *BlkioStats) Reset() { *m = BlkioStats{} } func (m *BlkioStats) String() string { return proto.CompactTextString(m) } func (*BlkioStats) ProtoMessage() {} -func (*BlkioStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{33} } +func (*BlkioStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{34} } func (m *BlkioStats) GetIoServiceBytesRecursive() []*BlkioStatsEntry { if m != nil { @@ -614,7 +649,7 @@ type HugetlbStats struct { func (m *HugetlbStats) Reset() { *m = HugetlbStats{} } func (m *HugetlbStats) String() string { return proto.CompactTextString(m) } func (*HugetlbStats) ProtoMessage() {} -func (*HugetlbStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{34} } +func (*HugetlbStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{35} } type CgroupStats struct { CpuStats *CpuStats `protobuf:"bytes,1,opt,name=cpu_stats" json:"cpu_stats,omitempty"` @@ -626,7 +661,7 @@ type CgroupStats struct { func (m *CgroupStats) Reset() { *m = CgroupStats{} } func (m *CgroupStats) String() string { return proto.CompactTextString(m) } func (*CgroupStats) ProtoMessage() {} -func (*CgroupStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{35} } +func (*CgroupStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{36} } func (m *CgroupStats) GetCpuStats() *CpuStats { if m != nil { @@ -665,7 +700,7 @@ type StatsResponse struct { func (m *StatsResponse) Reset() { *m = StatsResponse{} } func (m *StatsResponse) String() string { return proto.CompactTextString(m) } func (*StatsResponse) ProtoMessage() {} -func (*StatsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{36} } +func (*StatsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{37} } func (m *StatsResponse) GetNetworkStats() []*NetworkStats { if m != nil { @@ -688,7 +723,7 @@ type StatsRequest struct { func (m *StatsRequest) Reset() { *m = StatsRequest{} } func (m *StatsRequest) String() string { return proto.CompactTextString(m) } func (*StatsRequest) ProtoMessage() {} -func (*StatsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{37} } +func (*StatsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{38} } func init() { proto.RegisterType((*UpdateProcessRequest)(nil), "types.UpdateProcessRequest") @@ -714,6 +749,7 @@ func init() { proto.RegisterType((*Machine)(nil), "types.Machine") proto.RegisterType((*StateResponse)(nil), "types.StateResponse") proto.RegisterType((*UpdateContainerRequest)(nil), "types.UpdateContainerRequest") + proto.RegisterType((*UpdateResource)(nil), "types.UpdateResource") proto.RegisterType((*UpdateContainerResponse)(nil), "types.UpdateContainerResponse") proto.RegisterType((*EventsRequest)(nil), "types.EventsRequest") proto.RegisterType((*Event)(nil), "types.Event") @@ -1097,102 +1133,113 @@ var _API_serviceDesc = grpc.ServiceDesc{ } var fileDescriptor0 = []byte{ - // 1541 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x58, 0xeb, 0x6e, 0x1b, 0x45, - 0x14, 0x8e, 0x2f, 0xb1, 0xe3, 0xe3, 0x4b, 0x92, 0xcd, 0xcd, 0x71, 0x29, 0x0d, 0xdb, 0x42, 0x2b, - 0x54, 0x45, 0x25, 0xe5, 0x52, 0x8a, 0x84, 0x28, 0x69, 0x45, 0x41, 0x6d, 0x09, 0x4d, 0x82, 0xc4, - 0x2f, 0x6b, 0xbd, 0x3b, 0xd8, 0x43, 0xd6, 0xbb, 0xcb, 0xce, 0x6c, 0x2e, 0xaf, 0x00, 0xe2, 0x2f, - 0x6f, 0x81, 0xc4, 0x2f, 0x1e, 0x80, 0xc7, 0xe1, 0x29, 0x38, 0x73, 0x5b, 0xef, 0xae, 0x2f, 0x01, - 0x21, 0xfe, 0x58, 0x9a, 0x99, 0x73, 0xf9, 0xce, 0x77, 0x2e, 0x3b, 0x63, 0x68, 0x38, 0x11, 0xdd, - 0x8f, 0xe2, 0x90, 0x87, 0xd6, 0x32, 0xbf, 0x8a, 0x08, 0xb3, 0x07, 0xb0, 0x79, 0x1a, 0x79, 0x0e, - 0x27, 0x47, 0x71, 0xe8, 0x12, 0xc6, 0x5e, 0x93, 0x1f, 0x13, 0xc2, 0xb8, 0x05, 0x50, 0xa6, 0x5e, - 0xb7, 0xb4, 0x57, 0xba, 0xd7, 0xb0, 0x9a, 0x50, 0x89, 0x70, 0x51, 0x96, 0x0b, 0x3c, 0x71, 0xfd, - 0x90, 0x91, 0x63, 0xee, 0xd1, 0xa0, 0x5b, 0xc1, 0xbd, 0x15, 0xab, 0x0d, 0xcb, 0x17, 0xd4, 0xe3, - 0xa3, 0x6e, 0x15, 0x97, 0x6d, 0xab, 0x03, 0xb5, 0x11, 0xa1, 0xc3, 0x11, 0xef, 0x2e, 0x8b, 0xb5, - 0xbd, 0x03, 0x5b, 0x05, 0x1f, 0x2c, 0x0a, 0x03, 0x46, 0xec, 0x9f, 0x4b, 0xb0, 0x7d, 0x18, 0x13, - 0x3c, 0x39, 0x0c, 0x03, 0xee, 0xd0, 0x80, 0xc4, 0xb3, 0xfc, 0xe3, 0x62, 0x90, 0x04, 0x9e, 0x4f, - 0x8e, 0x1c, 0xf4, 0x31, 0x81, 0x31, 0x22, 0xee, 0x59, 0x14, 0xd2, 0x80, 0x4b, 0x18, 0x0d, 0x01, - 0x83, 0x49, 0x54, 0x55, 0xb9, 0x44, 0x18, 0xb8, 0x0c, 0x13, 0x05, 0xc3, 0xac, 0x49, 0x1c, 0x77, - 0x6b, 0x66, 0xed, 0x3b, 0x03, 0xe2, 0xb3, 0x6e, 0x7d, 0xaf, 0x72, 0xaf, 0x61, 0x7f, 0x0a, 0x3b, - 0x53, 0x60, 0x14, 0x50, 0xeb, 0x36, 0x34, 0x5c, 0xb3, 0x29, 0x41, 0x35, 0x0f, 0xd6, 0xf6, 0x25, - 0x81, 0xfb, 0xa9, 0xb0, 0xfd, 0x08, 0xda, 0xc7, 0x74, 0x18, 0x38, 0xfe, 0xb5, 0x1c, 0x0a, 0x24, - 0x52, 0x52, 0x02, 0x6f, 0xdb, 0x6b, 0xd0, 0x31, 0x9a, 0x9a, 0x99, 0xdf, 0x4b, 0xb0, 0xfe, 0xc4, - 0xf3, 0x16, 0x24, 0x65, 0x0d, 0x56, 0x38, 0x89, 0xc7, 0x54, 0x58, 0x29, 0xcb, 0x2c, 0xec, 0x42, - 0x35, 0x61, 0x88, 0xaf, 0x22, 0xf1, 0x35, 0x35, 0xbe, 0x53, 0xdc, 0xb2, 0x5a, 0x50, 0x75, 0xe2, - 0x21, 0x43, 0x62, 0x2a, 0x0a, 0x0b, 0x09, 0xce, 0x91, 0x15, 0xbd, 0x70, 0x2f, 0x3c, 0x4d, 0x89, - 0x46, 0x59, 0xcf, 0xd3, 0xb9, 0x52, 0xa0, 0xb3, 0x51, 0xa0, 0x13, 0xc4, 0x1a, 0xc3, 0xaf, 0x4a, - 0x5f, 0x68, 0x23, 0xd1, 0x28, 0xdb, 0x62, 0x31, 0xd4, 0x61, 0xb7, 0xad, 0x6d, 0xe8, 0x38, 0x9e, - 0x47, 0x39, 0x0d, 0x11, 0xf4, 0x17, 0xd4, 0x63, 0x08, 0xb5, 0x82, 0xe1, 0x6f, 0x82, 0x95, 0x8d, - 0x55, 0x53, 0xf0, 0x22, 0x4d, 0x47, 0x9a, 0xe7, 0x59, 0x3c, 0xbc, 0x9d, 0x2b, 0x84, 0xb2, 0x8c, - 0x7d, 0xdd, 0xe4, 0x26, 0x3d, 0xb0, 0x7b, 0xd0, 0x9d, 0xb6, 0xa6, 0x3d, 0x3d, 0x84, 0x9d, 0xa7, - 0xc4, 0x27, 0xd7, 0x79, 0x42, 0x12, 0x03, 0x67, 0x4c, 0x54, 0x0e, 0x85, 0xc1, 0x69, 0x25, 0x6d, - 0xf0, 0x36, 0x6c, 0xbd, 0xa0, 0x8c, 0x2f, 0x34, 0x67, 0x7f, 0x07, 0x30, 0x11, 0x48, 0x8d, 0xa7, - 0xae, 0xc8, 0x25, 0xe5, 0x3a, 0xb1, 0x48, 0x22, 0x77, 0x23, 0xdd, 0x6b, 0x1b, 0xd0, 0x4c, 0x02, - 0x7a, 0x79, 0x1c, 0xba, 0x67, 0x84, 0x33, 0x59, 0xea, 0xb2, 0x01, 0xd9, 0x88, 0xf8, 0xbe, 0xac, - 0xf4, 0x15, 0xfb, 0x33, 0xd8, 0x2e, 0xfa, 0xd7, 0x85, 0xfc, 0x0e, 0x34, 0x27, 0x6c, 0x31, 0xf4, - 0x56, 0x99, 0x47, 0x57, 0xeb, 0x98, 0x23, 0x5b, 0xb3, 0x80, 0xef, 0x41, 0x27, 0x2d, 0x7a, 0x29, - 0xa4, 0x4a, 0xc1, 0xe1, 0x09, 0xd3, 0x12, 0xbf, 0x95, 0xa0, 0xae, 0xd3, 0x69, 0x4a, 0xea, 0x7f, - 0x2c, 0xda, 0x75, 0x68, 0xb0, 0x2b, 0xc6, 0xc9, 0xf8, 0x48, 0x97, 0x6e, 0xfb, 0xdf, 0x96, 0xee, - 0x2f, 0x25, 0x68, 0xa4, 0x21, 0x5d, 0x3b, 0x7a, 0xde, 0x82, 0x46, 0xa4, 0x82, 0x23, 0xaa, 0x82, - 0x9b, 0x07, 0x1d, 0x8d, 0xdb, 0x04, 0x3d, 0x21, 0xa4, 0x5a, 0x18, 0x35, 0x0a, 0x3f, 0x86, 0x16, - 0x89, 0xfa, 0xaf, 0x89, 0xfa, 0xb7, 0x56, 0xa1, 0x1e, 0x27, 0x01, 0xa7, 0x98, 0x7e, 0xd9, 0x79, - 0xf6, 0x5d, 0xa8, 0xbf, 0x74, 0xdc, 0x11, 0xa2, 0x11, 0x92, 0x6e, 0xa4, 0x89, 0x95, 0x93, 0x75, - 0x4c, 0xc6, 0x61, 0x7c, 0x25, 0xa1, 0x54, 0xed, 0x6f, 0x71, 0xe4, 0xa8, 0x34, 0xe9, 0xfc, 0xde, - 0xc1, 0x6e, 0x30, 0x81, 0x98, 0xf4, 0x4e, 0x4d, 0x2a, 0xeb, 0x16, 0xd4, 0xc7, 0xca, 0xbe, 0x6e, - 0x18, 0x83, 0x5f, 0x7b, 0xb5, 0x9f, 0xc0, 0xb6, 0x9a, 0xd8, 0x0b, 0xe7, 0xf2, 0xd4, 0x4c, 0x53, - 0x21, 0xcb, 0x61, 0x6c, 0xef, 0xc2, 0xce, 0x94, 0x09, 0xdd, 0x1e, 0x36, 0xb4, 0x9f, 0x9d, 0x13, - 0xac, 0x3f, 0x63, 0x14, 0x33, 0x28, 0xa2, 0x47, 0xfd, 0x71, 0x24, 0x6d, 0x57, 0xed, 0x6f, 0x60, - 0x59, 0xca, 0x08, 0x02, 0x04, 0x36, 0xed, 0x52, 0xb9, 0x9f, 0xe5, 0xb1, 0x6d, 0xe0, 0x54, 0x4d, - 0x51, 0x4c, 0x4c, 0x2e, 0x4b, 0x93, 0x7f, 0x94, 0xa0, 0xf5, 0x8a, 0xf0, 0x8b, 0x30, 0x3e, 0x13, - 0xa4, 0xb1, 0x42, 0xcf, 0x61, 0x6d, 0xc6, 0x97, 0xfd, 0xc1, 0x15, 0xc7, 0xac, 0x4a, 0x76, 0x45, - 0xf2, 0x71, 0xe7, 0xc8, 0x51, 0x9d, 0x56, 0x91, 0x7b, 0x68, 0xf7, 0xf5, 0x65, 0x1f, 0x4b, 0x27, - 0x8c, 0x55, 0x72, 0xa5, 0x18, 0x6e, 0x79, 0x71, 0x18, 0x45, 0xc4, 0x53, 0xbe, 0x84, 0xb1, 0x13, - 0x63, 0xac, 0x66, 0xa4, 0x70, 0x27, 0xd2, 0xc6, 0xea, 0xc6, 0xd8, 0x49, 0x6a, 0x6c, 0x25, 0x23, - 0x66, 0x8c, 0x35, 0x24, 0xf0, 0x31, 0xac, 0x1c, 0x46, 0xc9, 0x29, 0x73, 0x86, 0x44, 0xb4, 0x3f, - 0x0f, 0xb9, 0xe3, 0xf7, 0x13, 0xb1, 0x54, 0x64, 0x59, 0x9b, 0xd0, 0x8a, 0x48, 0x8c, 0x75, 0xa2, - 0x77, 0xcb, 0x98, 0xf7, 0xaa, 0x75, 0x03, 0x36, 0xe4, 0xb2, 0x4f, 0x83, 0xfe, 0x19, 0x89, 0x03, - 0xe2, 0x8f, 0x43, 0x8f, 0xe8, 0x38, 0x76, 0x61, 0x3d, 0x3d, 0x14, 0x0d, 0x28, 0x8f, 0x64, 0x3c, - 0xf6, 0x09, 0x74, 0x4e, 0x46, 0x78, 0x47, 0xe0, 0x3e, 0x0d, 0x86, 0x4f, 0x1d, 0xee, 0x88, 0x02, - 0x45, 0xfb, 0x34, 0xf4, 0x98, 0x76, 0x88, 0xda, 0x5c, 0x89, 0x10, 0xaf, 0x6f, 0x8e, 0x14, 0x69, - 0x38, 0xe4, 0x27, 0x47, 0xb2, 0xa6, 0xa5, 0x43, 0x9b, 0xcb, 0x20, 0x14, 0xf1, 0x36, 0x7e, 0x4e, - 0x53, 0xb0, 0xea, 0x73, 0xba, 0x6a, 0x8a, 0xd4, 0x04, 0xba, 0x0f, 0xab, 0x3c, 0x45, 0xd1, 0xc7, - 0x42, 0x72, 0x74, 0xad, 0x6e, 0x69, 0xc9, 0x02, 0x46, 0xe4, 0x40, 0x4d, 0x01, 0x6d, 0x56, 0x79, - 0x7d, 0x05, 0xf0, 0x52, 0x36, 0x8c, 0x94, 0xc1, 0xb1, 0x90, 0xa5, 0x0d, 0xe9, 0x1f, 0x3b, 0x97, - 0x29, 0x67, 0x62, 0x0b, 0x23, 0xfd, 0xde, 0xa1, 0xbe, 0xab, 0xef, 0x14, 0x55, 0xa1, 0xe2, 0xd3, - 0x31, 0x8e, 0x62, 0xc5, 0xcd, 0x5f, 0x25, 0x68, 0x2a, 0x83, 0x2a, 0x12, 0x3c, 0x76, 0xb1, 0x67, - 0x8c, 0xc5, 0x3d, 0xe3, 0x20, 0xff, 0x1d, 0xca, 0x40, 0xc0, 0xcf, 0x15, 0xbb, 0x70, 0xa2, 0x0c, - 0xc8, 0x99, 0x62, 0x77, 0xa1, 0xa5, 0x52, 0xa6, 0x05, 0xab, 0xf3, 0x04, 0xef, 0x8b, 0x49, 0x87, - 0x48, 0xe4, 0x60, 0x69, 0x1e, 0xdc, 0xcc, 0x49, 0x48, 0x8c, 0xfb, 0xf2, 0xf7, 0x59, 0xc0, 0xe3, - 0xab, 0xde, 0x7d, 0x80, 0xc9, 0x4a, 0x34, 0xcc, 0x19, 0xb9, 0xd2, 0xe5, 0x8f, 0x91, 0x9c, 0x3b, - 0x7e, 0xa2, 0x89, 0x78, 0x5c, 0x7e, 0x54, 0xb2, 0xbf, 0x82, 0xd5, 0xcf, 0xfd, 0x33, 0x1a, 0x66, - 0x54, 0x50, 0x6a, 0xec, 0xfc, 0x10, 0xc6, 0x3a, 0x5e, 0xb1, 0xa4, 0x01, 0x2e, 0x15, 0x7b, 0xd8, - 0x9d, 0x61, 0x34, 0xb9, 0x8c, 0x29, 0x7b, 0x8a, 0xb8, 0x3f, 0x2b, 0x00, 0x13, 0x63, 0xd6, 0x63, - 0xe8, 0xd1, 0xb0, 0x8f, 0x75, 0x77, 0x4e, 0x5d, 0xa2, 0xfa, 0xa4, 0x1f, 0x13, 0x37, 0x89, 0x19, - 0x3d, 0x27, 0x7a, 0x6e, 0x6d, 0xeb, 0x58, 0x8a, 0x18, 0x3e, 0x80, 0xad, 0x89, 0xae, 0x97, 0x51, - 0x2b, 0x2f, 0x54, 0x7b, 0x08, 0x1b, 0xa8, 0x86, 0x03, 0x27, 0xc9, 0x29, 0x55, 0x16, 0x2a, 0x7d, - 0x0c, 0xbb, 0x19, 0x9c, 0xa2, 0x9c, 0x33, 0xaa, 0xd5, 0x85, 0xaa, 0x1f, 0xc2, 0x36, 0xaa, 0x5e, - 0x38, 0x94, 0x17, 0xf5, 0x96, 0xff, 0x01, 0xce, 0x31, 0x89, 0x87, 0x39, 0x9c, 0xb5, 0x85, 0x4a, - 0xef, 0xc1, 0x3a, 0x2a, 0x15, 0xfc, 0xd4, 0xaf, 0x53, 0x61, 0xc4, 0xe5, 0x38, 0x7a, 0x32, 0x2a, - 0x2b, 0x8b, 0x54, 0xec, 0x23, 0x68, 0x3d, 0x4f, 0x86, 0x84, 0xfb, 0x83, 0xb4, 0xfa, 0xff, 0x63, - 0x3f, 0xfd, 0x54, 0x86, 0xe6, 0xe1, 0x30, 0x0e, 0x93, 0x28, 0x37, 0x19, 0x54, 0x49, 0x4f, 0x4d, - 0x06, 0x25, 0x73, 0x0f, 0x5a, 0xea, 0x23, 0xa8, 0xc5, 0x54, 0xaf, 0x59, 0xd3, 0x95, 0x2f, 0x6e, - 0x3b, 0x03, 0x11, 0x82, 0x16, 0xcc, 0x77, 0x5b, 0xa6, 0x1a, 0x3f, 0x81, 0xf6, 0x48, 0xc5, 0xa5, - 0x25, 0x55, 0x66, 0xef, 0x18, 0xcf, 0x13, 0x80, 0xfb, 0xd9, 0xf8, 0x55, 0x4f, 0x3d, 0x87, 0xf5, - 0xa9, 0xcd, 0x7c, 0x6b, 0xd9, 0xd9, 0xd6, 0x6a, 0x1e, 0x6c, 0x68, 0xb3, 0x59, 0x2d, 0xd9, 0x6f, - 0x97, 0xea, 0x6b, 0x9e, 0x5e, 0x81, 0xad, 0x77, 0xa1, 0x1d, 0xa8, 0x0f, 0x56, 0xca, 0x48, 0x25, - 0x63, 0x20, 0xf7, 0x31, 0x43, 0x56, 0x5c, 0x89, 0x73, 0x26, 0x2b, 0x59, 0x8e, 0x73, 0x9f, 0x46, - 0x35, 0x26, 0xf5, 0x75, 0x6f, 0xd6, 0x43, 0xe3, 0xe0, 0xd7, 0x1a, 0x54, 0x9e, 0x1c, 0x7d, 0x69, - 0xbd, 0x86, 0xd5, 0xc2, 0xf3, 0xc8, 0x32, 0xd3, 0x66, 0xf6, 0x1b, 0xae, 0xf7, 0xe6, 0xbc, 0x63, - 0x7d, 0x0f, 0x58, 0x12, 0x36, 0x0b, 0x97, 0x84, 0xd4, 0xe6, 0xec, 0xfb, 0x47, 0x6a, 0x73, 0xde, - 0xdd, 0x62, 0xc9, 0xfa, 0x08, 0x6a, 0xea, 0x31, 0x65, 0x6d, 0x6a, 0xd9, 0xdc, 0xab, 0xac, 0xb7, - 0x55, 0xd8, 0x4d, 0x15, 0x5f, 0x40, 0x3b, 0xf7, 0x4c, 0xb5, 0x6e, 0xe4, 0x7c, 0xe5, 0xdf, 0x62, - 0xbd, 0x37, 0x66, 0x1f, 0xa6, 0xd6, 0x0e, 0x01, 0x26, 0x8f, 0x1a, 0xab, 0xab, 0xa5, 0xa7, 0xde, - 0x74, 0xbd, 0xdd, 0x19, 0x27, 0xa9, 0x91, 0x53, 0x58, 0x2b, 0xbe, 0x5a, 0xac, 0x02, 0xab, 0xc5, - 0x37, 0x46, 0xef, 0xd6, 0xdc, 0xf3, 0xac, 0xd9, 0xe2, 0xdb, 0x25, 0x35, 0x3b, 0xe7, 0x25, 0x94, - 0x9a, 0x9d, 0xfb, 0xe8, 0x59, 0xb2, 0xbe, 0x86, 0x4e, 0xfe, 0xd9, 0x61, 0x19, 0x92, 0x66, 0xbe, - 0x86, 0x7a, 0x37, 0xe7, 0x9c, 0xa6, 0x06, 0xdf, 0x87, 0x65, 0xf5, 0xc0, 0x30, 0x15, 0x9f, 0x7d, - 0x93, 0xf4, 0x36, 0xf3, 0x9b, 0xa9, 0xd6, 0x03, 0xa8, 0xa9, 0xeb, 0x65, 0x5a, 0x00, 0xb9, 0xdb, - 0x66, 0xaf, 0x95, 0xdd, 0xb5, 0x97, 0x1e, 0x94, 0x8c, 0x1f, 0x96, 0xf3, 0xc3, 0x66, 0xf9, 0xc9, - 0x24, 0x67, 0x50, 0x93, 0x7f, 0xa4, 0x3c, 0xfc, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x0a, 0x94, 0xe5, - 0x0c, 0x55, 0x11, 0x00, 0x00, + // 1723 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xcc, 0x58, 0xd9, 0x6e, 0xdb, 0x46, + 0x17, 0xb6, 0x76, 0xeb, 0x68, 0xb1, 0x4d, 0x6f, 0xb2, 0xf2, 0xe7, 0x8f, 0x7f, 0x26, 0x7f, 0x63, + 0x14, 0x81, 0x91, 0x3a, 0x5d, 0xd2, 0x14, 0x28, 0x9a, 0x3a, 0x41, 0xd3, 0xc2, 0x49, 0x15, 0x2f, + 0x2d, 0x7a, 0x25, 0x50, 0xe4, 0x44, 0x62, 0x4d, 0x91, 0x2c, 0x67, 0xe8, 0xe5, 0x15, 0x1a, 0xb4, + 0x97, 0x7d, 0x94, 0x3e, 0x40, 0x9f, 0xa5, 0x57, 0x7d, 0x8a, 0x9e, 0xd9, 0x28, 0x92, 0x5a, 0x5c, + 0xa0, 0x28, 0xd0, 0x1b, 0x01, 0x33, 0x73, 0xd6, 0xef, 0x9c, 0xef, 0x0c, 0x47, 0x50, 0xb7, 0x42, + 0x77, 0x3f, 0x8c, 0x02, 0x16, 0x18, 0x15, 0x76, 0x1d, 0x12, 0x6a, 0x0e, 0x60, 0xe3, 0x2c, 0x74, + 0x2c, 0x46, 0x7a, 0x51, 0x60, 0x13, 0x4a, 0x8f, 0xc9, 0x0f, 0x31, 0xa1, 0xcc, 0x00, 0x28, 0xba, + 0x4e, 0xa7, 0xb0, 0x5b, 0xd8, 0xab, 0x1b, 0x0d, 0x28, 0x85, 0xb8, 0x28, 0x8a, 0x05, 0x9e, 0xd8, + 0x5e, 0x40, 0xc9, 0x09, 0x73, 0x5c, 0xbf, 0x53, 0xc2, 0xbd, 0x65, 0xa3, 0x05, 0x95, 0x4b, 0xd7, + 0x61, 0xa3, 0x4e, 0x19, 0x97, 0x2d, 0xa3, 0x0d, 0xd5, 0x11, 0x71, 0x87, 0x23, 0xd6, 0xa9, 0xf0, + 0xb5, 0xb9, 0x0d, 0x9b, 0x39, 0x1f, 0x34, 0x0c, 0x7c, 0x4a, 0xcc, 0xb7, 0x05, 0xd8, 0x3a, 0x8c, + 0x08, 0x9e, 0x1c, 0x06, 0x3e, 0xb3, 0x5c, 0x9f, 0x44, 0xb3, 0xfc, 0xe3, 0x62, 0x10, 0xfb, 0x8e, + 0x47, 0x7a, 0x16, 0xfa, 0x98, 0x84, 0x31, 0x22, 0xf6, 0x79, 0x18, 0xb8, 0x3e, 0x13, 0x61, 0xd4, + 0x79, 0x18, 0x54, 0x44, 0x55, 0x16, 0x4b, 0x0c, 0x03, 0x97, 0x41, 0x2c, 0xc3, 0xd0, 0x6b, 0x12, + 0x45, 0x9d, 0xaa, 0x5e, 0x7b, 0xd6, 0x80, 0x78, 0xb4, 0x53, 0xdb, 0x2d, 0xed, 0xd5, 0xcd, 0x4f, + 0x61, 0x7b, 0x2a, 0x18, 0x19, 0xa8, 0x71, 0x17, 0xea, 0xb6, 0xde, 0x14, 0x41, 0x35, 0x0e, 0x56, + 0xf7, 0x05, 0x80, 0xfb, 0x89, 0xb0, 0xf9, 0x18, 0x5a, 0x27, 0xee, 0xd0, 0xb7, 0xbc, 0x1b, 0x31, + 0xe4, 0x91, 0x08, 0x49, 0x11, 0x78, 0xcb, 0x5c, 0x85, 0xb6, 0xd6, 0x54, 0xc8, 0xfc, 0x5c, 0x84, + 0xb5, 0xa7, 0x8e, 0xb3, 0xa0, 0x28, 0xab, 0xb0, 0xcc, 0x48, 0x34, 0x76, 0xb9, 0x95, 0xa2, 0xa8, + 0xc2, 0x0e, 0x94, 0x63, 0x8a, 0xf1, 0x95, 0x44, 0x7c, 0x0d, 0x15, 0xdf, 0x19, 0x6e, 0x19, 0x4d, + 0x28, 0x5b, 0xd1, 0x90, 0x22, 0x30, 0x25, 0x19, 0x0b, 0xf1, 0x2f, 0x10, 0x15, 0xb5, 0xb0, 0x2f, + 0x1d, 0x05, 0x89, 0x8a, 0xb2, 0x96, 0x85, 0x73, 0x39, 0x07, 0x67, 0x3d, 0x07, 0x27, 0x88, 0xf5, + 0x06, 0x34, 0x6d, 0x2b, 0xb4, 0x06, 0xae, 0xe7, 0x32, 0x97, 0xd0, 0x4e, 0x43, 0x98, 0xdf, 0x86, + 0x15, 0x2b, 0x0c, 0xad, 0x68, 0x1c, 0x44, 0x98, 0xcc, 0x1b, 0xd7, 0x23, 0x9d, 0xa6, 0x16, 0xa7, + 0xc4, 0x73, 0xfd, 0xf8, 0xea, 0x88, 0x17, 0xa1, 0xd3, 0x12, 0xbb, 0x28, 0xee, 0x07, 0xaf, 0xc8, + 0x65, 0x2f, 0x72, 0x2f, 0x50, 0x76, 0x88, 0x76, 0xda, 0x3c, 0x39, 0x04, 0xb7, 0x2c, 0x32, 0xc1, + 0x08, 0x63, 0x85, 0x41, 0x8b, 0x2f, 0x86, 0x0a, 0xd4, 0x96, 0xb1, 0x05, 0x6d, 0xcb, 0x71, 0xd0, + 0x77, 0x80, 0x90, 0x7c, 0xe1, 0x3a, 0x14, 0x81, 0x28, 0x21, 0xb8, 0x1b, 0x60, 0xa4, 0x91, 0x54, + 0x00, 0x1f, 0x25, 0xc5, 0x4e, 0xba, 0x68, 0x16, 0xca, 0xff, 0xcf, 0xb4, 0x59, 0x51, 0x20, 0xbb, + 0xa6, 0x2b, 0x9f, 0x1c, 0x98, 0x5d, 0xe8, 0x4c, 0x5b, 0x53, 0x9e, 0x1e, 0xc1, 0xf6, 0x33, 0xe2, + 0x91, 0x9b, 0x3c, 0x61, 0x89, 0x7c, 0x6b, 0x4c, 0x64, 0x87, 0x70, 0x83, 0xd3, 0x4a, 0xca, 0xe0, + 0x5d, 0xd8, 0x3c, 0x72, 0x29, 0x5b, 0x68, 0xce, 0xfc, 0x0e, 0x60, 0x22, 0x90, 0x18, 0x4f, 0x5c, + 0x91, 0x2b, 0x97, 0xa9, 0xb6, 0x41, 0x10, 0x99, 0x1d, 0x2a, 0x26, 0xaf, 0x43, 0x23, 0xf6, 0xdd, + 0xab, 0x93, 0xc0, 0x3e, 0x27, 0x8c, 0x0a, 0x22, 0x09, 0x7a, 0xd3, 0x11, 0xf1, 0x3c, 0xc1, 0xa3, + 0x65, 0xf3, 0x33, 0xd8, 0xca, 0xfb, 0x57, 0x34, 0x79, 0x07, 0x1a, 0x13, 0xb4, 0x28, 0x7a, 0x2b, + 0xcd, 0x83, 0xab, 0x79, 0xc2, 0x10, 0xad, 0x59, 0x81, 0xef, 0x42, 0x3b, 0xa1, 0x94, 0x10, 0x92, + 0x8d, 0x66, 0xb1, 0x98, 0x2a, 0x89, 0xb7, 0x45, 0xa8, 0xa9, 0x72, 0xea, 0x86, 0xfd, 0x07, 0x29, + 0xb1, 0x06, 0x75, 0x7a, 0x4d, 0x19, 0x19, 0xf7, 0x14, 0x31, 0x5a, 0xff, 0x2e, 0x62, 0xfc, 0x54, + 0x80, 0x7a, 0x02, 0xd8, 0x8d, 0x63, 0xf3, 0x7f, 0x50, 0x0f, 0x25, 0x74, 0x44, 0xf2, 0xa3, 0x71, + 0xd0, 0x56, 0xa8, 0x68, 0x48, 0x27, 0x70, 0x97, 0x73, 0x63, 0x52, 0xa2, 0x83, 0xc0, 0x85, 0x9c, + 0x5d, 0x55, 0xce, 0x2e, 0x63, 0x05, 0x6a, 0x51, 0xec, 0x33, 0x17, 0x9b, 0x4b, 0x4c, 0x0d, 0xf3, + 0x3e, 0xd4, 0x5e, 0x5a, 0xf6, 0x08, 0xa3, 0xe1, 0x92, 0x76, 0xa8, 0xca, 0x26, 0x6e, 0x85, 0x31, + 0xc1, 0x6c, 0xaf, 0x45, 0x28, 0x65, 0xf3, 0x1b, 0x1c, 0x97, 0xb2, 0x09, 0x54, 0xf7, 0xdc, 0x43, + 0xae, 0xe9, 0x44, 0x74, 0xf3, 0x4c, 0x4d, 0x59, 0xe3, 0x0e, 0xd4, 0xc6, 0xd2, 0xbe, 0xa2, 0xa3, + 0x8e, 0x5f, 0x79, 0x35, 0xcf, 0x61, 0x4b, 0xde, 0x36, 0x0b, 0xef, 0x94, 0xa9, 0x79, 0x2c, 0x53, + 0x96, 0x17, 0xc9, 0x1e, 0xd4, 0x23, 0x42, 0x83, 0x38, 0x42, 0x40, 0x04, 0x0a, 0x8d, 0x83, 0x4d, + 0xdd, 0x3b, 0xc2, 0xf4, 0xb1, 0x3a, 0x35, 0x7f, 0x2f, 0x40, 0x3b, 0xbb, 0xc5, 0x29, 0x34, 0xf0, + 0xce, 0xdd, 0xe0, 0x5b, 0x79, 0x05, 0xca, 0xe4, 0xb1, 0x8b, 0x10, 0x8a, 0x93, 0x91, 0x85, 0x76, + 0xd5, 0xbc, 0x92, 0x5b, 0x3d, 0x12, 0xb9, 0x81, 0x23, 0xef, 0x01, 0xde, 0xc0, 0xb8, 0xf5, 0x3a, + 0x0e, 0x98, 0xa5, 0xae, 0x52, 0x7e, 0xcd, 0x21, 0x84, 0x84, 0x1d, 0x72, 0x20, 0x2b, 0xc9, 0xd5, + 0x27, 0xf6, 0x5e, 0x92, 0x31, 0x55, 0x5d, 0x8a, 0x4e, 0x25, 0xb8, 0x47, 0xee, 0x18, 0x99, 0x5d, + 0xd3, 0xca, 0x72, 0xf3, 0xe4, 0xd2, 0x0a, 0x45, 0xb3, 0xb6, 0x90, 0x11, 0x6b, 0x72, 0x0f, 0xe3, + 0x25, 0xd1, 0x85, 0xc5, 0xc7, 0xa5, 0xe8, 0x5b, 0x71, 0x74, 0x4e, 0x22, 0x9f, 0x78, 0x2f, 0x53, + 0x96, 0x40, 0x5c, 0x50, 0x3b, 0xb0, 0x3d, 0x85, 0xa9, 0x9a, 0x46, 0x26, 0xb4, 0x9e, 0x5f, 0x10, + 0xa4, 0xbb, 0x46, 0x19, 0xf3, 0xe2, 0xed, 0x80, 0x80, 0x8e, 0x43, 0x91, 0x7d, 0xd9, 0x7c, 0x0d, + 0x15, 0x21, 0xc3, 0x3b, 0x82, 0xc3, 0xa8, 0x6a, 0x20, 0xeb, 0x31, 0xab, 0x04, 0x2d, 0x5d, 0x9f, + 0xb2, 0xe6, 0xe0, 0xc4, 0x64, 0x45, 0x98, 0xfc, 0xb5, 0x00, 0xcd, 0x57, 0x84, 0x5d, 0x06, 0xd1, + 0x39, 0xef, 0x22, 0x9a, 0x1b, 0x71, 0x88, 0x64, 0x74, 0xd5, 0x1f, 0x5c, 0x33, 0x05, 0x77, 0x99, + 0x83, 0x81, 0x3b, 0x3d, 0x4b, 0x0e, 0xb6, 0x92, 0xd8, 0x43, 0xbb, 0xc7, 0x57, 0x7d, 0x64, 0x6a, + 0x10, 0xc9, 0x3a, 0x0b, 0x31, 0xdc, 0x72, 0xa2, 0x20, 0x0c, 0x89, 0x23, 0x7d, 0x71, 0x63, 0xa7, + 0xda, 0x58, 0x55, 0x4b, 0xe1, 0x4e, 0xa8, 0x8c, 0xd5, 0xb4, 0xb1, 0xd3, 0xc4, 0xd8, 0x72, 0x4a, + 0x4c, 0x1b, 0xab, 0x8b, 0xc0, 0xc7, 0xb0, 0x8c, 0xb5, 0x3c, 0xa3, 0xd6, 0x50, 0xb4, 0x0a, 0xc3, + 0x5a, 0x7b, 0xfd, 0x98, 0x2f, 0x25, 0x58, 0x9c, 0xff, 0x21, 0x89, 0xb0, 0xc2, 0x6a, 0xb7, 0x88, + 0x44, 0x28, 0x1b, 0xb7, 0x60, 0x5d, 0x2c, 0xfb, 0xae, 0xdf, 0x97, 0x55, 0x1a, 0x07, 0x0e, 0x51, + 0x79, 0x60, 0xe5, 0x92, 0x43, 0x3e, 0xef, 0xc4, 0x91, 0xc8, 0xc7, 0x3c, 0x85, 0xf6, 0xe9, 0x08, + 0x3f, 0xf8, 0x18, 0x4e, 0x94, 0xe1, 0x33, 0x8b, 0x59, 0x9c, 0xb1, 0xa1, 0x68, 0x3a, 0xaa, 0x1c, + 0xa2, 0x36, 0x93, 0x22, 0xc4, 0xe9, 0xeb, 0x23, 0x09, 0x1a, 0xde, 0xa9, 0x93, 0x23, 0x41, 0x72, + 0xe1, 0xd0, 0x64, 0x22, 0x09, 0x09, 0xbc, 0x29, 0xfa, 0x38, 0x95, 0x42, 0xe3, 0x60, 0x45, 0xb3, + 0x56, 0x27, 0xba, 0x0f, 0x2b, 0x2c, 0x89, 0xa2, 0x8f, 0x8d, 0x64, 0x29, 0xf2, 0x6a, 0x5a, 0xe5, + 0x62, 0xe4, 0x33, 0x50, 0x0c, 0x5d, 0x65, 0x56, 0x7a, 0x7d, 0x05, 0x20, 0x5b, 0x53, 0xc8, 0xe0, + 0x14, 0x4e, 0xc3, 0x86, 0xf0, 0x8f, 0xad, 0xab, 0x04, 0x33, 0xbe, 0x85, 0x99, 0xbe, 0xb1, 0x5c, + 0xcf, 0x56, 0x1f, 0x88, 0x65, 0xae, 0xe2, 0x89, 0xae, 0x96, 0xd8, 0xfc, 0x51, 0x80, 0x86, 0x34, + 0x28, 0x33, 0xc1, 0x63, 0x1b, 0x87, 0x88, 0xb6, 0xb8, 0xab, 0x1d, 0x64, 0xaf, 0xfd, 0x54, 0x08, + 0xf8, 0x75, 0x40, 0x91, 0x5a, 0xa9, 0x20, 0x67, 0x8a, 0xdd, 0x87, 0xa6, 0x2c, 0x99, 0x12, 0x2c, + 0xcf, 0x13, 0x7c, 0xc0, 0x2f, 0x16, 0x8c, 0x44, 0x4c, 0xda, 0xc6, 0xc1, 0xed, 0x8c, 0x84, 0x88, + 0x71, 0x5f, 0xfc, 0x3e, 0xf7, 0x59, 0x74, 0xdd, 0x7d, 0x00, 0x30, 0x59, 0x71, 0xc2, 0x9c, 0x93, + 0x6b, 0xd5, 0xfe, 0x98, 0xc9, 0x85, 0xe5, 0xc5, 0x0a, 0x88, 0x27, 0xc5, 0xc7, 0x05, 0xf3, 0x2b, + 0x58, 0xf9, 0x9c, 0x8f, 0xa5, 0x94, 0x0a, 0x4a, 0x8d, 0xad, 0xef, 0x83, 0x48, 0xe5, 0xcb, 0x97, + 0xae, 0x8f, 0x4b, 0x89, 0x1e, 0xb2, 0x33, 0x08, 0x27, 0x5f, 0xd6, 0xd2, 0x9e, 0x04, 0xee, 0xb7, + 0x12, 0xc0, 0xc4, 0x98, 0xf1, 0x04, 0xba, 0x6e, 0xd0, 0xe7, 0xe3, 0xc4, 0xb5, 0x89, 0xe4, 0x49, + 0x3f, 0x22, 0x76, 0x1c, 0x51, 0xf7, 0x82, 0xa8, 0x41, 0xbe, 0xa5, 0x72, 0xc9, 0xc7, 0xf0, 0x01, + 0x6c, 0x4e, 0x74, 0x9d, 0x94, 0x5a, 0x71, 0xa1, 0xda, 0x23, 0x58, 0x47, 0x35, 0x1c, 0x38, 0x71, + 0x46, 0xa9, 0xb4, 0x50, 0xe9, 0x63, 0xd8, 0x49, 0xc5, 0xc9, 0xdb, 0x39, 0xa5, 0x5a, 0x5e, 0xa8, + 0xfa, 0x21, 0x6c, 0xa1, 0xea, 0xa5, 0xe5, 0xb2, 0xbc, 0x5e, 0xe5, 0x2f, 0xc4, 0x39, 0x26, 0xd1, + 0x30, 0x13, 0x67, 0x75, 0xa1, 0xd2, 0x7b, 0xb0, 0x86, 0x4a, 0x39, 0x3f, 0xb5, 0x9b, 0x54, 0x28, + 0xb1, 0x19, 0x8e, 0x9e, 0x94, 0xca, 0xf2, 0x22, 0x15, 0xb3, 0x07, 0xcd, 0x17, 0xf1, 0x90, 0x30, + 0x6f, 0x90, 0x74, 0xff, 0xdf, 0xe4, 0xd3, 0x8f, 0x45, 0x68, 0x1c, 0x0e, 0xa3, 0x20, 0x0e, 0x33, + 0x93, 0x41, 0xb6, 0xf4, 0xd4, 0x64, 0x90, 0x32, 0x7b, 0xd0, 0x94, 0xf7, 0x91, 0x12, 0x93, 0x5c, + 0x33, 0xa6, 0x3b, 0x9f, 0x7f, 0x5c, 0x8a, 0x7b, 0x55, 0x09, 0x66, 0xd9, 0x96, 0xea, 0xc6, 0x4f, + 0xa0, 0x35, 0x92, 0x79, 0x29, 0x49, 0x59, 0xd9, 0x7b, 0xda, 0xf3, 0x24, 0xc0, 0xfd, 0x74, 0xfe, + 0x92, 0x53, 0x2f, 0x60, 0x6d, 0x6a, 0x33, 0x4b, 0x2d, 0x33, 0x4d, 0xad, 0xc6, 0xc1, 0xba, 0x32, + 0x9b, 0xd6, 0x12, 0x7c, 0xbb, 0x92, 0x9f, 0x37, 0xc9, 0x8b, 0xc3, 0x78, 0x17, 0x5a, 0xbe, 0xbc, + 0xb0, 0x12, 0x44, 0x4a, 0x29, 0x03, 0x99, 0xcb, 0x0c, 0x51, 0xb1, 0x45, 0x9c, 0x33, 0x51, 0x49, + 0x63, 0x9c, 0xb9, 0x1a, 0xe5, 0x98, 0x54, 0x5f, 0xd7, 0xb3, 0x5e, 0x8d, 0x07, 0xbf, 0x54, 0xa1, + 0xf4, 0xb4, 0xf7, 0xa5, 0x71, 0x0c, 0x2b, 0xb9, 0xb7, 0xae, 0xa1, 0xa7, 0xcd, 0xec, 0x07, 0x79, + 0xf7, 0xbf, 0xf3, 0x8e, 0xd5, 0x77, 0xc0, 0x12, 0xb7, 0x99, 0xfb, 0x48, 0x48, 0x6c, 0xce, 0xfe, + 0x20, 0x4b, 0x6c, 0xce, 0xfb, 0xb6, 0x58, 0x32, 0x3e, 0x82, 0xaa, 0x7c, 0x19, 0x1b, 0x1b, 0x4a, + 0x36, 0xf3, 0xc4, 0xee, 0x6e, 0xe6, 0x76, 0x13, 0xc5, 0x23, 0x68, 0x65, 0xfe, 0x73, 0x30, 0x6e, + 0x65, 0x7c, 0x65, 0x1f, 0xd6, 0xdd, 0xff, 0xcc, 0x3e, 0x4c, 0xac, 0x1d, 0x02, 0x4c, 0xde, 0x90, + 0x46, 0x47, 0x49, 0x4f, 0x3d, 0xd0, 0xbb, 0x3b, 0x33, 0x4e, 0x12, 0x23, 0x67, 0xb0, 0x9a, 0x7f, + 0x24, 0x1a, 0x39, 0x54, 0xf3, 0x4f, 0xba, 0xee, 0x9d, 0xb9, 0xe7, 0x69, 0xb3, 0xf9, 0xa7, 0x62, + 0x62, 0x76, 0xce, 0xc3, 0x33, 0x31, 0x3b, 0xf7, 0x8d, 0xb9, 0x64, 0x7c, 0x0d, 0xed, 0xec, 0x2b, + 0xcf, 0xd0, 0x20, 0xcd, 0x7c, 0x7c, 0x76, 0x6f, 0xcf, 0x39, 0x4d, 0x0c, 0xbe, 0x0f, 0x15, 0xf9, + 0x9e, 0xd3, 0x1d, 0x9f, 0x7e, 0x02, 0x76, 0x37, 0xb2, 0x9b, 0x89, 0xd6, 0x43, 0xa8, 0xca, 0xcf, + 0xcb, 0xa4, 0x01, 0x32, 0x5f, 0x9b, 0xdd, 0x66, 0x7a, 0xd7, 0x5c, 0x7a, 0x58, 0xd0, 0x7e, 0x68, + 0xc6, 0x0f, 0x9d, 0xe5, 0x27, 0x55, 0x9c, 0x41, 0x55, 0xfc, 0x2b, 0xf6, 0xe8, 0xcf, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x96, 0xc1, 0x71, 0xd3, 0x22, 0x13, 0x00, 0x00, } diff --git a/api/grpc/types/api.proto b/api/grpc/types/api.proto index 4a8d516..f8b8b77 100644 --- a/api/grpc/types/api.proto +++ b/api/grpc/types/api.proto @@ -61,6 +61,10 @@ message AddProcessRequest { string stdin = 8; // path to the file where stdin will be read (optional) string stdout = 9; // path to file where stdout will be written (optional) string stderr = 10; // path to file where stderr will be written (optional) + repeated string capabilities = 11; + string apparmorProfile = 12; + string selinuxLabel = 13; + bool noNewPrivileges = 14; } message User { @@ -123,6 +127,10 @@ message Process { string stdin = 8; // path to the file where stdin will be read (optional) string stdout = 9; // path to file where stdout will be written (optional) string stderr = 10; // path to file where stderr will be written (optional) +repeated string capabilities = 11; + string apparmorProfile = 12; + string selinuxLabel = 13; + bool noNewPrivileges = 14; } message Container { @@ -151,6 +159,20 @@ message UpdateContainerRequest { string id = 1; // ID of container string pid = 2; string status = 3; // Status to whcih containerd will try to change + UpdateResource resources =4; +} + +message UpdateResource { + uint32 blkioWeight =1; + uint32 cpuShares = 2; + uint32 cpuPeriod = 3; + uint32 cpuQuota = 4; + string cpusetCpus = 5; + string cpusetMems = 6; + uint32 memoryLimit = 7; + uint32 memorySwap = 8; + uint32 memoryReservation = 9; + uint32 kernelMemoryLimit = 10; } message UpdateContainerResponse { diff --git a/ctr/container.go b/ctr/container.go index 4af28eb..809dfff 100644 --- a/ctr/container.go +++ b/ctr/container.go @@ -53,6 +53,7 @@ var containersCommand = cli.Command{ startCommand, statsCommand, watchCommand, + updateCommand, }, Action: listContainers, } @@ -517,6 +518,59 @@ var statsCommand = cli.Command{ }, } +var updateCommand = cli.Command{ + Name: "update", + Usage: "update a containers resources", + Flags: []cli.Flag{ + cli.IntFlag{ + Name: "memory-limit", + }, + cli.IntFlag{ + Name: "memory-reservation", + }, + cli.IntFlag{ + Name: "memory-swap", + }, + cli.IntFlag{ + Name: "cpu-quota", + }, + cli.IntFlag{ + Name: "cpu-period", + }, + cli.IntFlag{ + Name: "kernel-limit", + }, + cli.IntFlag{ + Name: "blkio-weight", + }, + cli.StringFlag{ + Name: "cpuset-cpus", + }, + cli.StringFlag{ + Name: "cpuset-mems", + }, + }, + Action: func(context *cli.Context) { + req := &types.UpdateContainerRequest{ + Id: context.Args().First(), + } + req.Resources = &types.UpdateResource{} + req.Resources.MemoryLimit = uint32(context.Int("memory-limit")) + req.Resources.MemoryReservation = uint32(context.Int("memory-reservation")) + req.Resources.MemorySwap = uint32(context.Int("memory-swap")) + req.Resources.BlkioWeight = uint32(context.Int("blkio-weight")) + req.Resources.CpuPeriod = uint32(context.Int("cpu-period")) + req.Resources.CpuQuota = uint32(context.Int("cpu-quota")) + req.Resources.CpuShares = uint32(context.Int("cpu-shares")) + req.Resources.CpusetCpus = context.String("cpuset-cpus") + req.Resources.CpusetMems = context.String("cpuset-mems") + c := getClient(context) + if _, err := c.UpdateContainer(netcontext.Background(), req); err != nil { + fatal(err.Error(), 1) + } + }, +} + func waitForExit(c types.APIClient, events types.API_EventsClient, id, pid string, closer func()) error { for { e, err := events.Recv() diff --git a/hack/vendor.sh b/hack/vendor.sh index 6aa3ab2..27caffc 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -14,8 +14,8 @@ clone git github.com/docker/go-units master clone git github.com/godbus/dbus master clone git github.com/golang/glog master clone git github.com/golang/protobuf master -clone git github.com/opencontainers/runc master -clone git github.com/opencontainers/specs master +clone git github.com/opencontainers/runc 7b6c4c418d5090f4f11eee949fdf49afd15838c9 +clone git github.com/opencontainers/specs a1e32a8ead2ba57adce3e36e956b4dc32c1b85c4 clone git github.com/rcrowley/go-metrics master clone git github.com/satori/go.uuid master clone git github.com/syndtr/gocapability master diff --git a/runtime/container.go b/runtime/container.go index e34805e..619200d 100644 --- a/runtime/container.go +++ b/runtime/container.go @@ -48,6 +48,8 @@ type Container interface { Runtime() string // OOM signals the channel if the container received an OOM notification OOM() (OOM, error) + // UpdateResource updates the containers resources to new values + UpdateResources(*Resource) error } type OOM interface { @@ -213,3 +215,22 @@ func (c *container) RemoveProcess(pid string) error { delete(c.processes, pid) return os.RemoveAll(filepath.Join(c.root, c.id, pid)) } + +func (c *container) UpdateResources(r *Resource) error { + container, err := c.getLibctContainer() + if err != nil { + return err + } + config := container.Config() + config.Cgroups.Resources.CpuShares = r.CPUShares + config.Cgroups.Resources.BlkioWeight = r.BlkioWeight + config.Cgroups.Resources.CpuPeriod = r.CPUPeriod + config.Cgroups.Resources.CpuQuota = r.CPUQuota + config.Cgroups.Resources.CpusetCpus = r.CpusetCpus + config.Cgroups.Resources.CpusetMems = r.CpusetMems + config.Cgroups.Resources.KernelMemory = r.KernelMemory + config.Cgroups.Resources.Memory = r.Memory + config.Cgroups.Resources.MemoryReservation = r.MemoryReservation + config.Cgroups.Resources.MemorySwap = r.MemorySwap + return container.Set(config) +} diff --git a/runtime/runtime.go b/runtime/runtime.go index 82685aa..39ed404 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -32,6 +32,19 @@ const ( type State string +type Resource struct { + CPUShares int64 + BlkioWeight uint16 + CPUPeriod int64 + CPUQuota int64 + CpusetCpus string + CpusetMems string + KernelMemory int64 + Memory int64 + MemoryReservation int64 + MemorySwap int64 +} + const ( Paused = State("paused") Stopped = State("stopped") diff --git a/supervisor/update.go b/supervisor/update.go index 4ef2360..7d34d82 100644 --- a/supervisor/update.go +++ b/supervisor/update.go @@ -8,8 +8,9 @@ import ( type UpdateTask struct { baseTask - ID string - State runtime.State + ID string + State runtime.State + Resources *runtime.Resource } func (s *Supervisor) updateContainer(t *UpdateTask) error { @@ -41,6 +42,10 @@ func (s *Supervisor) updateContainer(t *UpdateTask) error { default: return ErrUnknownContainerStatus } + return nil + } + if t.Resources != nil { + return container.UpdateResources(t.Resources) } return nil } diff --git a/vendor/src/github.com/docker/docker/pkg/pubsub/publisher.go b/vendor/src/github.com/docker/docker/pkg/pubsub/publisher.go deleted file mode 100644 index 8529ffa..0000000 --- a/vendor/src/github.com/docker/docker/pkg/pubsub/publisher.go +++ /dev/null @@ -1,104 +0,0 @@ -package pubsub - -import ( - "sync" - "time" -) - -// NewPublisher creates a new pub/sub publisher to broadcast messages. -// The duration is used as the send timeout as to not block the publisher publishing -// messages to other clients if one client is slow or unresponsive. -// The buffer is used when creating new channels for subscribers. -func NewPublisher(publishTimeout time.Duration, buffer int) *Publisher { - return &Publisher{ - buffer: buffer, - timeout: publishTimeout, - subscribers: make(map[subscriber]topicFunc), - } -} - -type subscriber chan interface{} -type topicFunc func(v interface{}) bool - -// Publisher is basic pub/sub structure. Allows to send events and subscribe -// to them. Can be safely used from multiple goroutines. -type Publisher struct { - m sync.RWMutex - buffer int - timeout time.Duration - subscribers map[subscriber]topicFunc -} - -// Len returns the number of subscribers for the publisher -func (p *Publisher) Len() int { - p.m.RLock() - i := len(p.subscribers) - p.m.RUnlock() - return i -} - -// Subscribe adds a new subscriber to the publisher returning the channel. -func (p *Publisher) Subscribe() chan interface{} { - return p.SubscribeTopic(nil) -} - -// SubscribeTopic adds a new subscriber that filters messages sent by a topic. -func (p *Publisher) SubscribeTopic(topic topicFunc) chan interface{} { - ch := make(chan interface{}, p.buffer) - p.m.Lock() - p.subscribers[ch] = topic - p.m.Unlock() - return ch -} - -// Evict removes the specified subscriber from receiving any more messages. -func (p *Publisher) Evict(sub chan interface{}) { - p.m.Lock() - delete(p.subscribers, sub) - close(sub) - p.m.Unlock() -} - -// Publish sends the data in v to all subscribers currently registered with the publisher. -func (p *Publisher) Publish(v interface{}) { - p.m.RLock() - wg := new(sync.WaitGroup) - for sub, topic := range p.subscribers { - wg.Add(1) - - go p.sendTopic(sub, topic, v, wg) - } - wg.Wait() - p.m.RUnlock() -} - -// Close closes the channels to all subscribers registered with the publisher. -func (p *Publisher) Close() { - p.m.Lock() - for sub := range p.subscribers { - delete(p.subscribers, sub) - close(sub) - } - p.m.Unlock() -} - -func (p *Publisher) sendTopic(sub subscriber, topic topicFunc, v interface{}, wg *sync.WaitGroup) { - defer wg.Done() - if topic != nil && !topic(v) { - return - } - - // send under a select as to not block if the receiver is unavailable - if p.timeout > 0 { - select { - case sub <- v: - case <-time.After(p.timeout): - } - return - } - - select { - case sub <- v: - default: - } -} diff --git a/vendor/src/github.com/opencontainers/runc/.gitignore b/vendor/src/github.com/opencontainers/runc/.gitignore deleted file mode 100644 index 41b8418..0000000 --- a/vendor/src/github.com/opencontainers/runc/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -vendor/pkg -runc diff --git a/vendor/src/github.com/opencontainers/runc/CONTRIBUTING.md b/vendor/src/github.com/opencontainers/runc/CONTRIBUTING.md deleted file mode 100644 index 6f341f6..0000000 --- a/vendor/src/github.com/opencontainers/runc/CONTRIBUTING.md +++ /dev/null @@ -1,117 +0,0 @@ -## Contribution Guidelines - -### Pull requests are always welcome - -We are always thrilled to receive pull requests, and do our best to -process them as fast as possible. Not sure if that typo is worth a pull -request? Do it! We will appreciate it. - -If your pull request is not accepted on the first try, don't be -discouraged! If there's a problem with the implementation, hopefully you -received feedback on what to improve. - -We're trying very hard to keep runc lean and focused. We don't want it -to do everything for everybody. This means that we might decide against -incorporating a new feature. However, there might be a way to implement -that feature *on top of* runc. - - -### Conventions - -Fork the repo and make changes on your fork in a feature branch: - -- If it's a bugfix branch, name it XXX-something where XXX is the number of the - issue -- If it's a feature branch, create an enhancement issue to announce your - intentions, and name it XXX-something where XXX is the number of the issue. - -Submit unit tests for your changes. Go has a great test framework built in; use -it! Take a look at existing tests for inspiration. Run the full test suite on -your branch before submitting a pull request. - -Update the documentation when creating or modifying features. Test -your documentation changes for clarity, concision, and correctness, as -well as a clean documentation build. See ``docs/README.md`` for more -information on building the docs and how docs get released. - -Write clean code. Universally formatted code promotes ease of writing, reading, -and maintenance. Always run `gofmt -s -w file.go` on each changed file before -committing your changes. Most editors have plugins that do this automatically. - -Pull requests descriptions should be as clear as possible and include a -reference to all the issues that they address. - -Pull requests must not contain commits from other users or branches. - -Commit messages must start with a capitalized and short summary (max. 50 -chars) written in the imperative, followed by an optional, more detailed -explanatory text which is separated from the summary by an empty line. - -Code review comments may be added to your pull request. Discuss, then make the -suggested modifications and push additional commits to your feature branch. Be -sure to post a comment after pushing. The new commits will show up in the pull -request automatically, but the reviewers will not be notified unless you -comment. - -Before the pull request is merged, make sure that you squash your commits into -logical units of work using `git rebase -i` and `git push -f`. After every -commit the test suite should be passing. Include documentation changes in the -same commit so that a revert would remove all traces of the feature or fix. - -Commits that fix or close an issue should include a reference like `Closes #XXX` -or `Fixes #XXX`, which will automatically close the issue when merged. - -### Sign your work - -The sign-off is a simple line at the end of the explanation for the -patch, which certifies that you wrote it or otherwise have the right to -pass it on as an open-source patch. The rules are pretty simple: if you -can certify the below (from -[developercertificate.org](http://developercertificate.org/)): - -``` -Developer Certificate of Origin -Version 1.1 - -Copyright (C) 2004, 2006 The Linux Foundation and its contributors. -660 York Street, Suite 102, -San Francisco, CA 94110 USA - -Everyone is permitted to copy and distribute verbatim copies of this -license document, but changing it is not allowed. - - -Developer's Certificate of Origin 1.1 - -By making a contribution to this project, I certify that: - -(a) The contribution was created in whole or in part by me and I - have the right to submit it under the open source license - indicated in the file; or - -(b) The contribution is based upon previous work that, to the best - of my knowledge, is covered under an appropriate open source - license and I have the right under that license to submit that - work with modifications, whether created in whole or in part - by me, under the same open source license (unless I am - permitted to submit under a different license), as indicated - in the file; or - -(c) The contribution was provided directly to me by some other - person who certified (a), (b) or (c) and I have not modified - it. - -(d) I understand and agree that this project and the contribution - are public and that a record of the contribution (including all - personal information I submit with it, including my sign-off) is - maintained indefinitely and may be redistributed consistent with - this project or the open source license(s) involved. -``` - -then you just add a line to every git commit message: - - Signed-off-by: Joe Smith - -using your real name (sorry, no pseudonyms or anonymous contributions.) - -You can add the sign off when creating the git commit via `git commit -s`. diff --git a/vendor/src/github.com/opencontainers/runc/MAINTAINERS b/vendor/src/github.com/opencontainers/runc/MAINTAINERS deleted file mode 100644 index 5ce8037..0000000 --- a/vendor/src/github.com/opencontainers/runc/MAINTAINERS +++ /dev/null @@ -1,7 +0,0 @@ -Michael Crosby (@crosbymichael) -Rohit Jnagal (@rjnagal) -Victor Marmol (@vmarmol) -Mrunal Patel (@mrunalp) -Alexander Morozov (@LK4D4) -Daniel, Dao Quang Minh (@dqminh) -Andrey Vagin (@avagin) diff --git a/vendor/src/github.com/opencontainers/runc/MAINTAINERS_GUIDE.md b/vendor/src/github.com/opencontainers/runc/MAINTAINERS_GUIDE.md deleted file mode 100644 index caf27b5..0000000 --- a/vendor/src/github.com/opencontainers/runc/MAINTAINERS_GUIDE.md +++ /dev/null @@ -1,120 +0,0 @@ -## Introduction - -Dear maintainer. Thank you for investing the time and energy to help -make runc as useful as possible. Maintaining a project is difficult, -sometimes unrewarding work. Sure, you will get to contribute cool -features to the project. But most of your time will be spent reviewing, -cleaning up, documenting, answering questions, justifying design -decisions - while everyone has all the fun! But remember - the quality -of the maintainers work is what distinguishes the good projects from the -great. So please be proud of your work, even the unglamourous parts, -and encourage a culture of appreciation and respect for *every* aspect -of improving the project - not just the hot new features. - -This document is a manual for maintainers old and new. It explains what -is expected of maintainers, how they should work, and what tools are -available to them. - -This is a living document - if you see something out of date or missing, -speak up! - -## What are a maintainer's responsibility? - -It is every maintainer's responsibility to: - -* 1) Expose a clear roadmap for improving their component. -* 2) Deliver prompt feedback and decisions on pull requests. -* 3) Be available to anyone with questions, bug reports, criticism etc. - on their component. This includes IRC and GitHub issues and pull requests. -* 4) Make sure their component respects the philosophy, design and - roadmap of the project. - -## How are decisions made? - -Short answer: with pull requests to the runc repository. - -runc is an open-source project with an open design philosophy. This -means that the repository is the source of truth for EVERY aspect of the -project, including its philosophy, design, roadmap and APIs. *If it's -part of the project, it's in the repo. It's in the repo, it's part of -the project.* - -As a result, all decisions can be expressed as changes to the -repository. An implementation change is a change to the source code. An -API change is a change to the API specification. A philosophy change is -a change to the philosophy manifesto. And so on. - -All decisions affecting runc, big and small, follow the same 3 steps: - -* Step 1: Open a pull request. Anyone can do this. - -* Step 2: Discuss the pull request. Anyone can do this. - -* Step 3: Accept (`LGTM`) or refuse a pull request. The relevant maintainers do -this (see below "Who decides what?") - -### I'm a maintainer, should I make pull requests too? - -Yes. Nobody should ever push to master directly. All changes should be -made through a pull request. - -## Who decides what? - -All decisions are pull requests, and the relevant maintainers make -decisions by accepting or refusing the pull request. Review and acceptance -by anyone is denoted by adding a comment in the pull request: `LGTM`. -However, only currently listed `MAINTAINERS` are counted towards the required -two LGTMs. - -Overall the maintainer system works because of mutual respect across the -maintainers of the project. The maintainers trust one another to make decisions -in the best interests of the project. Sometimes maintainers can disagree and -this is part of a healthy project to represent the point of views of various people. -In the case where maintainers cannot find agreement on a specific change the -role of a Chief Maintainer comes into play. - -The Chief Maintainer for the project is responsible for overall architecture -of the project to maintain conceptual integrity. Large decisions and -architecture changes should be reviewed by the chief maintainer. -The current chief maintainer for the project is Michael Crosby (@crosbymichael). - -Even though the maintainer system is built on trust, if there is a conflict -with the chief maintainer on a decision, their decision can be challenged -and brought to the technical oversight board if two-thirds of the -maintainers vote for an appeal. It is expected that this would be a -very exceptional event. - - -### How are maintainers added? - -The best maintainers have a vested interest in the project. Maintainers -are first and foremost contributors that have shown they are committed to -the long term success of the project. Contributors wanting to become -maintainers are expected to be deeply involved in contributing code, -pull request review, and triage of issues in the project for more than two months. - -Just contributing does not make you a maintainer, it is about building trust -with the current maintainers of the project and being a person that they can -depend on and trust to make decisions in the best interest of the project. The -final vote to add a new maintainer should be approved by over 66% of the current -maintainers with the chief maintainer having veto power. In case of a veto, -conflict resolution rules expressed above apply. The voting period is -five business days on the Pull Request to add the new maintainer. - - -### What is expected of maintainers? - -Part of a healthy project is to have active maintainers to support the community -in contributions and perform tasks to keep the project running. Maintainers are -expected to be able to respond in a timely manner if their help is required on specific -issues where they are pinged. Being a maintainer is a time consuming commitment and should -not be taken lightly. - -When a maintainer is unable to perform the required duties they can be removed with -a vote by 66% of the current maintainers with the chief maintainer having veto power. -The voting period is ten business days. Issues related to a maintainer's performance should -be discussed with them among the other maintainers so that they are not surprised by -a pull request removing them. - - - diff --git a/vendor/src/github.com/opencontainers/runc/Makefile b/vendor/src/github.com/opencontainers/runc/Makefile deleted file mode 100644 index a708972..0000000 --- a/vendor/src/github.com/opencontainers/runc/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -RUNC_TEST_IMAGE=runc_test -PROJECT=github.com/opencontainers/runc -TEST_DOCKERFILE=script/test_Dockerfile -BUILDTAGS=seccomp -export GOPATH:=$(CURDIR)/Godeps/_workspace:$(GOPATH) - -all: - go build -tags "$(BUILDTAGS)" -o runc . - -static: - CGO_ENABLED=1 go build -tags "$(BUILDTAGS) cgo static_build" -ldflags "-w -extldflags -static" -o runc . - -vet: - go get golang.org/x/tools/cmd/vet - -lint: vet - go vet ./... - go fmt ./... - -runctestimage: - docker build -t $(RUNC_TEST_IMAGE) -f $(TEST_DOCKERFILE) . - -test: runctestimage - docker run -e TESTFLAGS --privileged --rm -v $(CURDIR):/go/src/$(PROJECT) $(RUNC_TEST_IMAGE) make localtest - -localtest: - go test -tags "$(BUILDTAGS)" ${TESTFLAGS} -v ./... - - -install: - cp runc /usr/local/bin/runc - -clean: - rm runc - -validate: vet - script/validate-gofmt - go vet ./... - -ci: validate localtest diff --git a/vendor/src/github.com/opencontainers/runc/NOTICE b/vendor/src/github.com/opencontainers/runc/NOTICE deleted file mode 100644 index 5c97abc..0000000 --- a/vendor/src/github.com/opencontainers/runc/NOTICE +++ /dev/null @@ -1,17 +0,0 @@ -runc - -Copyright 2012-2015 Docker, Inc. - -This product includes software developed at Docker, Inc. (http://www.docker.com). - -The following is courtesy of our legal counsel: - - -Use and transfer of Docker may be subject to certain restrictions by the -United States and other governments. -It is your responsibility to ensure that your use and/or transfer does not -violate applicable laws. - -For more information, please see http://www.bis.doc.gov - -See also http://www.apache.org/dev/crypto.html and/or seek legal counsel. diff --git a/vendor/src/github.com/opencontainers/runc/PRINCIPLES.md b/vendor/src/github.com/opencontainers/runc/PRINCIPLES.md deleted file mode 100644 index fdcc373..0000000 --- a/vendor/src/github.com/opencontainers/runc/PRINCIPLES.md +++ /dev/null @@ -1,19 +0,0 @@ -# runc principles - -In the design and development of runc and libcontainer we try to follow these principles: - -(Work in progress) - -* Don't try to replace every tool. Instead, be an ingredient to improve them. -* Less code is better. -* Fewer components are better. Do you really need to add one more class? -* 50 lines of straightforward, readable code is better than 10 lines of magic that nobody can understand. -* Don't do later what you can do now. "//TODO: refactor" is not acceptable in new code. -* When hesitating between two options, choose the one that is easier to reverse. -* "No" is temporary; "Yes" is forever. If you're not sure about a new feature, say no. You can change your mind later. -* Containers must be portable to the greatest possible number of machines. Be suspicious of any change which makes machines less interchangeable. -* The fewer moving parts in a container, the better. -* Don't merge it unless you document it. -* Don't document it unless you can keep it up-to-date. -* Don't merge it unless you test it! -* Everyone's problem is slightly different. Focus on the part that is the same for everyone, and solve that. diff --git a/vendor/src/github.com/opencontainers/runc/README.md b/vendor/src/github.com/opencontainers/runc/README.md deleted file mode 100644 index 1b5343d..0000000 --- a/vendor/src/github.com/opencontainers/runc/README.md +++ /dev/null @@ -1,144 +0,0 @@ -[![Build Status](https://jenkins.dockerproject.org/buildStatus/icon?job=runc Master)](https://jenkins.dockerproject.org/job/runc Master) - -## runc - -`runc` is a CLI tool for spawning and running containers according to the OCF specification. - -## State of the project - -Currently `runc` is an implementation of the OCI specification. We are currently sprinting -to have a v1 of the spec out. So the `runc` config format will be constantly changing until -the spec is finalized. However, we encourage you to try out the tool and give feedback. - -### OCF - -How does `runc` integrate with the Open Container Initiative Specification? -`runc` depends on the types specified in the -[specs](https://github.com/opencontainers/specs) repository. Whenever the -specification is updated and ready to be versioned `runc` will update its dependency -on the specs repository and support the update spec. - -### Building: - -At the time of writing, runc only builds on the Linux platform. - -```bash -# create a 'github.com/opencontainers' in your GOPATH/src -cd github.com/opencontainers -git clone https://github.com/opencontainers/runc -cd runc -make -sudo make install -``` - -In order to enable seccomp support you will need to install libseccomp on your platform. -If you do not with to build `runc` with seccomp support you can add `BUILDTAGS=""` when running make. - -#### Build Tags - -`runc` supports optional build tags for compiling in support for various features. - - -| Build Tag | Feature | Dependency | -|-----------|------------------------------------|-------------| -| seccomp | Syscall filtering | libseccomp | -| selinux | selinux process and mount labeling | | -| apparmor | apparmor profile support | libapparmor | - -### Testing: - -You can run tests for runC by using command: - -```bash -# make test -``` - -Note that test cases are run in Docker container, so you need to install -`docker` first. And test requires mounting cgroups inside container, it's -done by docker now, so you need a docker version newer than 1.8.0-rc2. - -You can also run specific test cases by: - -```bash -# make test TESTFLAGS="-run=SomeTestFunction" -``` - -### Using: - -To run a container with the id "test", execute `runc start` with the containers id as arg one -in the bundle's root directory: - -```bash -runc start test -/ $ ps -PID USER COMMAND -1 daemon sh -5 daemon sh -/ $ -``` - -### OCI Container JSON Format: - -OCI container JSON format is based on OCI [specs](https://github.com/opencontainers/specs). -You can generate JSON files by using `runc spec`. -It assumes that the file-system is found in a directory called -`rootfs` and there is a user with uid and gid of `0` defined within that file-system. - -### Examples: - -#### Using a Docker image (requires version 1.3 or later) - -To test using Docker's `busybox` image follow these steps: -* Install `docker` and download the `busybox` image: `docker pull busybox` -* Create a container from that image and export its contents to a tar file: -`docker export $(docker create busybox) > busybox.tar` -* Untar the contents to create your filesystem directory: -``` -mkdir rootfs -tar -C rootfs -xf busybox.tar -``` -* Create `config.json` by using `runc spec`. -* Execute `runc start` and you should be placed into a shell where you can run `ps`: -``` -$ runc start test -/ # ps -PID USER COMMAND - 1 root sh - 9 root ps -``` - -#### Using runc with systemd - -To use runc with systemd, you can create a unit file -`/usr/lib/systemd/system/minecraft.service` as below (edit your -own Description or WorkingDirectory or service name as you need). - -```service -[Unit] -Description=Minecraft Build Server -Documentation=http://minecraft.net -After=network.target - -[Service] -CPUQuota=200% -MemoryLimit=1536M -ExecStart=/usr/local/bin/runc start minecraft -Restart=on-failure -WorkingDirectory=/containers/minecraftbuild - -[Install] -WantedBy=multi-user.target -``` - -Make sure you have the bundle's root directory and JSON configs in -your WorkingDirectory, then use systemd commands to start the service: - -```bash -systemctl daemon-reload -systemctl start minecraft.service -``` - -Note that if you use JSON configs by `runc spec`, you need to modify -`config.json` and change `process.terminal` to false so runc won't -create tty, because we can't set terminal from the stdin when using -systemd service. diff --git a/vendor/src/github.com/opencontainers/runc/checkpoint.go b/vendor/src/github.com/opencontainers/runc/checkpoint.go deleted file mode 100644 index c1ca44f..0000000 --- a/vendor/src/github.com/opencontainers/runc/checkpoint.go +++ /dev/null @@ -1,84 +0,0 @@ -// +build linux - -package main - -import ( - "fmt" - "strconv" - "strings" - - "github.com/codegangsta/cli" - "github.com/opencontainers/runc/libcontainer" -) - -var checkpointCommand = cli.Command{ - Name: "checkpoint", - Usage: "checkpoint a running container", - Flags: []cli.Flag{ - cli.StringFlag{Name: "image-path", Value: "", Usage: "path for saving criu image files"}, - cli.StringFlag{Name: "work-path", Value: "", Usage: "path for saving work files and logs"}, - cli.BoolFlag{Name: "leave-running", Usage: "leave the process running after checkpointing"}, - cli.BoolFlag{Name: "tcp-established", Usage: "allow open tcp connections"}, - cli.BoolFlag{Name: "ext-unix-sk", Usage: "allow external unix sockets"}, - cli.BoolFlag{Name: "shell-job", Usage: "allow shell jobs"}, - cli.StringFlag{Name: "page-server", Value: "", Usage: "ADDRESS:PORT of the page server"}, - cli.BoolFlag{Name: "file-locks", Usage: "handle file locks, for safety"}, - cli.StringFlag{Name: "manage-cgroups-mode", Value: "", Usage: "cgroups mode: 'soft' (default), 'full' and 'strict'."}, - }, - Action: func(context *cli.Context) { - container, err := getContainer(context) - if err != nil { - fatal(err) - } - defer destroy(container) - options := criuOptions(context) - // these are the mandatory criu options for a container - setPageServer(context, options) - setManageCgroupsMode(context, options) - if err := container.Checkpoint(options); err != nil { - fatal(err) - } - }, -} - -func getCheckpointImagePath(context *cli.Context) string { - imagePath := context.String("image-path") - if imagePath == "" { - imagePath = getDefaultImagePath(context) - } - return imagePath -} - -func setPageServer(context *cli.Context, options *libcontainer.CriuOpts) { - // xxx following criu opts are optional - // The dump image can be sent to a criu page server - if psOpt := context.String("page-server"); psOpt != "" { - addressPort := strings.Split(psOpt, ":") - if len(addressPort) != 2 { - fatal(fmt.Errorf("Use --page-server ADDRESS:PORT to specify page server")) - } - portInt, err := strconv.Atoi(addressPort[1]) - if err != nil { - fatal(fmt.Errorf("Invalid port number")) - } - options.PageServer = libcontainer.CriuPageServerInfo{ - Address: addressPort[0], - Port: int32(portInt), - } - } -} - -func setManageCgroupsMode(context *cli.Context, options *libcontainer.CriuOpts) { - if cgOpt := context.String("manage-cgroups-mode"); cgOpt != "" { - switch cgOpt { - case "soft": - options.ManageCgroupsMode = libcontainer.CRIU_CG_MODE_SOFT - case "full": - options.ManageCgroupsMode = libcontainer.CRIU_CG_MODE_FULL - case "strict": - options.ManageCgroupsMode = libcontainer.CRIU_CG_MODE_STRICT - default: - fatal(fmt.Errorf("Invalid manage cgroups mode")) - } - } -} diff --git a/vendor/src/github.com/opencontainers/runc/delete.go b/vendor/src/github.com/opencontainers/runc/delete.go deleted file mode 100644 index 41b3778..0000000 --- a/vendor/src/github.com/opencontainers/runc/delete.go +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import "github.com/codegangsta/cli" - -var deleteCommand = cli.Command{ - Name: "delete", - Usage: "delete any resources held by the container often used with detached containers", - Action: func(context *cli.Context) { - container, err := getContainer(context) - if err != nil { - fatal(err) - } - destroy(container) - }, -} diff --git a/vendor/src/github.com/opencontainers/runc/events.go b/vendor/src/github.com/opencontainers/runc/events.go deleted file mode 100644 index a4dbaed..0000000 --- a/vendor/src/github.com/opencontainers/runc/events.go +++ /dev/null @@ -1,95 +0,0 @@ -// +build linux - -package main - -import ( - "encoding/json" - "os" - "sync" - "time" - - "github.com/Sirupsen/logrus" - "github.com/codegangsta/cli" - "github.com/opencontainers/runc/libcontainer" -) - -// event struct for encoding the event data to json. -type event struct { - Type string `json:"type"` - ID string `json:"id"` - Data interface{} `json:"data,omitempty"` -} - -var eventsCommand = cli.Command{ - Name: "events", - Usage: "display container events such as OOM notifications, cpu, memory, IO and network stats", - Flags: []cli.Flag{ - cli.DurationFlag{Name: "interval", Value: 5 * time.Second, Usage: "set the stats collection interval"}, - cli.BoolFlag{Name: "stats", Usage: "display the container's stats then exit"}, - }, - Action: func(context *cli.Context) { - container, err := getContainer(context) - if err != nil { - logrus.Fatal(err) - } - var ( - stats = make(chan *libcontainer.Stats, 1) - events = make(chan *event, 1024) - group = &sync.WaitGroup{} - ) - group.Add(1) - go func() { - defer group.Done() - enc := json.NewEncoder(os.Stdout) - for e := range events { - if err := enc.Encode(e); err != nil { - logrus.Error(err) - } - } - }() - if context.Bool("stats") { - s, err := container.Stats() - if err != nil { - fatal(err) - } - events <- &event{Type: "stats", ID: container.ID(), Data: s} - close(events) - group.Wait() - return - } - go func() { - for range time.Tick(context.Duration("interval")) { - s, err := container.Stats() - if err != nil { - logrus.Error(err) - continue - } - stats <- s - } - }() - n, err := container.NotifyOOM() - if err != nil { - logrus.Fatal(err) - } - for { - select { - case _, ok := <-n: - if ok { - // this means an oom event was received, if it is !ok then - // the channel was closed because the container stopped and - // the cgroups no longer exist. - events <- &event{Type: "oom", ID: container.ID()} - } else { - n = nil - } - case s := <-stats: - events <- &event{Type: "stats", ID: container.ID(), Data: s} - } - if n == nil { - close(events) - break - } - } - group.Wait() - }, -} diff --git a/vendor/src/github.com/opencontainers/runc/exec.go b/vendor/src/github.com/opencontainers/runc/exec.go deleted file mode 100644 index 5f7c9e7..0000000 --- a/vendor/src/github.com/opencontainers/runc/exec.go +++ /dev/null @@ -1,140 +0,0 @@ -// +build linux - -package main - -import ( - "encoding/json" - "fmt" - "os" - "path" - "strconv" - "strings" - - "github.com/Sirupsen/logrus" - "github.com/codegangsta/cli" - "github.com/opencontainers/specs" -) - -var execCommand = cli.Command{ - Name: "exec", - Usage: "execute new process inside the container", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "console", - Usage: "specify the pty slave path for use with the container", - }, - cli.StringFlag{ - Name: "cwd", - Usage: "current working directory in the container", - }, - cli.StringSliceFlag{ - Name: "env, e", - Usage: "set environment variables", - }, - cli.BoolFlag{ - Name: "tty, t", - Usage: "allocate a pseudo-TTY", - }, - cli.StringFlag{ - Name: "user, u", - Usage: "UID (format: [:])", - }, - cli.StringFlag{ - Name: "process,p", - Usage: "path to the process.json", - }, - cli.BoolFlag{ - Name: "detach,d", - Usage: "detach from the container's process", - }, - cli.StringFlag{ - Name: "pid-file", - Value: "", - Usage: "specify the file to write the process id to", - }, - }, - Action: func(context *cli.Context) { - if os.Geteuid() != 0 { - logrus.Fatal("runc should be run as root") - } - status, err := execProcess(context) - if err != nil { - logrus.Fatalf("exec failed: %v", err) - } - os.Exit(status) - }, -} - -func execProcess(context *cli.Context) (int, error) { - container, err := getContainer(context) - if err != nil { - return -1, err - } - - var ( - detach = context.Bool("detach") - rootfs = container.Config().Rootfs - ) - - p, err := getProcess(context, path.Dir(rootfs)) - if err != nil { - return -1, err - } - - return runProcess(container, p, nil, context.String("console"), context.String("pid-file"), detach) - -} - -func getProcess(context *cli.Context, bundle string) (*specs.Process, error) { - if path := context.String("process"); path != "" { - f, err := os.Open(path) - if err != nil { - return nil, err - } - defer f.Close() - var p specs.Process - if err := json.NewDecoder(f).Decode(&p); err != nil { - return nil, err - } - return &p, nil - } - // process via cli flags - if err := os.Chdir(bundle); err != nil { - return nil, err - } - spec, err := loadSpec(specConfig) - if err != nil { - return nil, err - } - p := spec.Process - p.Args = context.Args()[1:] - // override the cwd, if passed - if context.String("cwd") != "" { - p.Cwd = context.String("cwd") - } - // append the passed env variables - for _, e := range context.StringSlice("env") { - p.Env = append(p.Env, e) - } - // set the tty - if context.IsSet("tty") { - p.Terminal = context.Bool("tty") - } - // override the user, if passed - if context.String("user") != "" { - u := strings.SplitN(context.String("user"), ":", 2) - if len(u) > 1 { - gid, err := strconv.Atoi(u[1]) - if err != nil { - return nil, fmt.Errorf("parsing %s as int for gid failed: %v", u[1], err) - } - p.User.GID = uint32(gid) - } - uid, err := strconv.Atoi(u[0]) - if err != nil { - return nil, fmt.Errorf("parsing %s as int for uid failed: %v", u[0], err) - } - p.User.UID = uint32(uid) - } - return &p, nil -} diff --git a/vendor/src/github.com/opencontainers/runc/kill.go b/vendor/src/github.com/opencontainers/runc/kill.go deleted file mode 100644 index 4040b59..0000000 --- a/vendor/src/github.com/opencontainers/runc/kill.go +++ /dev/null @@ -1,87 +0,0 @@ -// +build linux - -package main - -import ( - "fmt" - "strconv" - "strings" - "syscall" - - "github.com/codegangsta/cli" -) - -var signalMap = map[string]syscall.Signal{ - "ABRT": syscall.SIGABRT, - "ALRM": syscall.SIGALRM, - "BUS": syscall.SIGBUS, - "CHLD": syscall.SIGCHLD, - "CLD": syscall.SIGCLD, - "CONT": syscall.SIGCONT, - "FPE": syscall.SIGFPE, - "HUP": syscall.SIGHUP, - "ILL": syscall.SIGILL, - "INT": syscall.SIGINT, - "IO": syscall.SIGIO, - "IOT": syscall.SIGIOT, - "KILL": syscall.SIGKILL, - "PIPE": syscall.SIGPIPE, - "POLL": syscall.SIGPOLL, - "PROF": syscall.SIGPROF, - "PWR": syscall.SIGPWR, - "QUIT": syscall.SIGQUIT, - "SEGV": syscall.SIGSEGV, - "STKFLT": syscall.SIGSTKFLT, - "STOP": syscall.SIGSTOP, - "SYS": syscall.SIGSYS, - "TERM": syscall.SIGTERM, - "TRAP": syscall.SIGTRAP, - "TSTP": syscall.SIGTSTP, - "TTIN": syscall.SIGTTIN, - "TTOU": syscall.SIGTTOU, - "UNUSED": syscall.SIGUNUSED, - "URG": syscall.SIGURG, - "USR1": syscall.SIGUSR1, - "USR2": syscall.SIGUSR2, - "VTALRM": syscall.SIGVTALRM, - "WINCH": syscall.SIGWINCH, - "XCPU": syscall.SIGXCPU, - "XFSZ": syscall.SIGXFSZ, -} - -var killCommand = cli.Command{ - Name: "kill", - Usage: "kill sends the specified signal (default: SIGTERM) to the container's init process", - Action: func(context *cli.Context) { - container, err := getContainer(context) - if err != nil { - fatal(err) - } - - sigstr := context.Args().Get(1) - if sigstr == "" { - sigstr = "SIGTERM" - } - - signal, err := parseSignal(sigstr) - if err != nil { - fatal(err) - } - - if err := container.Signal(signal); err != nil { - fatal(err) - } - }, -} - -func parseSignal(rawSignal string) (syscall.Signal, error) { - s, err := strconv.Atoi(rawSignal) - if err == nil { - return syscall.Signal(s), nil - } - signal, ok := signalMap[strings.TrimPrefix(strings.ToUpper(rawSignal), "SIG")] - if !ok { - return -1, fmt.Errorf("unknown signal %q", rawSignal) - } - return signal, nil -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/README.md b/vendor/src/github.com/opencontainers/runc/libcontainer/README.md index fc6b4b0..2f63e64 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/README.md +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/README.md @@ -76,7 +76,7 @@ config := &configs.Config{ Name: "test-container", Parent: "system", Resources: &configs.Resources{ - MemorySwappiness: -1, + MemorySwappiness: nil, AllowAllDevices: false, AllowedDevices: configs.DefaultAllowedDevices, }, diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/cgroups_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/cgroups_test.go deleted file mode 100644 index 2f702bc..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/cgroups_test.go +++ /dev/null @@ -1,18 +0,0 @@ -// +build linux - -package cgroups - -import ( - "testing" -) - -func TestParseCgroups(t *testing.T) { - cgroups, err := ParseCgroupFile("/proc/self/cgroup") - if err != nil { - t.Fatal(err) - } - - if _, ok := cgroups["cpu"]; !ok { - t.Fail() - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go index 21646e5..6def4ea 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go @@ -14,6 +14,7 @@ import ( "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" + libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils" ) var ( @@ -30,6 +31,7 @@ var ( &NetPrioGroup{}, &PerfEventGroup{}, &FreezerGroup{}, + &NameGroup{GroupName: "name=systemd", Join: true}, } CgroupProcesses = "cgroup.procs" HugePageSizes, _ = cgroups.GetHugePageSize() @@ -128,12 +130,9 @@ func (m *Manager) Apply(pid int) (err error) { return cgroups.EnterPid(m.Paths, pid) } + m.mu.Lock() + defer m.mu.Unlock() paths := make(map[string]string) - defer func() { - if err != nil { - cgroups.RemovePaths(paths) - } - }() for _, sys := range subsystems { if err := sys.Apply(d); err != nil { return err @@ -276,14 +275,19 @@ func getCgroupData(c *configs.Cgroup, pid int) (*cgroupData, error) { return nil, fmt.Errorf("cgroup: either Path or Name and Parent should be used") } - innerPath := c.Path + // XXX: Do not remove this code. Path safety is important! -- cyphar + cgPath := libcontainerUtils.CleanPath(c.Path) + cgParent := libcontainerUtils.CleanPath(c.Parent) + cgName := libcontainerUtils.CleanPath(c.Name) + + innerPath := cgPath if innerPath == "" { - innerPath = filepath.Join(c.Parent, c.Name) + innerPath = filepath.Join(cgParent, cgName) } return &cgroupData{ root: root, - innerPath: c.Path, + innerPath: innerPath, config: c, pid: pid, }, nil diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/blkio_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/blkio_test.go deleted file mode 100644 index 6957392..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/blkio_test.go +++ /dev/null @@ -1,636 +0,0 @@ -// +build linux - -package fs - -import ( - "strconv" - "testing" - - "github.com/opencontainers/runc/libcontainer/cgroups" - "github.com/opencontainers/runc/libcontainer/configs" -) - -const ( - sectorsRecursiveContents = `8:0 1024` - serviceBytesRecursiveContents = `8:0 Read 100 -8:0 Write 200 -8:0 Sync 300 -8:0 Async 500 -8:0 Total 500 -Total 500` - servicedRecursiveContents = `8:0 Read 10 -8:0 Write 40 -8:0 Sync 20 -8:0 Async 30 -8:0 Total 50 -Total 50` - queuedRecursiveContents = `8:0 Read 1 -8:0 Write 4 -8:0 Sync 2 -8:0 Async 3 -8:0 Total 5 -Total 5` - serviceTimeRecursiveContents = `8:0 Read 173959 -8:0 Write 0 -8:0 Sync 0 -8:0 Async 173959 -8:0 Total 17395 -Total 17395` - waitTimeRecursiveContents = `8:0 Read 15571 -8:0 Write 0 -8:0 Sync 0 -8:0 Async 15571 -8:0 Total 15571` - mergedRecursiveContents = `8:0 Read 5 -8:0 Write 10 -8:0 Sync 0 -8:0 Async 0 -8:0 Total 15 -Total 15` - timeRecursiveContents = `8:0 8` - throttleServiceBytes = `8:0 Read 11030528 -8:0 Write 23 -8:0 Sync 42 -8:0 Async 11030528 -8:0 Total 11030528 -252:0 Read 11030528 -252:0 Write 23 -252:0 Sync 42 -252:0 Async 11030528 -252:0 Total 11030528 -Total 22061056` - throttleServiced = `8:0 Read 164 -8:0 Write 23 -8:0 Sync 42 -8:0 Async 164 -8:0 Total 164 -252:0 Read 164 -252:0 Write 23 -252:0 Sync 42 -252:0 Async 164 -252:0 Total 164 -Total 328` -) - -func appendBlkioStatEntry(blkioStatEntries *[]cgroups.BlkioStatEntry, major, minor, value uint64, op string) { - *blkioStatEntries = append(*blkioStatEntries, cgroups.BlkioStatEntry{Major: major, Minor: minor, Value: value, Op: op}) -} - -func TestBlkioSetWeight(t *testing.T) { - helper := NewCgroupTestUtil("blkio", t) - defer helper.cleanup() - - const ( - weightBefore = 100 - weightAfter = 200 - ) - - helper.writeFileContents(map[string]string{ - "blkio.weight": strconv.Itoa(weightBefore), - }) - - helper.CgroupData.config.Resources.BlkioWeight = weightAfter - blkio := &BlkioGroup{} - if err := blkio.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - value, err := getCgroupParamUint(helper.CgroupPath, "blkio.weight") - if err != nil { - t.Fatalf("Failed to parse blkio.weight - %s", err) - } - - if value != weightAfter { - t.Fatal("Got the wrong value, set blkio.weight failed.") - } -} - -func TestBlkioSetWeightDevice(t *testing.T) { - helper := NewCgroupTestUtil("blkio", t) - defer helper.cleanup() - - const ( - weightDeviceBefore = "8:0 400" - ) - - wd := configs.NewWeightDevice(8, 0, 500, 0) - weightDeviceAfter := wd.WeightString() - - helper.writeFileContents(map[string]string{ - "blkio.weight_device": weightDeviceBefore, - }) - - helper.CgroupData.config.Resources.BlkioWeightDevice = []*configs.WeightDevice{wd} - blkio := &BlkioGroup{} - if err := blkio.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - value, err := getCgroupParamString(helper.CgroupPath, "blkio.weight_device") - if err != nil { - t.Fatalf("Failed to parse blkio.weight_device - %s", err) - } - - if value != weightDeviceAfter { - t.Fatal("Got the wrong value, set blkio.weight_device failed.") - } -} - -// regression #274 -func TestBlkioSetMultipleWeightDevice(t *testing.T) { - helper := NewCgroupTestUtil("blkio", t) - defer helper.cleanup() - - const ( - weightDeviceBefore = "8:0 400" - ) - - wd1 := configs.NewWeightDevice(8, 0, 500, 0) - wd2 := configs.NewWeightDevice(8, 16, 500, 0) - // we cannot actually set and check both because normal ioutil.WriteFile - // when writing to cgroup file will overwrite the whole file content instead - // of updating it as the kernel is doing. Just check the second device - // is present will suffice for the test to ensure multiple writes are done. - weightDeviceAfter := wd2.WeightString() - - helper.writeFileContents(map[string]string{ - "blkio.weight_device": weightDeviceBefore, - }) - - helper.CgroupData.config.Resources.BlkioWeightDevice = []*configs.WeightDevice{wd1, wd2} - blkio := &BlkioGroup{} - if err := blkio.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - value, err := getCgroupParamString(helper.CgroupPath, "blkio.weight_device") - if err != nil { - t.Fatalf("Failed to parse blkio.weight_device - %s", err) - } - - if value != weightDeviceAfter { - t.Fatal("Got the wrong value, set blkio.weight_device failed.") - } -} - -func TestBlkioStats(t *testing.T) { - helper := NewCgroupTestUtil("blkio", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "blkio.io_service_bytes_recursive": serviceBytesRecursiveContents, - "blkio.io_serviced_recursive": servicedRecursiveContents, - "blkio.io_queued_recursive": queuedRecursiveContents, - "blkio.io_service_time_recursive": serviceTimeRecursiveContents, - "blkio.io_wait_time_recursive": waitTimeRecursiveContents, - "blkio.io_merged_recursive": mergedRecursiveContents, - "blkio.time_recursive": timeRecursiveContents, - "blkio.sectors_recursive": sectorsRecursiveContents, - }) - - blkio := &BlkioGroup{} - actualStats := *cgroups.NewStats() - err := blkio.GetStats(helper.CgroupPath, &actualStats) - if err != nil { - t.Fatal(err) - } - - // Verify expected stats. - expectedStats := cgroups.BlkioStats{} - appendBlkioStatEntry(&expectedStats.SectorsRecursive, 8, 0, 1024, "") - - appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 100, "Read") - appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 200, "Write") - appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 300, "Sync") - appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 500, "Async") - appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 500, "Total") - - appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 10, "Read") - appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 40, "Write") - appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 20, "Sync") - appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 30, "Async") - appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 50, "Total") - - appendBlkioStatEntry(&expectedStats.IoQueuedRecursive, 8, 0, 1, "Read") - appendBlkioStatEntry(&expectedStats.IoQueuedRecursive, 8, 0, 4, "Write") - appendBlkioStatEntry(&expectedStats.IoQueuedRecursive, 8, 0, 2, "Sync") - appendBlkioStatEntry(&expectedStats.IoQueuedRecursive, 8, 0, 3, "Async") - appendBlkioStatEntry(&expectedStats.IoQueuedRecursive, 8, 0, 5, "Total") - - appendBlkioStatEntry(&expectedStats.IoServiceTimeRecursive, 8, 0, 173959, "Read") - appendBlkioStatEntry(&expectedStats.IoServiceTimeRecursive, 8, 0, 0, "Write") - appendBlkioStatEntry(&expectedStats.IoServiceTimeRecursive, 8, 0, 0, "Sync") - appendBlkioStatEntry(&expectedStats.IoServiceTimeRecursive, 8, 0, 173959, "Async") - appendBlkioStatEntry(&expectedStats.IoServiceTimeRecursive, 8, 0, 17395, "Total") - - appendBlkioStatEntry(&expectedStats.IoWaitTimeRecursive, 8, 0, 15571, "Read") - appendBlkioStatEntry(&expectedStats.IoWaitTimeRecursive, 8, 0, 0, "Write") - appendBlkioStatEntry(&expectedStats.IoWaitTimeRecursive, 8, 0, 0, "Sync") - appendBlkioStatEntry(&expectedStats.IoWaitTimeRecursive, 8, 0, 15571, "Async") - appendBlkioStatEntry(&expectedStats.IoWaitTimeRecursive, 8, 0, 15571, "Total") - - appendBlkioStatEntry(&expectedStats.IoMergedRecursive, 8, 0, 5, "Read") - appendBlkioStatEntry(&expectedStats.IoMergedRecursive, 8, 0, 10, "Write") - appendBlkioStatEntry(&expectedStats.IoMergedRecursive, 8, 0, 0, "Sync") - appendBlkioStatEntry(&expectedStats.IoMergedRecursive, 8, 0, 0, "Async") - appendBlkioStatEntry(&expectedStats.IoMergedRecursive, 8, 0, 15, "Total") - - appendBlkioStatEntry(&expectedStats.IoTimeRecursive, 8, 0, 8, "") - - expectBlkioStatsEquals(t, expectedStats, actualStats.BlkioStats) -} - -func TestBlkioStatsNoSectorsFile(t *testing.T) { - helper := NewCgroupTestUtil("blkio", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "blkio.io_service_bytes_recursive": serviceBytesRecursiveContents, - "blkio.io_serviced_recursive": servicedRecursiveContents, - "blkio.io_queued_recursive": queuedRecursiveContents, - "blkio.io_service_time_recursive": serviceTimeRecursiveContents, - "blkio.io_wait_time_recursive": waitTimeRecursiveContents, - "blkio.io_merged_recursive": mergedRecursiveContents, - "blkio.time_recursive": timeRecursiveContents, - }) - - blkio := &BlkioGroup{} - actualStats := *cgroups.NewStats() - err := blkio.GetStats(helper.CgroupPath, &actualStats) - if err != nil { - t.Fatalf("Failed unexpectedly: %s", err) - } -} - -func TestBlkioStatsNoServiceBytesFile(t *testing.T) { - helper := NewCgroupTestUtil("blkio", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "blkio.io_serviced_recursive": servicedRecursiveContents, - "blkio.io_queued_recursive": queuedRecursiveContents, - "blkio.sectors_recursive": sectorsRecursiveContents, - "blkio.io_service_time_recursive": serviceTimeRecursiveContents, - "blkio.io_wait_time_recursive": waitTimeRecursiveContents, - "blkio.io_merged_recursive": mergedRecursiveContents, - "blkio.time_recursive": timeRecursiveContents, - }) - - blkio := &BlkioGroup{} - actualStats := *cgroups.NewStats() - err := blkio.GetStats(helper.CgroupPath, &actualStats) - if err != nil { - t.Fatalf("Failed unexpectedly: %s", err) - } -} - -func TestBlkioStatsNoServicedFile(t *testing.T) { - helper := NewCgroupTestUtil("blkio", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "blkio.io_service_bytes_recursive": serviceBytesRecursiveContents, - "blkio.io_queued_recursive": queuedRecursiveContents, - "blkio.sectors_recursive": sectorsRecursiveContents, - "blkio.io_service_time_recursive": serviceTimeRecursiveContents, - "blkio.io_wait_time_recursive": waitTimeRecursiveContents, - "blkio.io_merged_recursive": mergedRecursiveContents, - "blkio.time_recursive": timeRecursiveContents, - }) - - blkio := &BlkioGroup{} - actualStats := *cgroups.NewStats() - err := blkio.GetStats(helper.CgroupPath, &actualStats) - if err != nil { - t.Fatalf("Failed unexpectedly: %s", err) - } -} - -func TestBlkioStatsNoQueuedFile(t *testing.T) { - helper := NewCgroupTestUtil("blkio", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "blkio.io_service_bytes_recursive": serviceBytesRecursiveContents, - "blkio.io_serviced_recursive": servicedRecursiveContents, - "blkio.sectors_recursive": sectorsRecursiveContents, - "blkio.io_service_time_recursive": serviceTimeRecursiveContents, - "blkio.io_wait_time_recursive": waitTimeRecursiveContents, - "blkio.io_merged_recursive": mergedRecursiveContents, - "blkio.time_recursive": timeRecursiveContents, - }) - - blkio := &BlkioGroup{} - actualStats := *cgroups.NewStats() - err := blkio.GetStats(helper.CgroupPath, &actualStats) - if err != nil { - t.Fatalf("Failed unexpectedly: %s", err) - } -} - -func TestBlkioStatsNoServiceTimeFile(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - helper := NewCgroupTestUtil("blkio", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "blkio.io_service_bytes_recursive": serviceBytesRecursiveContents, - "blkio.io_serviced_recursive": servicedRecursiveContents, - "blkio.io_queued_recursive": queuedRecursiveContents, - "blkio.io_wait_time_recursive": waitTimeRecursiveContents, - "blkio.io_merged_recursive": mergedRecursiveContents, - "blkio.time_recursive": timeRecursiveContents, - "blkio.sectors_recursive": sectorsRecursiveContents, - }) - - blkio := &BlkioGroup{} - actualStats := *cgroups.NewStats() - err := blkio.GetStats(helper.CgroupPath, &actualStats) - if err != nil { - t.Fatalf("Failed unexpectedly: %s", err) - } -} - -func TestBlkioStatsNoWaitTimeFile(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - helper := NewCgroupTestUtil("blkio", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "blkio.io_service_bytes_recursive": serviceBytesRecursiveContents, - "blkio.io_serviced_recursive": servicedRecursiveContents, - "blkio.io_queued_recursive": queuedRecursiveContents, - "blkio.io_service_time_recursive": serviceTimeRecursiveContents, - "blkio.io_merged_recursive": mergedRecursiveContents, - "blkio.time_recursive": timeRecursiveContents, - "blkio.sectors_recursive": sectorsRecursiveContents, - }) - - blkio := &BlkioGroup{} - actualStats := *cgroups.NewStats() - err := blkio.GetStats(helper.CgroupPath, &actualStats) - if err != nil { - t.Fatalf("Failed unexpectedly: %s", err) - } -} - -func TestBlkioStatsNoMergedFile(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - helper := NewCgroupTestUtil("blkio", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "blkio.io_service_bytes_recursive": serviceBytesRecursiveContents, - "blkio.io_serviced_recursive": servicedRecursiveContents, - "blkio.io_queued_recursive": queuedRecursiveContents, - "blkio.io_service_time_recursive": serviceTimeRecursiveContents, - "blkio.io_wait_time_recursive": waitTimeRecursiveContents, - "blkio.time_recursive": timeRecursiveContents, - "blkio.sectors_recursive": sectorsRecursiveContents, - }) - - blkio := &BlkioGroup{} - actualStats := *cgroups.NewStats() - err := blkio.GetStats(helper.CgroupPath, &actualStats) - if err != nil { - t.Fatalf("Failed unexpectedly: %s", err) - } -} - -func TestBlkioStatsNoTimeFile(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - helper := NewCgroupTestUtil("blkio", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "blkio.io_service_bytes_recursive": serviceBytesRecursiveContents, - "blkio.io_serviced_recursive": servicedRecursiveContents, - "blkio.io_queued_recursive": queuedRecursiveContents, - "blkio.io_service_time_recursive": serviceTimeRecursiveContents, - "blkio.io_wait_time_recursive": waitTimeRecursiveContents, - "blkio.io_merged_recursive": mergedRecursiveContents, - "blkio.sectors_recursive": sectorsRecursiveContents, - }) - - blkio := &BlkioGroup{} - actualStats := *cgroups.NewStats() - err := blkio.GetStats(helper.CgroupPath, &actualStats) - if err != nil { - t.Fatalf("Failed unexpectedly: %s", err) - } -} - -func TestBlkioStatsUnexpectedNumberOfFields(t *testing.T) { - helper := NewCgroupTestUtil("blkio", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "blkio.io_service_bytes_recursive": "8:0 Read 100 100", - "blkio.io_serviced_recursive": servicedRecursiveContents, - "blkio.io_queued_recursive": queuedRecursiveContents, - "blkio.sectors_recursive": sectorsRecursiveContents, - "blkio.io_service_time_recursive": serviceTimeRecursiveContents, - "blkio.io_wait_time_recursive": waitTimeRecursiveContents, - "blkio.io_merged_recursive": mergedRecursiveContents, - "blkio.time_recursive": timeRecursiveContents, - }) - - blkio := &BlkioGroup{} - actualStats := *cgroups.NewStats() - err := blkio.GetStats(helper.CgroupPath, &actualStats) - if err == nil { - t.Fatal("Expected to fail, but did not") - } -} - -func TestBlkioStatsUnexpectedFieldType(t *testing.T) { - helper := NewCgroupTestUtil("blkio", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "blkio.io_service_bytes_recursive": "8:0 Read Write", - "blkio.io_serviced_recursive": servicedRecursiveContents, - "blkio.io_queued_recursive": queuedRecursiveContents, - "blkio.sectors_recursive": sectorsRecursiveContents, - "blkio.io_service_time_recursive": serviceTimeRecursiveContents, - "blkio.io_wait_time_recursive": waitTimeRecursiveContents, - "blkio.io_merged_recursive": mergedRecursiveContents, - "blkio.time_recursive": timeRecursiveContents, - }) - - blkio := &BlkioGroup{} - actualStats := *cgroups.NewStats() - err := blkio.GetStats(helper.CgroupPath, &actualStats) - if err == nil { - t.Fatal("Expected to fail, but did not") - } -} - -func TestNonCFQBlkioStats(t *testing.T) { - helper := NewCgroupTestUtil("blkio", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "blkio.io_service_bytes_recursive": "", - "blkio.io_serviced_recursive": "", - "blkio.io_queued_recursive": "", - "blkio.sectors_recursive": "", - "blkio.io_service_time_recursive": "", - "blkio.io_wait_time_recursive": "", - "blkio.io_merged_recursive": "", - "blkio.time_recursive": "", - "blkio.throttle.io_service_bytes": throttleServiceBytes, - "blkio.throttle.io_serviced": throttleServiced, - }) - - blkio := &BlkioGroup{} - actualStats := *cgroups.NewStats() - err := blkio.GetStats(helper.CgroupPath, &actualStats) - if err != nil { - t.Fatal(err) - } - - // Verify expected stats. - expectedStats := cgroups.BlkioStats{} - - appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 11030528, "Read") - appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 23, "Write") - appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 42, "Sync") - appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 11030528, "Async") - appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 11030528, "Total") - appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 252, 0, 11030528, "Read") - appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 252, 0, 23, "Write") - appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 252, 0, 42, "Sync") - appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 252, 0, 11030528, "Async") - appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 252, 0, 11030528, "Total") - - appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 164, "Read") - appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 23, "Write") - appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 42, "Sync") - appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 164, "Async") - appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 164, "Total") - appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 252, 0, 164, "Read") - appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 252, 0, 23, "Write") - appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 252, 0, 42, "Sync") - appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 252, 0, 164, "Async") - appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 252, 0, 164, "Total") - - expectBlkioStatsEquals(t, expectedStats, actualStats.BlkioStats) -} - -func TestBlkioSetThrottleReadBpsDevice(t *testing.T) { - helper := NewCgroupTestUtil("blkio", t) - defer helper.cleanup() - - const ( - throttleBefore = `8:0 1024` - ) - - td := configs.NewThrottleDevice(8, 0, 2048) - throttleAfter := td.String() - - helper.writeFileContents(map[string]string{ - "blkio.throttle.read_bps_device": throttleBefore, - }) - - helper.CgroupData.config.Resources.BlkioThrottleReadBpsDevice = []*configs.ThrottleDevice{td} - blkio := &BlkioGroup{} - if err := blkio.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - value, err := getCgroupParamString(helper.CgroupPath, "blkio.throttle.read_bps_device") - if err != nil { - t.Fatalf("Failed to parse blkio.throttle.read_bps_device - %s", err) - } - - if value != throttleAfter { - t.Fatal("Got the wrong value, set blkio.throttle.read_bps_device failed.") - } -} -func TestBlkioSetThrottleWriteBpsDevice(t *testing.T) { - helper := NewCgroupTestUtil("blkio", t) - defer helper.cleanup() - - const ( - throttleBefore = `8:0 1024` - ) - - td := configs.NewThrottleDevice(8, 0, 2048) - throttleAfter := td.String() - - helper.writeFileContents(map[string]string{ - "blkio.throttle.write_bps_device": throttleBefore, - }) - - helper.CgroupData.config.Resources.BlkioThrottleWriteBpsDevice = []*configs.ThrottleDevice{td} - blkio := &BlkioGroup{} - if err := blkio.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - value, err := getCgroupParamString(helper.CgroupPath, "blkio.throttle.write_bps_device") - if err != nil { - t.Fatalf("Failed to parse blkio.throttle.write_bps_device - %s", err) - } - - if value != throttleAfter { - t.Fatal("Got the wrong value, set blkio.throttle.write_bps_device failed.") - } -} -func TestBlkioSetThrottleReadIOpsDevice(t *testing.T) { - helper := NewCgroupTestUtil("blkio", t) - defer helper.cleanup() - - const ( - throttleBefore = `8:0 1024` - ) - - td := configs.NewThrottleDevice(8, 0, 2048) - throttleAfter := td.String() - - helper.writeFileContents(map[string]string{ - "blkio.throttle.read_iops_device": throttleBefore, - }) - - helper.CgroupData.config.Resources.BlkioThrottleReadIOPSDevice = []*configs.ThrottleDevice{td} - blkio := &BlkioGroup{} - if err := blkio.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - value, err := getCgroupParamString(helper.CgroupPath, "blkio.throttle.read_iops_device") - if err != nil { - t.Fatalf("Failed to parse blkio.throttle.read_iops_device - %s", err) - } - - if value != throttleAfter { - t.Fatal("Got the wrong value, set blkio.throttle.read_iops_device failed.") - } -} -func TestBlkioSetThrottleWriteIOpsDevice(t *testing.T) { - helper := NewCgroupTestUtil("blkio", t) - defer helper.cleanup() - - const ( - throttleBefore = `8:0 1024` - ) - - td := configs.NewThrottleDevice(8, 0, 2048) - throttleAfter := td.String() - - helper.writeFileContents(map[string]string{ - "blkio.throttle.write_iops_device": throttleBefore, - }) - - helper.CgroupData.config.Resources.BlkioThrottleWriteIOPSDevice = []*configs.ThrottleDevice{td} - blkio := &BlkioGroup{} - if err := blkio.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - value, err := getCgroupParamString(helper.CgroupPath, "blkio.throttle.write_iops_device") - if err != nil { - t.Fatalf("Failed to parse blkio.throttle.write_iops_device - %s", err) - } - - if value != throttleAfter { - t.Fatal("Got the wrong value, set blkio.throttle.write_iops_device failed.") - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu_test.go deleted file mode 100644 index 554fd5e..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu_test.go +++ /dev/null @@ -1,163 +0,0 @@ -// +build linux - -package fs - -import ( - "fmt" - "strconv" - "testing" - - "github.com/opencontainers/runc/libcontainer/cgroups" -) - -func TestCpuSetShares(t *testing.T) { - helper := NewCgroupTestUtil("cpu", t) - defer helper.cleanup() - - const ( - sharesBefore = 1024 - sharesAfter = 512 - ) - - helper.writeFileContents(map[string]string{ - "cpu.shares": strconv.Itoa(sharesBefore), - }) - - helper.CgroupData.config.Resources.CpuShares = sharesAfter - cpu := &CpuGroup{} - if err := cpu.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - value, err := getCgroupParamUint(helper.CgroupPath, "cpu.shares") - if err != nil { - t.Fatalf("Failed to parse cpu.shares - %s", err) - } - - if value != sharesAfter { - t.Fatal("Got the wrong value, set cpu.shares failed.") - } -} - -func TestCpuSetBandWidth(t *testing.T) { - helper := NewCgroupTestUtil("cpu", t) - defer helper.cleanup() - - const ( - quotaBefore = 8000 - quotaAfter = 5000 - periodBefore = 10000 - periodAfter = 7000 - rtRuntimeBefore = 8000 - rtRuntimeAfter = 5000 - rtPeriodBefore = 10000 - rtPeriodAfter = 7000 - ) - - helper.writeFileContents(map[string]string{ - "cpu.cfs_quota_us": strconv.Itoa(quotaBefore), - "cpu.cfs_period_us": strconv.Itoa(periodBefore), - "cpu.rt_runtime_us": strconv.Itoa(rtRuntimeBefore), - "cpu.rt_period_us": strconv.Itoa(rtPeriodBefore), - }) - - helper.CgroupData.config.Resources.CpuQuota = quotaAfter - helper.CgroupData.config.Resources.CpuPeriod = periodAfter - helper.CgroupData.config.Resources.CpuRtRuntime = rtRuntimeAfter - helper.CgroupData.config.Resources.CpuRtPeriod = rtPeriodAfter - cpu := &CpuGroup{} - if err := cpu.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - quota, err := getCgroupParamUint(helper.CgroupPath, "cpu.cfs_quota_us") - if err != nil { - t.Fatalf("Failed to parse cpu.cfs_quota_us - %s", err) - } - if quota != quotaAfter { - t.Fatal("Got the wrong value, set cpu.cfs_quota_us failed.") - } - - period, err := getCgroupParamUint(helper.CgroupPath, "cpu.cfs_period_us") - if err != nil { - t.Fatalf("Failed to parse cpu.cfs_period_us - %s", err) - } - if period != periodAfter { - t.Fatal("Got the wrong value, set cpu.cfs_period_us failed.") - } - rtRuntime, err := getCgroupParamUint(helper.CgroupPath, "cpu.rt_runtime_us") - if err != nil { - t.Fatalf("Failed to parse cpu.rt_runtime_us - %s", err) - } - if rtRuntime != rtRuntimeAfter { - t.Fatal("Got the wrong value, set cpu.rt_runtime_us failed.") - } - rtPeriod, err := getCgroupParamUint(helper.CgroupPath, "cpu.rt_period_us") - if err != nil { - t.Fatalf("Failed to parse cpu.rt_period_us - %s", err) - } - if rtPeriod != rtPeriodAfter { - t.Fatal("Got the wrong value, set cpu.rt_period_us failed.") - } -} - -func TestCpuStats(t *testing.T) { - helper := NewCgroupTestUtil("cpu", t) - defer helper.cleanup() - - const ( - kNrPeriods = 2000 - kNrThrottled = 200 - kThrottledTime = uint64(18446744073709551615) - ) - - cpuStatContent := fmt.Sprintf("nr_periods %d\n nr_throttled %d\n throttled_time %d\n", - kNrPeriods, kNrThrottled, kThrottledTime) - helper.writeFileContents(map[string]string{ - "cpu.stat": cpuStatContent, - }) - - cpu := &CpuGroup{} - actualStats := *cgroups.NewStats() - err := cpu.GetStats(helper.CgroupPath, &actualStats) - if err != nil { - t.Fatal(err) - } - - expectedStats := cgroups.ThrottlingData{ - Periods: kNrPeriods, - ThrottledPeriods: kNrThrottled, - ThrottledTime: kThrottledTime} - - expectThrottlingDataEquals(t, expectedStats, actualStats.CpuStats.ThrottlingData) -} - -func TestNoCpuStatFile(t *testing.T) { - helper := NewCgroupTestUtil("cpu", t) - defer helper.cleanup() - - cpu := &CpuGroup{} - actualStats := *cgroups.NewStats() - err := cpu.GetStats(helper.CgroupPath, &actualStats) - if err != nil { - t.Fatal("Expected not to fail, but did") - } -} - -func TestInvalidCpuStat(t *testing.T) { - helper := NewCgroupTestUtil("cpu", t) - defer helper.cleanup() - cpuStatContent := `nr_periods 2000 - nr_throttled 200 - throttled_time fortytwo` - helper.writeFileContents(map[string]string{ - "cpu.stat": cpuStatContent, - }) - - cpu := &CpuGroup{} - actualStats := *cgroups.NewStats() - err := cpu.GetStats(helper.CgroupPath, &actualStats) - if err == nil { - t.Fatal("Expected failed stat parsing.") - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset_test.go deleted file mode 100644 index 0f92915..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset_test.go +++ /dev/null @@ -1,65 +0,0 @@ -// +build linux - -package fs - -import ( - "testing" -) - -func TestCpusetSetCpus(t *testing.T) { - helper := NewCgroupTestUtil("cpuset", t) - defer helper.cleanup() - - const ( - cpusBefore = "0" - cpusAfter = "1-3" - ) - - helper.writeFileContents(map[string]string{ - "cpuset.cpus": cpusBefore, - }) - - helper.CgroupData.config.Resources.CpusetCpus = cpusAfter - cpuset := &CpusetGroup{} - if err := cpuset.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - value, err := getCgroupParamString(helper.CgroupPath, "cpuset.cpus") - if err != nil { - t.Fatalf("Failed to parse cpuset.cpus - %s", err) - } - - if value != cpusAfter { - t.Fatal("Got the wrong value, set cpuset.cpus failed.") - } -} - -func TestCpusetSetMems(t *testing.T) { - helper := NewCgroupTestUtil("cpuset", t) - defer helper.cleanup() - - const ( - memsBefore = "0" - memsAfter = "1" - ) - - helper.writeFileContents(map[string]string{ - "cpuset.mems": memsBefore, - }) - - helper.CgroupData.config.Resources.CpusetMems = memsAfter - cpuset := &CpusetGroup{} - if err := cpuset.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - value, err := getCgroupParamString(helper.CgroupPath, "cpuset.mems") - if err != nil { - t.Fatalf("Failed to parse cpuset.mems - %s", err) - } - - if value != memsAfter { - t.Fatal("Got the wrong value, set cpuset.mems failed.") - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go index 4969798..5f78331 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go @@ -5,6 +5,7 @@ package fs import ( "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/system" ) type DevicesGroup struct { @@ -25,6 +26,10 @@ func (s *DevicesGroup) Apply(d *cgroupData) error { } func (s *DevicesGroup) Set(path string, cgroup *configs.Cgroup) error { + if system.RunningInUserNS() { + return nil + } + devices := cgroup.Resources.Devices if len(devices) > 0 { for _, dev := range devices { diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices_test.go deleted file mode 100644 index ee44084..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices_test.go +++ /dev/null @@ -1,84 +0,0 @@ -// +build linux - -package fs - -import ( - "testing" - - "github.com/opencontainers/runc/libcontainer/configs" -) - -var ( - allowedDevices = []*configs.Device{ - { - Path: "/dev/zero", - Type: 'c', - Major: 1, - Minor: 5, - Permissions: "rwm", - FileMode: 0666, - }, - } - allowedList = "c 1:5 rwm" - deniedDevices = []*configs.Device{ - { - Path: "/dev/null", - Type: 'c', - Major: 1, - Minor: 3, - Permissions: "rwm", - FileMode: 0666, - }, - } - deniedList = "c 1:3 rwm" -) - -func TestDevicesSetAllow(t *testing.T) { - helper := NewCgroupTestUtil("devices", t) - defer helper.cleanup() - - helper.writeFileContents(map[string]string{ - "devices.deny": "a", - }) - - helper.CgroupData.config.Resources.AllowAllDevices = false - helper.CgroupData.config.Resources.AllowedDevices = allowedDevices - devices := &DevicesGroup{} - if err := devices.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - value, err := getCgroupParamString(helper.CgroupPath, "devices.allow") - if err != nil { - t.Fatalf("Failed to parse devices.allow - %s", err) - } - - if value != allowedList { - t.Fatal("Got the wrong value, set devices.allow failed.") - } -} - -func TestDevicesSetDeny(t *testing.T) { - helper := NewCgroupTestUtil("devices", t) - defer helper.cleanup() - - helper.writeFileContents(map[string]string{ - "devices.allow": "a", - }) - - helper.CgroupData.config.Resources.AllowAllDevices = true - helper.CgroupData.config.Resources.DeniedDevices = deniedDevices - devices := &DevicesGroup{} - if err := devices.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - value, err := getCgroupParamString(helper.CgroupPath, "devices.deny") - if err != nil { - t.Fatalf("Failed to parse devices.deny - %s", err) - } - - if value != deniedList { - t.Fatal("Got the wrong value, set devices.deny failed.") - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer_test.go deleted file mode 100644 index 77708db..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer_test.go +++ /dev/null @@ -1,47 +0,0 @@ -// +build linux - -package fs - -import ( - "testing" - - "github.com/opencontainers/runc/libcontainer/configs" -) - -func TestFreezerSetState(t *testing.T) { - helper := NewCgroupTestUtil("freezer", t) - defer helper.cleanup() - - helper.writeFileContents(map[string]string{ - "freezer.state": string(configs.Frozen), - }) - - helper.CgroupData.config.Resources.Freezer = configs.Thawed - freezer := &FreezerGroup{} - if err := freezer.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - value, err := getCgroupParamString(helper.CgroupPath, "freezer.state") - if err != nil { - t.Fatalf("Failed to parse freezer.state - %s", err) - } - if value != string(configs.Thawed) { - t.Fatal("Got the wrong value, set freezer.state failed.") - } -} - -func TestFreezerSetInvalidState(t *testing.T) { - helper := NewCgroupTestUtil("freezer", t) - defer helper.cleanup() - - const ( - invalidArg configs.FreezerState = "Invalid" - ) - - helper.CgroupData.config.Resources.Freezer = invalidArg - freezer := &FreezerGroup{} - if err := freezer.Set(helper.CgroupPath, helper.CgroupData.config); err == nil { - t.Fatal("Failed to return invalid argument error") - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/hugetlb_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/hugetlb_test.go deleted file mode 100644 index 2d41c4e..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/hugetlb_test.go +++ /dev/null @@ -1,154 +0,0 @@ -// +build linux - -package fs - -import ( - "fmt" - "strconv" - "testing" - - "github.com/opencontainers/runc/libcontainer/cgroups" - "github.com/opencontainers/runc/libcontainer/configs" -) - -const ( - hugetlbUsageContents = "128\n" - hugetlbMaxUsageContents = "256\n" - hugetlbFailcnt = "100\n" -) - -var ( - usage = "hugetlb.%s.usage_in_bytes" - limit = "hugetlb.%s.limit_in_bytes" - maxUsage = "hugetlb.%s.max_usage_in_bytes" - failcnt = "hugetlb.%s.failcnt" -) - -func TestHugetlbSetHugetlb(t *testing.T) { - helper := NewCgroupTestUtil("hugetlb", t) - defer helper.cleanup() - - const ( - hugetlbBefore = 256 - hugetlbAfter = 512 - ) - - for _, pageSize := range HugePageSizes { - helper.writeFileContents(map[string]string{ - fmt.Sprintf(limit, pageSize): strconv.Itoa(hugetlbBefore), - }) - } - - for _, pageSize := range HugePageSizes { - helper.CgroupData.config.Resources.HugetlbLimit = []*configs.HugepageLimit{ - { - Pagesize: pageSize, - Limit: hugetlbAfter, - }, - } - hugetlb := &HugetlbGroup{} - if err := hugetlb.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - } - - for _, pageSize := range HugePageSizes { - limit := fmt.Sprintf(limit, pageSize) - value, err := getCgroupParamUint(helper.CgroupPath, limit) - if err != nil { - t.Fatalf("Failed to parse %s - %s", limit, err) - } - if value != hugetlbAfter { - t.Fatalf("Set hugetlb.limit_in_bytes failed. Expected: %v, Got: %v", hugetlbAfter, value) - } - } -} - -func TestHugetlbStats(t *testing.T) { - helper := NewCgroupTestUtil("hugetlb", t) - defer helper.cleanup() - for _, pageSize := range HugePageSizes { - helper.writeFileContents(map[string]string{ - fmt.Sprintf(usage, pageSize): hugetlbUsageContents, - fmt.Sprintf(maxUsage, pageSize): hugetlbMaxUsageContents, - fmt.Sprintf(failcnt, pageSize): hugetlbFailcnt, - }) - } - - hugetlb := &HugetlbGroup{} - actualStats := *cgroups.NewStats() - err := hugetlb.GetStats(helper.CgroupPath, &actualStats) - if err != nil { - t.Fatal(err) - } - expectedStats := cgroups.HugetlbStats{Usage: 128, MaxUsage: 256, Failcnt: 100} - for _, pageSize := range HugePageSizes { - expectHugetlbStatEquals(t, expectedStats, actualStats.HugetlbStats[pageSize]) - } -} - -func TestHugetlbStatsNoUsageFile(t *testing.T) { - helper := NewCgroupTestUtil("hugetlb", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - maxUsage: hugetlbMaxUsageContents, - }) - - hugetlb := &HugetlbGroup{} - actualStats := *cgroups.NewStats() - err := hugetlb.GetStats(helper.CgroupPath, &actualStats) - if err == nil { - t.Fatal("Expected failure") - } -} - -func TestHugetlbStatsNoMaxUsageFile(t *testing.T) { - helper := NewCgroupTestUtil("hugetlb", t) - defer helper.cleanup() - for _, pageSize := range HugePageSizes { - helper.writeFileContents(map[string]string{ - fmt.Sprintf(usage, pageSize): hugetlbUsageContents, - }) - } - - hugetlb := &HugetlbGroup{} - actualStats := *cgroups.NewStats() - err := hugetlb.GetStats(helper.CgroupPath, &actualStats) - if err == nil { - t.Fatal("Expected failure") - } -} - -func TestHugetlbStatsBadUsageFile(t *testing.T) { - helper := NewCgroupTestUtil("hugetlb", t) - defer helper.cleanup() - for _, pageSize := range HugePageSizes { - helper.writeFileContents(map[string]string{ - fmt.Sprintf(usage, pageSize): "bad", - maxUsage: hugetlbMaxUsageContents, - }) - } - - hugetlb := &HugetlbGroup{} - actualStats := *cgroups.NewStats() - err := hugetlb.GetStats(helper.CgroupPath, &actualStats) - if err == nil { - t.Fatal("Expected failure") - } -} - -func TestHugetlbStatsBadMaxUsageFile(t *testing.T) { - helper := NewCgroupTestUtil("hugetlb", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - usage: hugetlbUsageContents, - maxUsage: "bad", - }) - - hugetlb := &HugetlbGroup{} - actualStats := *cgroups.NewStats() - err := hugetlb.GetStats(helper.CgroupPath, &actualStats) - if err == nil { - t.Fatal("Expected failure") - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go index 2121f6d..e3fd327 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go @@ -86,14 +86,14 @@ func (s *MemoryGroup) Set(path string, cgroup *configs.Cgroup) error { return err } } - if cgroup.Resources.MemorySwappiness >= 0 && cgroup.Resources.MemorySwappiness <= 100 { - if err := writeFile(path, "memory.swappiness", strconv.FormatInt(cgroup.Resources.MemorySwappiness, 10)); err != nil { + if cgroup.Resources.MemorySwappiness == nil || int64(*cgroup.Resources.MemorySwappiness) == -1 { + return nil + } else if int64(*cgroup.Resources.MemorySwappiness) >= 0 && int64(*cgroup.Resources.MemorySwappiness) <= 100 { + if err := writeFile(path, "memory.swappiness", strconv.FormatInt(*cgroup.Resources.MemorySwappiness, 10)); err != nil { return err } - } else if cgroup.Resources.MemorySwappiness == -1 { - return nil } else { - return fmt.Errorf("invalid value:%d. valid memory swappiness range is 0-100", cgroup.Resources.MemorySwappiness) + return fmt.Errorf("invalid value:%d. valid memory swappiness range is 0-100", int64(*cgroup.Resources.MemorySwappiness)) } return nil @@ -149,7 +149,7 @@ func memoryAssigned(cgroup *configs.Cgroup) bool { cgroup.Resources.MemorySwap > 0 || cgroup.Resources.KernelMemory > 0 || cgroup.Resources.OomKillDisable || - cgroup.Resources.MemorySwappiness != -1 + (cgroup.Resources.MemorySwappiness != nil && *cgroup.Resources.MemorySwappiness != -1) } func getMemoryData(path, name string) (cgroups.MemoryData, error) { diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory_test.go deleted file mode 100644 index 6dc4ae7..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory_test.go +++ /dev/null @@ -1,339 +0,0 @@ -// +build linux - -package fs - -import ( - "strconv" - "testing" - - "github.com/opencontainers/runc/libcontainer/cgroups" -) - -const ( - memoryStatContents = `cache 512 -rss 1024` - memoryUsageContents = "2048\n" - memoryMaxUsageContents = "4096\n" - memoryFailcnt = "100\n" - memoryLimitContents = "8192\n" -) - -func TestMemorySetMemory(t *testing.T) { - helper := NewCgroupTestUtil("memory", t) - defer helper.cleanup() - - const ( - memoryBefore = 314572800 // 300M - memoryAfter = 524288000 // 500M - reservationBefore = 209715200 // 200M - reservationAfter = 314572800 // 300M - ) - - helper.writeFileContents(map[string]string{ - "memory.limit_in_bytes": strconv.Itoa(memoryBefore), - "memory.soft_limit_in_bytes": strconv.Itoa(reservationBefore), - }) - - helper.CgroupData.config.Resources.Memory = memoryAfter - helper.CgroupData.config.Resources.MemoryReservation = reservationAfter - memory := &MemoryGroup{} - if err := memory.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - value, err := getCgroupParamUint(helper.CgroupPath, "memory.limit_in_bytes") - if err != nil { - t.Fatalf("Failed to parse memory.limit_in_bytes - %s", err) - } - if value != memoryAfter { - t.Fatal("Got the wrong value, set memory.limit_in_bytes failed.") - } - - value, err = getCgroupParamUint(helper.CgroupPath, "memory.soft_limit_in_bytes") - if err != nil { - t.Fatalf("Failed to parse memory.soft_limit_in_bytes - %s", err) - } - if value != reservationAfter { - t.Fatal("Got the wrong value, set memory.soft_limit_in_bytes failed.") - } -} - -func TestMemorySetMemoryswap(t *testing.T) { - helper := NewCgroupTestUtil("memory", t) - defer helper.cleanup() - - const ( - memoryswapBefore = 314572800 // 300M - memoryswapAfter = 524288000 // 500M - ) - - helper.writeFileContents(map[string]string{ - "memory.memsw.limit_in_bytes": strconv.Itoa(memoryswapBefore), - }) - - helper.CgroupData.config.Resources.MemorySwap = memoryswapAfter - memory := &MemoryGroup{} - if err := memory.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - value, err := getCgroupParamUint(helper.CgroupPath, "memory.memsw.limit_in_bytes") - if err != nil { - t.Fatalf("Failed to parse memory.memsw.limit_in_bytes - %s", err) - } - if value != memoryswapAfter { - t.Fatal("Got the wrong value, set memory.memsw.limit_in_bytes failed.") - } -} - -func TestMemorySetKernelMemory(t *testing.T) { - helper := NewCgroupTestUtil("memory", t) - defer helper.cleanup() - - const ( - kernelMemoryBefore = 314572800 // 300M - kernelMemoryAfter = 524288000 // 500M - ) - - helper.writeFileContents(map[string]string{ - "memory.kmem.limit_in_bytes": strconv.Itoa(kernelMemoryBefore), - }) - - helper.CgroupData.config.Resources.KernelMemory = kernelMemoryAfter - memory := &MemoryGroup{} - if err := memory.SetKernelMemory(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - value, err := getCgroupParamUint(helper.CgroupPath, "memory.kmem.limit_in_bytes") - if err != nil { - t.Fatalf("Failed to parse memory.kmem.limit_in_bytes - %s", err) - } - if value != kernelMemoryAfter { - t.Fatal("Got the wrong value, set memory.kmem.limit_in_bytes failed.") - } -} - -func TestMemorySetMemorySwappinessDefault(t *testing.T) { - helper := NewCgroupTestUtil("memory", t) - defer helper.cleanup() - - const ( - swappinessBefore = 60 //deafult is 60 - swappinessAfter = 0 - ) - - helper.writeFileContents(map[string]string{ - "memory.swappiness": strconv.Itoa(swappinessBefore), - }) - - helper.CgroupData.config.Resources.Memory = swappinessAfter - memory := &MemoryGroup{} - if err := memory.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - value, err := getCgroupParamUint(helper.CgroupPath, "memory.swappiness") - if err != nil { - t.Fatalf("Failed to parse memory.swappiness - %s", err) - } - if value != swappinessAfter { - t.Fatal("Got the wrong value, set memory.swappiness failed.") - } -} - -func TestMemoryStats(t *testing.T) { - helper := NewCgroupTestUtil("memory", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "memory.stat": memoryStatContents, - "memory.usage_in_bytes": memoryUsageContents, - "memory.limit_in_bytes": memoryLimitContents, - "memory.max_usage_in_bytes": memoryMaxUsageContents, - "memory.failcnt": memoryFailcnt, - "memory.memsw.usage_in_bytes": memoryUsageContents, - "memory.memsw.max_usage_in_bytes": memoryMaxUsageContents, - "memory.memsw.failcnt": memoryFailcnt, - "memory.memsw.limit_in_bytes": memoryLimitContents, - "memory.kmem.usage_in_bytes": memoryUsageContents, - "memory.kmem.max_usage_in_bytes": memoryMaxUsageContents, - "memory.kmem.failcnt": memoryFailcnt, - "memory.kmem.limit_in_bytes": memoryLimitContents, - }) - - memory := &MemoryGroup{} - actualStats := *cgroups.NewStats() - err := memory.GetStats(helper.CgroupPath, &actualStats) - if err != nil { - t.Fatal(err) - } - expectedStats := cgroups.MemoryStats{Cache: 512, Usage: cgroups.MemoryData{Usage: 2048, MaxUsage: 4096, Failcnt: 100, Limit: 8192}, SwapUsage: cgroups.MemoryData{Usage: 2048, MaxUsage: 4096, Failcnt: 100, Limit: 8192}, KernelUsage: cgroups.MemoryData{Usage: 2048, MaxUsage: 4096, Failcnt: 100, Limit: 8192}, Stats: map[string]uint64{"cache": 512, "rss": 1024}} - expectMemoryStatEquals(t, expectedStats, actualStats.MemoryStats) -} - -func TestMemoryStatsNoStatFile(t *testing.T) { - helper := NewCgroupTestUtil("memory", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "memory.usage_in_bytes": memoryUsageContents, - "memory.max_usage_in_bytes": memoryMaxUsageContents, - "memory.limit_in_bytes": memoryLimitContents, - }) - - memory := &MemoryGroup{} - actualStats := *cgroups.NewStats() - err := memory.GetStats(helper.CgroupPath, &actualStats) - if err != nil { - t.Fatal(err) - } -} - -func TestMemoryStatsNoUsageFile(t *testing.T) { - helper := NewCgroupTestUtil("memory", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "memory.stat": memoryStatContents, - "memory.max_usage_in_bytes": memoryMaxUsageContents, - "memory.limit_in_bytes": memoryLimitContents, - }) - - memory := &MemoryGroup{} - actualStats := *cgroups.NewStats() - err := memory.GetStats(helper.CgroupPath, &actualStats) - if err == nil { - t.Fatal("Expected failure") - } -} - -func TestMemoryStatsNoMaxUsageFile(t *testing.T) { - helper := NewCgroupTestUtil("memory", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "memory.stat": memoryStatContents, - "memory.usage_in_bytes": memoryUsageContents, - "memory.limit_in_bytes": memoryLimitContents, - }) - - memory := &MemoryGroup{} - actualStats := *cgroups.NewStats() - err := memory.GetStats(helper.CgroupPath, &actualStats) - if err == nil { - t.Fatal("Expected failure") - } -} - -func TestMemoryStatsNoLimitInBytesFile(t *testing.T) { - helper := NewCgroupTestUtil("memory", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "memory.stat": memoryStatContents, - "memory.usage_in_bytes": memoryUsageContents, - "memory.max_usage_in_bytes": memoryMaxUsageContents, - }) - - memory := &MemoryGroup{} - actualStats := *cgroups.NewStats() - err := memory.GetStats(helper.CgroupPath, &actualStats) - if err == nil { - t.Fatal("Expected failure") - } -} - -func TestMemoryStatsBadStatFile(t *testing.T) { - helper := NewCgroupTestUtil("memory", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "memory.stat": "rss rss", - "memory.usage_in_bytes": memoryUsageContents, - "memory.max_usage_in_bytes": memoryMaxUsageContents, - "memory.limit_in_bytes": memoryLimitContents, - }) - - memory := &MemoryGroup{} - actualStats := *cgroups.NewStats() - err := memory.GetStats(helper.CgroupPath, &actualStats) - if err == nil { - t.Fatal("Expected failure") - } -} - -func TestMemoryStatsBadUsageFile(t *testing.T) { - helper := NewCgroupTestUtil("memory", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "memory.stat": memoryStatContents, - "memory.usage_in_bytes": "bad", - "memory.max_usage_in_bytes": memoryMaxUsageContents, - "memory.limit_in_bytes": memoryLimitContents, - }) - - memory := &MemoryGroup{} - actualStats := *cgroups.NewStats() - err := memory.GetStats(helper.CgroupPath, &actualStats) - if err == nil { - t.Fatal("Expected failure") - } -} - -func TestMemoryStatsBadMaxUsageFile(t *testing.T) { - helper := NewCgroupTestUtil("memory", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "memory.stat": memoryStatContents, - "memory.usage_in_bytes": memoryUsageContents, - "memory.max_usage_in_bytes": "bad", - "memory.limit_in_bytes": memoryLimitContents, - }) - - memory := &MemoryGroup{} - actualStats := *cgroups.NewStats() - err := memory.GetStats(helper.CgroupPath, &actualStats) - if err == nil { - t.Fatal("Expected failure") - } -} - -func TestMemoryStatsBadLimitInBytesFile(t *testing.T) { - helper := NewCgroupTestUtil("memory", t) - defer helper.cleanup() - helper.writeFileContents(map[string]string{ - "memory.stat": memoryStatContents, - "memory.usage_in_bytes": memoryUsageContents, - "memory.max_usage_in_bytes": memoryMaxUsageContents, - "memory.limit_in_bytes": "bad", - }) - - memory := &MemoryGroup{} - actualStats := *cgroups.NewStats() - err := memory.GetStats(helper.CgroupPath, &actualStats) - if err == nil { - t.Fatal("Expected failure") - } -} - -func TestMemorySetOomControl(t *testing.T) { - helper := NewCgroupTestUtil("memory", t) - defer helper.cleanup() - - const ( - oom_kill_disable = 1 // disable oom killer, default is 0 - ) - - helper.writeFileContents(map[string]string{ - "memory.oom_control": strconv.Itoa(oom_kill_disable), - }) - - memory := &MemoryGroup{} - if err := memory.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - value, err := getCgroupParamUint(helper.CgroupPath, "memory.oom_control") - if err != nil { - t.Fatalf("Failed to parse memory.oom_control - %s", err) - } - - if value != oom_kill_disable { - t.Fatalf("Got the wrong value, set memory.oom_control failed.") - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/name.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/name.go index 0e423f6..d8cf1d8 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/name.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/name.go @@ -9,6 +9,7 @@ import ( type NameGroup struct { GroupName string + Join bool } func (s *NameGroup) Name() string { @@ -16,6 +17,10 @@ func (s *NameGroup) Name() string { } func (s *NameGroup) Apply(d *cgroupData) error { + if s.Join { + // ignore errors if the named cgroup does not exist + d.join(s.GroupName) + } return nil } @@ -24,6 +29,9 @@ func (s *NameGroup) Set(path string, cgroup *configs.Cgroup) error { } func (s *NameGroup) Remove(d *cgroupData) error { + if s.Join { + removePath(d.path(s.GroupName)) + } return nil } diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls_test.go deleted file mode 100644 index 974bd9d..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls_test.go +++ /dev/null @@ -1,38 +0,0 @@ -// +build linux - -package fs - -import ( - "testing" -) - -const ( - classidBefore = "0x100002" - classidAfter = "0x100001" -) - -func TestNetClsSetClassid(t *testing.T) { - helper := NewCgroupTestUtil("net_cls", t) - defer helper.cleanup() - - helper.writeFileContents(map[string]string{ - "net_cls.classid": classidBefore, - }) - - helper.CgroupData.config.Resources.NetClsClassid = classidAfter - netcls := &NetClsGroup{} - if err := netcls.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - // As we are in mock environment, we can't get correct value of classid from - // net_cls.classid. - // So. we just judge if we successfully write classid into file - value, err := getCgroupParamString(helper.CgroupPath, "net_cls.classid") - if err != nil { - t.Fatalf("Failed to parse net_cls.classid - %s", err) - } - if value != classidAfter { - t.Fatal("Got the wrong value, set net_cls.classid failed.") - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_prio_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_prio_test.go deleted file mode 100644 index efbf063..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_prio_test.go +++ /dev/null @@ -1,38 +0,0 @@ -// +build linux - -package fs - -import ( - "strings" - "testing" - - "github.com/opencontainers/runc/libcontainer/configs" -) - -var ( - prioMap = []*configs.IfPrioMap{ - { - Interface: "test", - Priority: 5, - }, - } -) - -func TestNetPrioSetIfPrio(t *testing.T) { - helper := NewCgroupTestUtil("net_prio", t) - defer helper.cleanup() - - helper.CgroupData.config.Resources.NetPrioIfpriomap = prioMap - netPrio := &NetPrioGroup{} - if err := netPrio.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { - t.Fatal(err) - } - - value, err := getCgroupParamString(helper.CgroupPath, "net_prio.ifpriomap") - if err != nil { - t.Fatalf("Failed to parse net_prio.ifpriomap - %s", err) - } - if !strings.Contains(value, "test 5") { - t.Fatal("Got the wrong value, set net_prio.ifpriomap failed.") - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids_test.go deleted file mode 100644 index 06b1192..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids_test.go +++ /dev/null @@ -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) - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/stats_util_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/stats_util_test.go deleted file mode 100644 index 295e7bd..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/stats_util_test.go +++ /dev/null @@ -1,117 +0,0 @@ -// +build linux - -package fs - -import ( - "fmt" - "testing" - - "github.com/Sirupsen/logrus" - "github.com/opencontainers/runc/libcontainer/cgroups" -) - -func blkioStatEntryEquals(expected, actual []cgroups.BlkioStatEntry) error { - if len(expected) != len(actual) { - return fmt.Errorf("blkioStatEntries length do not match") - } - for i, expValue := range expected { - actValue := actual[i] - if expValue != actValue { - return fmt.Errorf("Expected blkio stat entry %v but found %v", expValue, actValue) - } - } - return nil -} - -func expectBlkioStatsEquals(t *testing.T, expected, actual cgroups.BlkioStats) { - if err := blkioStatEntryEquals(expected.IoServiceBytesRecursive, actual.IoServiceBytesRecursive); err != nil { - logrus.Printf("blkio IoServiceBytesRecursive do not match - %s\n", err) - t.Fail() - } - - if err := blkioStatEntryEquals(expected.IoServicedRecursive, actual.IoServicedRecursive); err != nil { - logrus.Printf("blkio IoServicedRecursive do not match - %s\n", err) - t.Fail() - } - - if err := blkioStatEntryEquals(expected.IoQueuedRecursive, actual.IoQueuedRecursive); err != nil { - logrus.Printf("blkio IoQueuedRecursive do not match - %s\n", err) - t.Fail() - } - - if err := blkioStatEntryEquals(expected.SectorsRecursive, actual.SectorsRecursive); err != nil { - logrus.Printf("blkio SectorsRecursive do not match - %s\n", err) - t.Fail() - } - - if err := blkioStatEntryEquals(expected.IoServiceTimeRecursive, actual.IoServiceTimeRecursive); err != nil { - logrus.Printf("blkio IoServiceTimeRecursive do not match - %s\n", err) - t.Fail() - } - - if err := blkioStatEntryEquals(expected.IoWaitTimeRecursive, actual.IoWaitTimeRecursive); err != nil { - logrus.Printf("blkio IoWaitTimeRecursive do not match - %s\n", err) - t.Fail() - } - - if err := blkioStatEntryEquals(expected.IoMergedRecursive, actual.IoMergedRecursive); err != nil { - logrus.Printf("blkio IoMergedRecursive do not match - %v vs %v\n", expected.IoMergedRecursive, actual.IoMergedRecursive) - t.Fail() - } - - if err := blkioStatEntryEquals(expected.IoTimeRecursive, actual.IoTimeRecursive); err != nil { - logrus.Printf("blkio IoTimeRecursive do not match - %s\n", err) - t.Fail() - } -} - -func expectThrottlingDataEquals(t *testing.T, expected, actual cgroups.ThrottlingData) { - if expected != actual { - logrus.Printf("Expected throttling data %v but found %v\n", expected, actual) - t.Fail() - } -} - -func expectHugetlbStatEquals(t *testing.T, expected, actual cgroups.HugetlbStats) { - if expected != actual { - logrus.Printf("Expected hugetlb stats %v but found %v\n", expected, actual) - t.Fail() - } -} - -func expectMemoryStatEquals(t *testing.T, expected, actual cgroups.MemoryStats) { - expectMemoryDataEquals(t, expected.Usage, actual.Usage) - expectMemoryDataEquals(t, expected.SwapUsage, actual.SwapUsage) - expectMemoryDataEquals(t, expected.KernelUsage, actual.KernelUsage) - - for key, expValue := range expected.Stats { - actValue, ok := actual.Stats[key] - if !ok { - logrus.Printf("Expected memory stat key %s not found\n", key) - t.Fail() - } - if expValue != actValue { - logrus.Printf("Expected memory stat value %d but found %d\n", expValue, actValue) - t.Fail() - } - } -} - -func expectMemoryDataEquals(t *testing.T, expected, actual cgroups.MemoryData) { - if expected.Usage != actual.Usage { - logrus.Printf("Expected memory usage %d but found %d\n", expected.Usage, actual.Usage) - t.Fail() - } - if expected.MaxUsage != actual.MaxUsage { - logrus.Printf("Expected memory max usage %d but found %d\n", expected.MaxUsage, actual.MaxUsage) - t.Fail() - } - if expected.Failcnt != actual.Failcnt { - logrus.Printf("Expected memory failcnt %d but found %d\n", expected.Failcnt, actual.Failcnt) - t.Fail() - } - if expected.Limit != actual.Limit { - logrus.Printf("Expected memory limit %d but found %d\n", expected.Limit, actual.Limit) - t.Fail() - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/util_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/util_test.go deleted file mode 100644 index 7067e79..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/util_test.go +++ /dev/null @@ -1,67 +0,0 @@ -// +build linux - -/* -Utility for testing cgroup operations. - -Creates a mock of the cgroup filesystem for the duration of the test. -*/ -package fs - -import ( - "io/ioutil" - "os" - "path/filepath" - "testing" - - "github.com/opencontainers/runc/libcontainer/configs" -) - -type cgroupTestUtil struct { - // cgroup data to use in tests. - CgroupData *cgroupData - - // Path to the mock cgroup directory. - CgroupPath string - - // Temporary directory to store mock cgroup filesystem. - tempDir string - t *testing.T -} - -// Creates a new test util for the specified subsystem -func NewCgroupTestUtil(subsystem string, t *testing.T) *cgroupTestUtil { - d := &cgroupData{ - config: &configs.Cgroup{}, - } - d.config.Resources = &configs.Resources{} - tempDir, err := ioutil.TempDir("", "cgroup_test") - if err != nil { - t.Fatal(err) - } - d.root = tempDir - testCgroupPath := filepath.Join(d.root, subsystem) - if err != nil { - t.Fatal(err) - } - - // Ensure the full mock cgroup path exists. - err = os.MkdirAll(testCgroupPath, 0755) - if err != nil { - t.Fatal(err) - } - return &cgroupTestUtil{CgroupData: d, CgroupPath: testCgroupPath, tempDir: tempDir, t: t} -} - -func (c *cgroupTestUtil) cleanup() { - os.RemoveAll(c.tempDir) -} - -// Write the specified contents on the mock of the specified cgroup files. -func (c *cgroupTestUtil) writeFileContents(fileContents map[string]string) { - for file, contents := range fileContents { - err := writeFile(c.CgroupPath, file, contents) - if err != nil { - c.t.Fatal(err) - } - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/utils_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/utils_test.go deleted file mode 100644 index 99cdc18..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/utils_test.go +++ /dev/null @@ -1,97 +0,0 @@ -// +build linux - -package fs - -import ( - "io/ioutil" - "math" - "os" - "path/filepath" - "strconv" - "testing" -) - -const ( - cgroupFile = "cgroup.file" - floatValue = 2048.0 - floatString = "2048" -) - -func TestGetCgroupParamsInt(t *testing.T) { - // Setup tempdir. - tempDir, err := ioutil.TempDir("", "cgroup_utils_test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tempDir) - tempFile := filepath.Join(tempDir, cgroupFile) - - // Success. - err = ioutil.WriteFile(tempFile, []byte(floatString), 0755) - if err != nil { - t.Fatal(err) - } - value, err := getCgroupParamUint(tempDir, cgroupFile) - if err != nil { - t.Fatal(err) - } else if value != floatValue { - t.Fatalf("Expected %d to equal %f", value, floatValue) - } - - // Success with new line. - err = ioutil.WriteFile(tempFile, []byte(floatString+"\n"), 0755) - if err != nil { - t.Fatal(err) - } - value, err = getCgroupParamUint(tempDir, cgroupFile) - if err != nil { - t.Fatal(err) - } else if value != floatValue { - t.Fatalf("Expected %d to equal %f", value, floatValue) - } - - // Success with negative values - err = ioutil.WriteFile(tempFile, []byte("-12345"), 0755) - if err != nil { - t.Fatal(err) - } - value, err = getCgroupParamUint(tempDir, cgroupFile) - if err != nil { - t.Fatal(err) - } else if value != 0 { - t.Fatalf("Expected %d to equal %d", value, 0) - } - - // Success with negative values lesser than min int64 - s := strconv.FormatFloat(math.MinInt64, 'f', -1, 64) - err = ioutil.WriteFile(tempFile, []byte(s), 0755) - if err != nil { - t.Fatal(err) - } - value, err = getCgroupParamUint(tempDir, cgroupFile) - if err != nil { - t.Fatal(err) - } else if value != 0 { - t.Fatalf("Expected %d to equal %d", value, 0) - } - - // Not a float. - err = ioutil.WriteFile(tempFile, []byte("not-a-float"), 0755) - if err != nil { - t.Fatal(err) - } - _, err = getCgroupParamUint(tempDir, cgroupFile) - if err == nil { - t.Fatal("Expecting error, got none") - } - - // Unknown file. - err = os.Remove(tempFile) - if err != nil { - t.Fatal(err) - } - _, err = getCgroupParamUint(tempDir, cgroupFile) - if err == nil { - t.Fatal("Expecting error, got none") - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/stats.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/stats.go index 54ace41..a9a0743 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/stats.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/stats.go @@ -46,7 +46,7 @@ type MemoryStats struct { Usage MemoryData `json:"usage,omitempty"` // usage of memory + swap SwapUsage MemoryData `json:"swap_usage,omitempty"` - // usafe of kernel memory + // usage of kernel memory KernelUsage MemoryData `json:"kernel_usage,omitempty"` Stats map[string]uint64 `json:"stats,omitempty"` } @@ -80,7 +80,7 @@ type HugetlbStats struct { Usage uint64 `json:"usage,omitempty"` // maximum usage ever recorded. MaxUsage uint64 `json:"max_usage,omitempty"` - // number of times htgetlb usage allocation failure. + // number of times hugetlb usage allocation failure. Failcnt uint64 `json:"failcnt"` } diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/utils.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/utils.go index 8510c7f..006800d 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/utils.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/utils.go @@ -126,11 +126,11 @@ func getCgroupMountsHelper(ss map[string]bool, mi io.Reader) ([]Mount, error) { scanner := bufio.NewScanner(mi) for scanner.Scan() { txt := scanner.Text() - sepIdx := strings.IndexByte(txt, '-') + sepIdx := strings.Index(txt, " - ") if sepIdx == -1 { return nil, fmt.Errorf("invalid mountinfo format") } - if txt[sepIdx+2:sepIdx+8] != "cgroup" { + if txt[sepIdx+3:sepIdx+9] != "cgroup" { continue } fields := strings.Split(txt, " ") diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/utils_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/utils_test.go deleted file mode 100644 index 179c14a..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/utils_test.go +++ /dev/null @@ -1,138 +0,0 @@ -package cgroups - -import ( - "bytes" - "strings" - "testing" -) - -const fedoraMountinfo = `15 35 0:3 / /proc rw,nosuid,nodev,noexec,relatime shared:5 - proc proc rw -16 35 0:14 / /sys rw,nosuid,nodev,noexec,relatime shared:6 - sysfs sysfs rw,seclabel -17 35 0:5 / /dev rw,nosuid shared:2 - devtmpfs devtmpfs rw,seclabel,size=8056484k,nr_inodes=2014121,mode=755 -18 16 0:15 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime shared:7 - securityfs securityfs rw -19 16 0:13 / /sys/fs/selinux rw,relatime shared:8 - selinuxfs selinuxfs rw -20 17 0:16 / /dev/shm rw,nosuid,nodev shared:3 - tmpfs tmpfs rw,seclabel -21 17 0:10 / /dev/pts rw,nosuid,noexec,relatime shared:4 - devpts devpts rw,seclabel,gid=5,mode=620,ptmxmode=000 -22 35 0:17 / /run rw,nosuid,nodev shared:21 - tmpfs tmpfs rw,seclabel,mode=755 -23 16 0:18 / /sys/fs/cgroup rw,nosuid,nodev,noexec shared:9 - tmpfs tmpfs rw,seclabel,mode=755 -24 23 0:19 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:10 - cgroup cgroup rw,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd -25 16 0:20 / /sys/fs/pstore rw,nosuid,nodev,noexec,relatime shared:20 - pstore pstore rw -26 23 0:21 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:11 - cgroup cgroup rw,cpuset,clone_children -27 23 0:22 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:12 - cgroup cgroup rw,cpuacct,cpu,clone_children -28 23 0:23 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:13 - cgroup cgroup rw,memory,clone_children -29 23 0:24 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:14 - cgroup cgroup rw,devices,clone_children -30 23 0:25 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,freezer,clone_children -31 23 0:26 / /sys/fs/cgroup/net_cls rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,net_cls,clone_children -32 23 0:27 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,blkio,clone_children -33 23 0:28 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,perf_event,clone_children -34 23 0:29 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime shared:19 - cgroup cgroup rw,hugetlb,clone_children -35 1 253:2 / / rw,relatime shared:1 - ext4 /dev/mapper/ssd-root--f20 rw,seclabel,data=ordered -36 15 0:30 / /proc/sys/fs/binfmt_misc rw,relatime shared:22 - autofs systemd-1 rw,fd=38,pgrp=1,timeout=300,minproto=5,maxproto=5,direct -37 17 0:12 / /dev/mqueue rw,relatime shared:23 - mqueue mqueue rw,seclabel -38 35 0:31 / /tmp rw shared:24 - tmpfs tmpfs rw,seclabel -39 17 0:32 / /dev/hugepages rw,relatime shared:25 - hugetlbfs hugetlbfs rw,seclabel -40 16 0:7 / /sys/kernel/debug rw,relatime shared:26 - debugfs debugfs rw -41 16 0:33 / /sys/kernel/config rw,relatime shared:27 - configfs configfs rw -42 35 0:34 / /var/lib/nfs/rpc_pipefs rw,relatime shared:28 - rpc_pipefs sunrpc rw -43 15 0:35 / /proc/fs/nfsd rw,relatime shared:29 - nfsd sunrpc rw -45 35 8:17 / /boot rw,relatime shared:30 - ext4 /dev/sdb1 rw,seclabel,data=ordered -46 35 253:4 / /home rw,relatime shared:31 - ext4 /dev/mapper/ssd-home rw,seclabel,data=ordered -47 35 253:5 / /var/lib/libvirt/images rw,noatime,nodiratime shared:32 - ext4 /dev/mapper/ssd-virt rw,seclabel,discard,data=ordered -48 35 253:12 / /mnt/old rw,relatime shared:33 - ext4 /dev/mapper/HelpDeskRHEL6-FedoraRoot rw,seclabel,data=ordered -121 22 0:36 / /run/user/1000/gvfs rw,nosuid,nodev,relatime shared:104 - fuse.gvfsd-fuse gvfsd-fuse rw,user_id=1000,group_id=1000 -124 16 0:37 / /sys/fs/fuse/connections rw,relatime shared:107 - fusectl fusectl rw -165 38 253:3 / /tmp/mnt rw,relatime shared:147 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered -167 35 253:15 / /var/lib/docker/devicemapper/mnt/aae4076022f0e2b80a2afbf8fc6df450c52080191fcef7fb679a73e6f073e5c2 rw,relatime shared:149 - ext4 /dev/mapper/docker-253:2-425882-aae4076022f0e2b80a2afbf8fc6df450c52080191fcef7fb679a73e6f073e5c2 rw,seclabel,discard,stripe=16,data=ordered -171 35 253:16 / /var/lib/docker/devicemapper/mnt/c71be651f114db95180e472f7871b74fa597ee70a58ccc35cb87139ddea15373 rw,relatime shared:153 - ext4 /dev/mapper/docker-253:2-425882-c71be651f114db95180e472f7871b74fa597ee70a58ccc35cb87139ddea15373 rw,seclabel,discard,stripe=16,data=ordered -175 35 253:17 / /var/lib/docker/devicemapper/mnt/1bac6ab72862d2d5626560df6197cf12036b82e258c53d981fa29adce6f06c3c rw,relatime shared:157 - ext4 /dev/mapper/docker-253:2-425882-1bac6ab72862d2d5626560df6197cf12036b82e258c53d981fa29adce6f06c3c rw,seclabel,discard,stripe=16,data=ordered -179 35 253:18 / /var/lib/docker/devicemapper/mnt/d710a357d77158e80d5b2c55710ae07c94e76d34d21ee7bae65ce5418f739b09 rw,relatime shared:161 - ext4 /dev/mapper/docker-253:2-425882-d710a357d77158e80d5b2c55710ae07c94e76d34d21ee7bae65ce5418f739b09 rw,seclabel,discard,stripe=16,data=ordered -183 35 253:19 / /var/lib/docker/devicemapper/mnt/6479f52366114d5f518db6837254baab48fab39f2ac38d5099250e9a6ceae6c7 rw,relatime shared:165 - ext4 /dev/mapper/docker-253:2-425882-6479f52366114d5f518db6837254baab48fab39f2ac38d5099250e9a6ceae6c7 rw,seclabel,discard,stripe=16,data=ordered -187 35 253:20 / /var/lib/docker/devicemapper/mnt/8d9df91c4cca5aef49eeb2725292aab324646f723a7feab56be34c2ad08268e1 rw,relatime shared:169 - ext4 /dev/mapper/docker-253:2-425882-8d9df91c4cca5aef49eeb2725292aab324646f723a7feab56be34c2ad08268e1 rw,seclabel,discard,stripe=16,data=ordered -191 35 253:21 / /var/lib/docker/devicemapper/mnt/c8240b768603d32e920d365dc9d1dc2a6af46cd23e7ae819947f969e1b4ec661 rw,relatime shared:173 - ext4 /dev/mapper/docker-253:2-425882-c8240b768603d32e920d365dc9d1dc2a6af46cd23e7ae819947f969e1b4ec661 rw,seclabel,discard,stripe=16,data=ordered -195 35 253:22 / /var/lib/docker/devicemapper/mnt/2eb3a01278380bbf3ed12d86ac629eaa70a4351301ee307a5cabe7b5f3b1615f rw,relatime shared:177 - ext4 /dev/mapper/docker-253:2-425882-2eb3a01278380bbf3ed12d86ac629eaa70a4351301ee307a5cabe7b5f3b1615f rw,seclabel,discard,stripe=16,data=ordered -199 35 253:23 / /var/lib/docker/devicemapper/mnt/37a17fb7c9d9b80821235d5f2662879bd3483915f245f9b49cdaa0e38779b70b rw,relatime shared:181 - ext4 /dev/mapper/docker-253:2-425882-37a17fb7c9d9b80821235d5f2662879bd3483915f245f9b49cdaa0e38779b70b rw,seclabel,discard,stripe=16,data=ordered -203 35 253:24 / /var/lib/docker/devicemapper/mnt/aea459ae930bf1de913e2f29428fd80ee678a1e962d4080019d9f9774331ee2b rw,relatime shared:185 - ext4 /dev/mapper/docker-253:2-425882-aea459ae930bf1de913e2f29428fd80ee678a1e962d4080019d9f9774331ee2b rw,seclabel,discard,stripe=16,data=ordered -207 35 253:25 / /var/lib/docker/devicemapper/mnt/928ead0bc06c454bd9f269e8585aeae0a6bd697f46dc8754c2a91309bc810882 rw,relatime shared:189 - ext4 /dev/mapper/docker-253:2-425882-928ead0bc06c454bd9f269e8585aeae0a6bd697f46dc8754c2a91309bc810882 rw,seclabel,discard,stripe=16,data=ordered -211 35 253:26 / /var/lib/docker/devicemapper/mnt/0f284d18481d671644706e7a7244cbcf63d590d634cc882cb8721821929d0420 rw,relatime shared:193 - ext4 /dev/mapper/docker-253:2-425882-0f284d18481d671644706e7a7244cbcf63d590d634cc882cb8721821929d0420 rw,seclabel,discard,stripe=16,data=ordered -215 35 253:27 / /var/lib/docker/devicemapper/mnt/d9dd16722ab34c38db2733e23f69e8f4803ce59658250dd63e98adff95d04919 rw,relatime shared:197 - ext4 /dev/mapper/docker-253:2-425882-d9dd16722ab34c38db2733e23f69e8f4803ce59658250dd63e98adff95d04919 rw,seclabel,discard,stripe=16,data=ordered -219 35 253:28 / /var/lib/docker/devicemapper/mnt/bc4500479f18c2c08c21ad5282e5f826a016a386177d9874c2764751c031d634 rw,relatime shared:201 - ext4 /dev/mapper/docker-253:2-425882-bc4500479f18c2c08c21ad5282e5f826a016a386177d9874c2764751c031d634 rw,seclabel,discard,stripe=16,data=ordered -223 35 253:29 / /var/lib/docker/devicemapper/mnt/7770c8b24eb3d5cc159a065910076938910d307ab2f5d94e1dc3b24c06ee2c8a rw,relatime shared:205 - ext4 /dev/mapper/docker-253:2-425882-7770c8b24eb3d5cc159a065910076938910d307ab2f5d94e1dc3b24c06ee2c8a rw,seclabel,discard,stripe=16,data=ordered -227 35 253:30 / /var/lib/docker/devicemapper/mnt/c280cd3d0bf0aa36b478b292279671624cceafc1a67eaa920fa1082601297adf rw,relatime shared:209 - ext4 /dev/mapper/docker-253:2-425882-c280cd3d0bf0aa36b478b292279671624cceafc1a67eaa920fa1082601297adf rw,seclabel,discard,stripe=16,data=ordered -231 35 253:31 / /var/lib/docker/devicemapper/mnt/8b59a7d9340279f09fea67fd6ad89ddef711e9e7050eb647984f8b5ef006335f rw,relatime shared:213 - ext4 /dev/mapper/docker-253:2-425882-8b59a7d9340279f09fea67fd6ad89ddef711e9e7050eb647984f8b5ef006335f rw,seclabel,discard,stripe=16,data=ordered -235 35 253:32 / /var/lib/docker/devicemapper/mnt/1a28059f29eda821578b1bb27a60cc71f76f846a551abefabce6efd0146dce9f rw,relatime shared:217 - ext4 /dev/mapper/docker-253:2-425882-1a28059f29eda821578b1bb27a60cc71f76f846a551abefabce6efd0146dce9f rw,seclabel,discard,stripe=16,data=ordered -239 35 253:33 / /var/lib/docker/devicemapper/mnt/e9aa60c60128cad1 rw,relatime shared:221 - ext4 /dev/mapper/docker-253:2-425882-e9aa60c60128cad1 rw,seclabel,discard,stripe=16,data=ordered -243 35 253:34 / /var/lib/docker/devicemapper/mnt/5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d-init rw,relatime shared:225 - ext4 /dev/mapper/docker-253:2-425882-5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d-init rw,seclabel,discard,stripe=16,data=ordered -247 35 253:35 / /var/lib/docker/devicemapper/mnt/5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d rw,relatime shared:229 - ext4 /dev/mapper/docker-253:2-425882-5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d rw,seclabel,discard,stripe=16,data=ordered -31 21 0:23 / /DATA/foo_bla_bla rw,relatime - cifs //foo/BLA\040BLA\040BLA/ rw,sec=ntlm,cache=loose,unc=\\foo\BLA BLA BLA,username=my_login,domain=mydomain.com,uid=12345678,forceuid,gid=12345678,forcegid,addr=10.1.30.10,file_mode=0755,dir_mode=0755,nounix,rsize=61440,wsize=65536,actimeo=1` - -func TestGetCgroupMounts(t *testing.T) { - subsystems := map[string]bool{ - "cpuset": true, - "cpu": true, - "cpuacct": true, - "memory": true, - "devices": true, - "freezer": true, - "net_cls": true, - "blkio": true, - "perf_event": true, - "hugetlb": true, - } - mi := bytes.NewBufferString(fedoraMountinfo) - cgMounts, err := getCgroupMountsHelper(subsystems, mi) - if err != nil { - t.Fatal(err) - } - cgMap := make(map[string]Mount) - for _, m := range cgMounts { - for _, ss := range m.Subsystems { - cgMap[ss] = m - } - } - for ss := range subsystems { - m, ok := cgMap[ss] - if !ok { - t.Fatalf("%s not found", ss) - } - if m.Root != "/" { - t.Fatalf("unexpected root for %s: %s", ss, m.Root) - } - if !strings.HasPrefix(m.Mountpoint, "/sys/fs/cgroup/") && !strings.Contains(m.Mountpoint, ss) { - t.Fatalf("unexpected mountpoint for %s: %s", ss, m.Mountpoint) - } - var ssFound bool - for _, mss := range m.Subsystems { - if mss == ss { - ssFound = true - break - } - } - if !ssFound { - t.Fatalf("subsystem %s not found in Subsystems field %v", ss, m.Subsystems) - } - } -} - -func BenchmarkGetCgroupMounts(b *testing.B) { - subsystems := map[string]bool{ - "cpuset": true, - "cpu": true, - "cpuacct": true, - "memory": true, - "devices": true, - "freezer": true, - "net_cls": true, - "blkio": true, - "perf_event": true, - "hugetlb": true, - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - b.StopTimer() - mi := bytes.NewBufferString(fedoraMountinfo) - b.StartTimer() - if _, err := getCgroupMountsHelper(subsystems, mi); err != nil { - b.Fatal(err) - } - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/configs/cgroup_unix.go b/vendor/src/github.com/opencontainers/runc/libcontainer/configs/cgroup_unix.go index 40a033f..2ea0065 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/configs/cgroup_unix.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/configs/cgroup_unix.go @@ -111,7 +111,7 @@ type Resources struct { OomKillDisable bool `json:"oom_kill_disable"` // Tuning swappiness behaviour per cgroup - MemorySwappiness int64 `json:"memory_swappiness"` + MemorySwappiness *int64 `json:"memory_swappiness"` // Set priority of network traffic for container NetPrioIfpriomap []*IfPrioMap `json:"net_prio_ifpriomap"` diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/configs/config.go b/vendor/src/github.com/opencontainers/runc/libcontainer/configs/config.go index 069daae..668fa5e 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/configs/config.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/configs/config.go @@ -128,11 +128,11 @@ type Config struct { // AppArmorProfile specifies the profile to apply to the process running in the container and is // change at the time the process is execed - AppArmorProfile string `json:"apparmor_profile"` + AppArmorProfile string `json:"apparmor_profile,omitempty"` // ProcessLabel specifies the label to apply to the process running in the container. It is // commonly used by selinux - ProcessLabel string `json:"process_label"` + ProcessLabel string `json:"process_label,omitempty"` // Rlimits specifies the resource limits, such as max open files, to set in the container // If Rlimits are not set, the container will inherit rlimits from the parent process @@ -171,12 +171,18 @@ type Config struct { // A default action to be taken if no rules match is also given. Seccomp *Seccomp `json:"seccomp"` + // NoNewPrivileges controls whether processes in the container can gain additional privileges. + NoNewPrivileges bool `json:"no_new_privileges,omitempty"` + // Hooks are a collection of actions to perform at various container lifecycle events. // Hooks are not able to be marshaled to json but they are also not needed to. Hooks *Hooks `json:"-"` // Version is the version of opencontainer specification that is supported. Version string `json:"version"` + + // Labels are user defined metadata that is stored in the config and populated on the state + Labels []string `json:"labels"` } type Hooks struct { diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/configs/config_unix_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/configs/config_unix_test.go deleted file mode 100644 index 27d07d4..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/configs/config_unix_test.go +++ /dev/null @@ -1,156 +0,0 @@ -// +build linux freebsd - -package configs - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - "testing" -) - -// Checks whether the expected capability is specified in the capabilities. -func contains(expected string, values []string) bool { - for _, v := range values { - if v == expected { - return true - } - } - return false -} - -func containsDevice(expected *Device, values []*Device) bool { - for _, d := range values { - if d.Path == expected.Path && - d.Permissions == expected.Permissions && - d.FileMode == expected.FileMode && - d.Major == expected.Major && - d.Minor == expected.Minor && - d.Type == expected.Type { - return true - } - } - return false -} - -func loadConfig(name string) (*Config, error) { - f, err := os.Open(filepath.Join("../sample_configs", name)) - if err != nil { - return nil, err - } - defer f.Close() - - var container *Config - if err := json.NewDecoder(f).Decode(&container); err != nil { - return nil, err - } - - // Check that a config doesn't contain extra fields - var configMap, abstractMap map[string]interface{} - - if _, err := f.Seek(0, 0); err != nil { - return nil, err - } - - if err := json.NewDecoder(f).Decode(&abstractMap); err != nil { - return nil, err - } - - configData, err := json.Marshal(&container) - if err != nil { - return nil, err - } - - if err := json.Unmarshal(configData, &configMap); err != nil { - return nil, err - } - - for k := range configMap { - delete(abstractMap, k) - } - - if len(abstractMap) != 0 { - return nil, fmt.Errorf("unknown fields: %s", abstractMap) - } - - return container, nil -} - -func TestRemoveNamespace(t *testing.T) { - ns := Namespaces{ - {Type: NEWNET}, - } - if !ns.Remove(NEWNET) { - t.Fatal("NEWNET was not removed") - } - if len(ns) != 0 { - t.Fatalf("namespaces should have 0 items but reports %d", len(ns)) - } -} - -func TestHostUIDNoUSERNS(t *testing.T) { - config := &Config{ - Namespaces: Namespaces{}, - } - uid, err := config.HostUID() - if err != nil { - t.Fatal(err) - } - if uid != 0 { - t.Fatalf("expected uid 0 with no USERNS but received %d", uid) - } -} - -func TestHostUIDWithUSERNS(t *testing.T) { - config := &Config{ - Namespaces: Namespaces{{Type: NEWUSER}}, - UidMappings: []IDMap{ - { - ContainerID: 0, - HostID: 1000, - Size: 1, - }, - }, - } - uid, err := config.HostUID() - if err != nil { - t.Fatal(err) - } - if uid != 1000 { - t.Fatalf("expected uid 1000 with no USERNS but received %d", uid) - } -} - -func TestHostGIDNoUSERNS(t *testing.T) { - config := &Config{ - Namespaces: Namespaces{}, - } - uid, err := config.HostGID() - if err != nil { - t.Fatal(err) - } - if uid != 0 { - t.Fatalf("expected gid 0 with no USERNS but received %d", uid) - } -} - -func TestHostGIDWithUSERNS(t *testing.T) { - config := &Config{ - Namespaces: Namespaces{{Type: NEWUSER}}, - GidMappings: []IDMap{ - { - ContainerID: 0, - HostID: 1000, - Size: 1, - }, - }, - } - uid, err := config.HostGID() - if err != nil { - t.Fatal(err) - } - if uid != 1000 { - t.Fatalf("expected gid 1000 with no USERNS but received %d", uid) - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/configs/config_windows_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/configs/config_windows_test.go deleted file mode 100644 index 1a0c8fa..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/configs/config_windows_test.go +++ /dev/null @@ -1,3 +0,0 @@ -package configs - -// All current tests are for Unix-specific functionality diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/configs/namespaces_unix.go b/vendor/src/github.com/opencontainers/runc/libcontainer/configs/namespaces_unix.go index 7bc9085..b9c820d 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/configs/namespaces_unix.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/configs/namespaces_unix.go @@ -2,7 +2,11 @@ package configs -import "fmt" +import ( + "fmt" + "os" + "sync" +) const ( NEWNET NamespaceType = "NEWNET" @@ -13,6 +17,51 @@ const ( NEWUSER NamespaceType = "NEWUSER" ) +var ( + nsLock sync.Mutex + supportedNamespaces = make(map[NamespaceType]bool) +) + +// nsToFile converts the namespace type to its filename +func nsToFile(ns NamespaceType) string { + switch ns { + case NEWNET: + return "net" + case NEWNS: + return "mnt" + case NEWPID: + return "pid" + case NEWIPC: + return "ipc" + case NEWUSER: + return "user" + case NEWUTS: + return "uts" + } + return "" +} + +// IsNamespaceSupported returns whether a namespace is available or +// not +func IsNamespaceSupported(ns NamespaceType) bool { + nsLock.Lock() + defer nsLock.Unlock() + supported, ok := supportedNamespaces[ns] + if ok { + return supported + } + nsFile := nsToFile(ns) + // if the namespace type is unknown, just return false + if nsFile == "" { + return false + } + _, err := os.Stat(fmt.Sprintf("/proc/self/ns/%s", nsFile)) + // a namespace is supported if it exists and we have permissions to read it + supported = err == nil + supportedNamespaces[ns] = supported + return supported +} + func NamespaceTypes() []NamespaceType { return []NamespaceType{ NEWNET, @@ -35,26 +84,7 @@ func (n *Namespace) GetPath(pid int) string { if n.Path != "" { return n.Path } - return fmt.Sprintf("/proc/%d/ns/%s", pid, n.file()) -} - -func (n *Namespace) file() string { - file := "" - switch n.Type { - case NEWNET: - file = "net" - case NEWNS: - file = "mnt" - case NEWPID: - file = "pid" - case NEWIPC: - file = "ipc" - case NEWUSER: - file = "user" - case NEWUTS: - file = "uts" - } - return file + return fmt.Sprintf("/proc/%d/ns/%s", pid, nsToFile(n.Type)) } func (n *Namespaces) Remove(t NamespaceType) bool { @@ -87,3 +117,11 @@ func (n *Namespaces) index(t NamespaceType) int { func (n *Namespaces) Contains(t NamespaceType) bool { return n.index(t) != -1 } + +func (n *Namespaces) PathOf(t NamespaceType) string { + i := n.index(t) + if i == -1 { + return "" + } + return (*n)[i].Path +} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/configs/validate/config.go b/vendor/src/github.com/opencontainers/runc/libcontainer/configs/validate/config.go index 848a67c..e155ca1 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/configs/validate/config.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/configs/validate/config.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "path/filepath" + "strings" "github.com/opencontainers/runc/libcontainer/configs" ) @@ -35,6 +36,9 @@ func (v *ConfigValidator) Validate(config *configs.Config) error { if err := v.usernamespace(config); err != nil { return err } + if err := v.sysctl(config); err != nil { + return err + } return nil } @@ -91,3 +95,44 @@ func (v *ConfigValidator) usernamespace(config *configs.Config) error { } return nil } + +// sysctl validates that the specified sysctl keys are valid or not. +// /proc/sys isn't completely namespaced and depending on which namespaces +// are specified, a subset of sysctls are permitted. +func (v *ConfigValidator) sysctl(config *configs.Config) error { + validSysctlPrefixes := []string{} + validSysctlMap := make(map[string]bool) + if config.Namespaces.Contains(configs.NEWNET) { + validSysctlPrefixes = append(validSysctlPrefixes, "net.") + } + if config.Namespaces.Contains(configs.NEWIPC) { + validSysctlPrefixes = append(validSysctlPrefixes, "fs.mqueue.") + validSysctlMap = map[string]bool{ + "kernel.msgmax": true, + "kernel.msgmnb": true, + "kernel.msgmni": true, + "kernel.sem": true, + "kernel.shmall": true, + "kernel.shmmax": true, + "kernel.shmmni": true, + "kernel.shm_rmid_forced": true, + } + } + for s := range config.Sysctl { + if validSysctlMap[s] { + continue + } + valid := false + for _, vp := range validSysctlPrefixes { + if strings.HasPrefix(s, vp) { + valid = true + break + } + } + if !valid { + return fmt.Errorf("sysctl %q is not permitted in the config", s) + } + } + + return nil +} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/container.go b/vendor/src/github.com/opencontainers/runc/libcontainer/container.go index 6829123..32daa97 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/container.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/container.go @@ -27,9 +27,6 @@ const ( // The container exists, but all its processes are paused. Paused - // The container exists, but its state is saved on disk - Checkpointed - // The container does not exist. Destroyed ) @@ -44,8 +41,6 @@ func (s Status) String() string { return "pausing" case Paused: return "paused" - case Checkpointed: - return "checkpointed" case Destroyed: return "destroyed" default: diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/container_linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/container_linux.go index 284e15e..8e308fa 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/container_linux.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/container_linux.go @@ -23,6 +23,7 @@ import ( "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/criurpc" "github.com/opencontainers/runc/libcontainer/utils" + "github.com/syndtr/gocapability/capability" "github.com/vishvananda/netlink/nl" ) @@ -268,37 +269,40 @@ func (c *linuxContainer) commandTemplate(p *Process, childPipe *os.File) (*exec. } func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, parentPipe, childPipe *os.File) (*initProcess, error) { - t := "_LIBCONTAINER_INITTYPE=" + string(initStandard) - cloneFlags := c.config.Namespaces.CloneFlags() - if cloneFlags&syscall.CLONE_NEWUSER != 0 { - if err := c.addUidGidMappings(cmd.SysProcAttr); err != nil { - // user mappings are not supported - return nil, err - } - enableSetgroups(cmd.SysProcAttr) - // Default to root user when user namespaces are enabled. - if cmd.SysProcAttr.Credential == nil { - cmd.SysProcAttr.Credential = &syscall.Credential{} + cmd.Env = append(cmd.Env, "_LIBCONTAINER_INITTYPE="+string(initStandard)) + nsMaps := make(map[configs.NamespaceType]string) + for _, ns := range c.config.Namespaces { + if ns.Path != "" { + nsMaps[ns.Type] = ns.Path } } - cmd.Env = append(cmd.Env, t) - cmd.SysProcAttr.Cloneflags = cloneFlags + _, sharePidns := nsMaps[configs.NEWPID] + data, err := c.bootstrapData(c.config.Namespaces.CloneFlags(), nsMaps, "") + if err != nil { + return nil, err + } return &initProcess{ - cmd: cmd, - childPipe: childPipe, - parentPipe: parentPipe, - manager: c.cgroupManager, - config: c.newInitConfig(p), - container: c, - process: p, + cmd: cmd, + childPipe: childPipe, + parentPipe: parentPipe, + manager: c.cgroupManager, + config: c.newInitConfig(p), + container: c, + process: p, + bootstrapData: data, + sharePidns: sharePidns, }, nil } func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, parentPipe, childPipe *os.File) (*setnsProcess, error) { cmd.Env = append(cmd.Env, "_LIBCONTAINER_INITTYPE="+string(initSetns)) + state, err := c.currentState() + if err != nil { + return nil, newSystemError(err) + } // for setns process, we dont have to set cloneflags as the process namespaces // will only be set via setns syscall - data, err := c.bootstrapData(0, c.initProcess.pid(), p.consolePath) + data, err := c.bootstrapData(0, state.NamespacePaths, p.consolePath) if err != nil { return nil, err } @@ -315,7 +319,7 @@ func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, parentPipe, } func (c *linuxContainer) newInitConfig(process *Process) *initConfig { - return &initConfig{ + cfg := &initConfig{ Config: c.config, Args: process.Args, Env: process.Env, @@ -324,7 +328,21 @@ func (c *linuxContainer) newInitConfig(process *Process) *initConfig { Console: process.consolePath, Capabilities: process.Capabilities, PassedFilesCount: len(process.ExtraFiles), + ContainerId: c.ID(), + NoNewPrivileges: c.config.NoNewPrivileges, + AppArmorProfile: c.config.AppArmorProfile, + ProcessLabel: c.config.ProcessLabel, } + if process.NoNewPrivileges != nil { + cfg.NoNewPrivileges = *process.NoNewPrivileges + } + if process.AppArmorProfile != "" { + cfg.AppArmorProfile = process.AppArmorProfile + } + if process.Label != "" { + cfg.ProcessLabel = process.Label + } + return cfg } func newPipe() (parent *os.File, child *os.File, err error) { @@ -1059,6 +1077,9 @@ func (c *linuxContainer) currentState() (*State, error) { state.NamespacePaths[ns.Type] = ns.GetPath(pid) } for _, nsType := range configs.NamespaceTypes() { + if !configs.IsNamespaceSupported(nsType) { + continue + } if _, ok := state.NamespacePaths[nsType]; !ok { ns := configs.Namespace{Type: nsType} state.NamespacePaths[ns.Type] = ns.GetPath(pid) @@ -1068,18 +1089,69 @@ func (c *linuxContainer) currentState() (*State, error) { return state, nil } -// bootstrapData encodes the necessary data in netlink binary format as a io.Reader. -// Consumer can write the data to a bootstrap program such as one that uses -// nsenter package to bootstrap the container's init process correctly, i.e. with -// correct namespaces, uid/gid mapping etc. -func (c *linuxContainer) bootstrapData(cloneFlags uintptr, pid int, consolePath string) (io.Reader, error) { +// orderNamespacePaths sorts namespace paths into a list of paths that we +// can setns in order. +func (c *linuxContainer) orderNamespacePaths(namespaces map[configs.NamespaceType]string) ([]string, error) { + paths := []string{} + nsTypes := []configs.NamespaceType{ + configs.NEWIPC, + configs.NEWUTS, + configs.NEWNET, + configs.NEWPID, + configs.NEWNS, + } + // join userns if the init process explicitly requires NEWUSER + if c.config.Namespaces.Contains(configs.NEWUSER) { + nsTypes = append(nsTypes, configs.NEWUSER) + } + for _, nsType := range nsTypes { + if p, ok := namespaces[nsType]; ok && p != "" { + // check if the requested namespace is supported + if !configs.IsNamespaceSupported(nsType) { + return nil, newSystemError(fmt.Errorf("namespace %s is not supported", nsType)) + } + // only set to join this namespace if it exists + if _, err := os.Lstat(p); err != nil { + return nil, newSystemError(err) + } + // do not allow namespace path with comma as we use it to separate + // the namespace paths + if strings.ContainsRune(p, ',') { + return nil, newSystemError(fmt.Errorf("invalid path %s", p)) + } + paths = append(paths, p) + } + } + return paths, nil +} + +func encodeIDMapping(idMap []configs.IDMap) ([]byte, error) { + data := bytes.NewBuffer(nil) + for _, im := range idMap { + line := fmt.Sprintf("%d %d %d\n", im.ContainerID, im.HostID, im.Size) + if _, err := data.WriteString(line); err != nil { + return nil, err + } + } + return data.Bytes(), nil +} + +// bootstrapData encodes the necessary data in netlink binary format +// as a io.Reader. +// Consumer can write the data to a bootstrap program +// such as one that uses nsenter package to bootstrap the container's +// init process correctly, i.e. with correct namespaces, uid/gid +// mapping etc. +func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.NamespaceType]string, consolePath string) (io.Reader, error) { // create the netlink message r := nl.NewNetlinkRequest(int(InitMsg), 0) - // write pid + + // write cloneFlags r.AddData(&Int32msg{ - Type: PidAttr, - Value: uint32(pid), + Type: CloneFlagsAttr, + Value: uint32(cloneFlags), }) + // write console path if consolePath != "" { r.AddData(&Bytemsg{ @@ -1087,5 +1159,57 @@ func (c *linuxContainer) bootstrapData(cloneFlags uintptr, pid int, consolePath Value: []byte(consolePath), }) } + + // write custom namespace paths + if len(nsMaps) > 0 { + nsPaths, err := c.orderNamespacePaths(nsMaps) + if err != nil { + return nil, err + } + r.AddData(&Bytemsg{ + Type: NsPathsAttr, + Value: []byte(strings.Join(nsPaths, ",")), + }) + } + + // write namespace paths only when we are not joining an existing user ns + _, joinExistingUser := nsMaps[configs.NEWUSER] + if !joinExistingUser { + // write uid mappings + if len(c.config.UidMappings) > 0 { + b, err := encodeIDMapping(c.config.UidMappings) + if err != nil { + return nil, err + } + r.AddData(&Bytemsg{ + Type: UidmapAttr, + Value: b, + }) + } + + // write gid mappings + if len(c.config.GidMappings) > 0 { + b, err := encodeIDMapping(c.config.UidMappings) + if err != nil { + return nil, err + } + r.AddData(&Bytemsg{ + Type: GidmapAttr, + Value: b, + }) + // check if we have CAP_SETGID to setgroup properly + pid, err := capability.NewPid(os.Getpid()) + if err != nil { + return nil, err + } + if !pid.Get(capability.EFFECTIVE, capability.CAP_SETGID) { + r.AddData(&Boolmsg{ + Type: SetgroupAttr, + Value: true, + }) + } + } + } + return bytes.NewReader(r.Serialize()), nil } diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/container_linux_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/container_linux_test.go deleted file mode 100644 index 3af30bc..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/container_linux_test.go +++ /dev/null @@ -1,218 +0,0 @@ -// +build linux - -package libcontainer - -import ( - "fmt" - "os" - "testing" - - "github.com/opencontainers/runc/libcontainer/cgroups" - "github.com/opencontainers/runc/libcontainer/configs" -) - -type mockCgroupManager struct { - pids []int - allPids []int - stats *cgroups.Stats - paths map[string]string -} - -func (m *mockCgroupManager) GetPids() ([]int, error) { - return m.pids, nil -} - -func (m *mockCgroupManager) GetAllPids() ([]int, error) { - return m.allPids, nil -} - -func (m *mockCgroupManager) GetStats() (*cgroups.Stats, error) { - return m.stats, nil -} - -func (m *mockCgroupManager) Apply(pid int) error { - return nil -} - -func (m *mockCgroupManager) Set(container *configs.Config) error { - return nil -} - -func (m *mockCgroupManager) Destroy() error { - return nil -} - -func (m *mockCgroupManager) GetPaths() map[string]string { - return m.paths -} - -func (m *mockCgroupManager) Freeze(state configs.FreezerState) error { - return nil -} - -type mockProcess struct { - _pid int - started string -} - -func (m *mockProcess) terminate() error { - return nil -} - -func (m *mockProcess) pid() int { - return m._pid -} - -func (m *mockProcess) startTime() (string, error) { - return m.started, nil -} - -func (m *mockProcess) start() error { - return nil -} - -func (m *mockProcess) wait() (*os.ProcessState, error) { - return nil, nil -} - -func (m *mockProcess) signal(_ os.Signal) error { - return nil -} - -func (p *mockProcess) externalDescriptors() []string { - return []string{} -} - -func (p *mockProcess) setExternalDescriptors(newFds []string) { -} - -func TestGetContainerPids(t *testing.T) { - container := &linuxContainer{ - id: "myid", - config: &configs.Config{}, - cgroupManager: &mockCgroupManager{allPids: []int{1, 2, 3}}, - } - pids, err := container.Processes() - if err != nil { - t.Fatal(err) - } - for i, expected := range []int{1, 2, 3} { - if pids[i] != expected { - t.Fatalf("expected pid %d but received %d", expected, pids[i]) - } - } -} - -func TestGetContainerStats(t *testing.T) { - container := &linuxContainer{ - id: "myid", - config: &configs.Config{}, - cgroupManager: &mockCgroupManager{ - pids: []int{1, 2, 3}, - stats: &cgroups.Stats{ - MemoryStats: cgroups.MemoryStats{ - Usage: cgroups.MemoryData{ - Usage: 1024, - }, - }, - }, - }, - } - stats, err := container.Stats() - if err != nil { - t.Fatal(err) - } - if stats.CgroupStats == nil { - t.Fatal("cgroup stats are nil") - } - if stats.CgroupStats.MemoryStats.Usage.Usage != 1024 { - t.Fatalf("expected memory usage 1024 but recevied %d", stats.CgroupStats.MemoryStats.Usage.Usage) - } -} - -func TestGetContainerState(t *testing.T) { - var ( - pid = os.Getpid() - expectedMemoryPath = "/sys/fs/cgroup/memory/myid" - expectedNetworkPath = "/networks/fd" - ) - container := &linuxContainer{ - id: "myid", - config: &configs.Config{ - Namespaces: []configs.Namespace{ - {Type: configs.NEWPID}, - {Type: configs.NEWNS}, - {Type: configs.NEWNET, Path: expectedNetworkPath}, - {Type: configs.NEWUTS}, - // emulate host for IPC - //{Type: configs.NEWIPC}, - }, - }, - initProcess: &mockProcess{ - _pid: pid, - started: "010", - }, - cgroupManager: &mockCgroupManager{ - pids: []int{1, 2, 3}, - stats: &cgroups.Stats{ - MemoryStats: cgroups.MemoryStats{ - Usage: cgroups.MemoryData{ - Usage: 1024, - }, - }, - }, - paths: map[string]string{ - "memory": expectedMemoryPath, - }, - }, - } - container.state = &createdState{c: container} - state, err := container.State() - if err != nil { - t.Fatal(err) - } - if state.InitProcessPid != pid { - t.Fatalf("expected pid %d but received %d", pid, state.InitProcessPid) - } - if state.InitProcessStartTime != "010" { - t.Fatalf("expected process start time 010 but received %s", state.InitProcessStartTime) - } - paths := state.CgroupPaths - if paths == nil { - t.Fatal("cgroup paths should not be nil") - } - if memPath := paths["memory"]; memPath != expectedMemoryPath { - t.Fatalf("expected memory path %q but received %q", expectedMemoryPath, memPath) - } - for _, ns := range container.config.Namespaces { - path := state.NamespacePaths[ns.Type] - if path == "" { - t.Fatalf("expected non nil namespace path for %s", ns.Type) - } - if ns.Type == configs.NEWNET { - if path != expectedNetworkPath { - t.Fatalf("expected path %q but received %q", expectedNetworkPath, path) - } - } else { - file := "" - switch ns.Type { - case configs.NEWNET: - file = "net" - case configs.NEWNS: - file = "mnt" - case configs.NEWPID: - file = "pid" - case configs.NEWIPC: - file = "ipc" - case configs.NEWUSER: - file = "user" - case configs.NEWUTS: - file = "uts" - } - expected := fmt.Sprintf("/proc/%d/ns/%s", pid, file) - if expected != path { - t.Fatalf("expected path %q but received %q", expected, path) - } - } - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/container_nouserns_linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/container_nouserns_linux.go deleted file mode 100644 index 3b75d59..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/container_nouserns_linux.go +++ /dev/null @@ -1,13 +0,0 @@ -// +build !go1.4 - -package libcontainer - -import ( - "fmt" - "syscall" -) - -// not available before go 1.4 -func (c *linuxContainer) addUidGidMappings(sys *syscall.SysProcAttr) error { - return fmt.Errorf("User namespace is not supported in golang < 1.4") -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/container_userns_linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/container_userns_linux.go deleted file mode 100644 index 5f4cf3c..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/container_userns_linux.go +++ /dev/null @@ -1,26 +0,0 @@ -// +build go1.4 - -package libcontainer - -import "syscall" - -// Converts IDMap to SysProcIDMap array and adds it to SysProcAttr. -func (c *linuxContainer) addUidGidMappings(sys *syscall.SysProcAttr) error { - if c.config.UidMappings != nil { - sys.UidMappings = make([]syscall.SysProcIDMap, len(c.config.UidMappings)) - for i, um := range c.config.UidMappings { - sys.UidMappings[i].ContainerID = um.ContainerID - sys.UidMappings[i].HostID = um.HostID - sys.UidMappings[i].Size = um.Size - } - } - if c.config.GidMappings != nil { - sys.GidMappings = make([]syscall.SysProcIDMap, len(c.config.GidMappings)) - for i, gm := range c.config.GidMappings { - sys.GidMappings[i].ContainerID = gm.ContainerID - sys.GidMappings[i].HostID = gm.HostID - sys.GidMappings[i].Size = gm.Size - } - } - return nil -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/devices/devices_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/devices/devices_test.go deleted file mode 100644 index 50ea78b..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/devices/devices_test.go +++ /dev/null @@ -1,63 +0,0 @@ -// +build linux freebsd - -package devices - -import ( - "errors" - "os" - "testing" -) - -func TestDeviceFromPathLstatFailure(t *testing.T) { - testError := errors.New("test error") - - // Override os.Lstat to inject error. - osLstat = func(path string) (os.FileInfo, error) { - return nil, testError - } - - _, err := DeviceFromPath("", "") - if err != testError { - t.Fatalf("Unexpected error %v, expected %v", err, testError) - } -} - -func TestHostDevicesIoutilReadDirFailure(t *testing.T) { - testError := errors.New("test error") - - // Override ioutil.ReadDir to inject error. - ioutilReadDir = func(dirname string) ([]os.FileInfo, error) { - return nil, testError - } - - _, err := HostDevices() - if err != testError { - t.Fatalf("Unexpected error %v, expected %v", err, testError) - } -} - -func TestHostDevicesIoutilReadDirDeepFailure(t *testing.T) { - testError := errors.New("test error") - called := false - - // Override ioutil.ReadDir to inject error after the first call. - ioutilReadDir = func(dirname string) ([]os.FileInfo, error) { - if called { - return nil, testError - } - called = true - - // Provoke a second call. - fi, err := os.Lstat("/tmp") - if err != nil { - t.Fatalf("Unexpected error %v", err) - } - - return []os.FileInfo{fi}, nil - } - - _, err := HostDevices() - if err != testError { - t.Fatalf("Unexpected error %v, expected %v", err, testError) - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/devices/devices_unix.go b/vendor/src/github.com/opencontainers/runc/libcontainer/devices/devices_unix.go deleted file mode 100644 index c02b73e..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/devices/devices_unix.go +++ /dev/null @@ -1,102 +0,0 @@ -// +build linux freebsd - -package devices - -import ( - "errors" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "syscall" - - "github.com/opencontainers/runc/libcontainer/configs" -) - -var ( - ErrNotADevice = errors.New("not a device node") -) - -// Testing dependencies -var ( - osLstat = os.Lstat - ioutilReadDir = ioutil.ReadDir -) - -// Given the path to a device and it's cgroup_permissions(which cannot be easily queried) look up the information about a linux device and return that information as a Device struct. -func DeviceFromPath(path, permissions string) (*configs.Device, error) { - fileInfo, err := osLstat(path) - if err != nil { - return nil, err - } - var ( - devType rune - mode = fileInfo.Mode() - fileModePermissionBits = os.FileMode.Perm(mode) - ) - switch { - case mode&os.ModeDevice == 0: - return nil, ErrNotADevice - case mode&os.ModeCharDevice != 0: - fileModePermissionBits |= syscall.S_IFCHR - devType = 'c' - default: - fileModePermissionBits |= syscall.S_IFBLK - devType = 'b' - } - stat_t, ok := fileInfo.Sys().(*syscall.Stat_t) - if !ok { - return nil, fmt.Errorf("cannot determine the device number for device %s", path) - } - devNumber := int(stat_t.Rdev) - return &configs.Device{ - Type: devType, - Path: path, - Major: Major(devNumber), - Minor: Minor(devNumber), - Permissions: permissions, - FileMode: fileModePermissionBits, - Uid: stat_t.Uid, - Gid: stat_t.Gid, - }, nil -} - -func HostDevices() ([]*configs.Device, error) { - return getDevices("/dev") -} - -func getDevices(path string) ([]*configs.Device, error) { - files, err := ioutilReadDir(path) - if err != nil { - return nil, err - } - out := []*configs.Device{} - for _, f := range files { - switch { - case f.IsDir(): - switch f.Name() { - case "pts", "shm", "fd", "mqueue": - continue - default: - sub, err := getDevices(filepath.Join(path, f.Name())) - if err != nil { - return nil, err - } - - out = append(out, sub...) - continue - } - case f.Name() == "console": - continue - } - device, err := DeviceFromPath(filepath.Join(path, f.Name()), "rwm") - if err != nil { - if err == ErrNotADevice { - continue - } - return nil, err - } - out = append(out, device) - } - return out, nil -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/devices/devices_unsupported.go b/vendor/src/github.com/opencontainers/runc/libcontainer/devices/devices_unsupported.go deleted file mode 100644 index 1e84033..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/devices/devices_unsupported.go +++ /dev/null @@ -1,3 +0,0 @@ -// +build windows - -package devices diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/devices/number.go b/vendor/src/github.com/opencontainers/runc/libcontainer/devices/number.go deleted file mode 100644 index 885b6e5..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/devices/number.go +++ /dev/null @@ -1,24 +0,0 @@ -// +build linux freebsd - -package devices - -/* - -This code provides support for manipulating linux device numbers. It should be replaced by normal syscall functions once http://code.google.com/p/go/issues/detail?id=8106 is solved. - -You can read what they are here: - - - http://www.makelinux.net/ldd3/chp-3-sect-2 - - http://www.linux-tutorial.info/modules.php?name=MContent&pageid=94 - -Note! These are NOT the same as the MAJOR(dev_t device);, MINOR(dev_t device); and MKDEV(int major, int minor); functions as defined in as the representation of device numbers used by go is different than the one used internally to the kernel! - https://github.com/torvalds/linux/blob/master/include/linux/kdev_t.h#L9 - -*/ - -func Major(devNumber int) int64 { - return int64((devNumber >> 8) & 0xfff) -} - -func Minor(devNumber int) int64 { - return int64((devNumber & 0xff) | ((devNumber >> 12) & 0xfff00)) -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/error_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/error_test.go deleted file mode 100644 index 4bf4c9f..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/error_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package libcontainer - -import "testing" - -func TestErrorCode(t *testing.T) { - codes := map[ErrorCode]string{ - IdInUse: "Id already in use", - InvalidIdFormat: "Invalid format", - ContainerPaused: "Container paused", - ConfigInvalid: "Invalid configuration", - SystemError: "System error", - ContainerNotExists: "Container does not exist", - } - - for code, expected := range codes { - if actual := code.String(); actual != expected { - t.Fatalf("expected string %q but received %q", expected, actual) - } - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/factory_linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/factory_linux.go index 9a282cf..eb327be 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/factory_linux.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/factory_linux.go @@ -227,36 +227,40 @@ func (l *LinuxFactory) StartInitialization() (err error) { pipe = os.NewFile(uintptr(pipefd), "pipe") it = initType(os.Getenv("_LIBCONTAINER_INITTYPE")) ) + defer pipe.Close() // 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 { + i, err := newContainerInit(it, pipe) + if err != nil { + l.sendError(nil, pipe, err) + return err + } + if err := i.Init(); err != nil { + if !isExecError(err) { + l.sendError(i, pipe, err) + } + return err + } + return nil +} + +func (l *LinuxFactory) sendError(i initer, pipe *os.File, err error) { + // We have an error during the initialization of the container's init, + // send it back to the parent process in the form of an initError. + // If container's init successed, syscall.Exec will not return, hence + // this defer function will never be called. + if i != nil { + if _, ok := i.(*linuxStandardInit); ok { + // Synchronisation only necessary for standard init. + if err := utils.WriteJSON(pipe, syncT{procError}); 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() + if err := utils.WriteJSON(pipe, newSystemError(err)); err != nil { + panic(err) + } } func (l *LinuxFactory) loadState(root string) (*State, error) { @@ -284,3 +288,8 @@ func (l *LinuxFactory) validateID(id string) error { } return nil } + +func isExecError(err error) bool { + _, ok := err.(*exec.Error) + return ok +} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/factory_linux_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/factory_linux_test.go deleted file mode 100644 index b0c0f49..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/factory_linux_test.go +++ /dev/null @@ -1,183 +0,0 @@ -// +build linux - -package libcontainer - -import ( - "io/ioutil" - "os" - "path/filepath" - "syscall" - "testing" - - "github.com/docker/docker/pkg/mount" - "github.com/opencontainers/runc/libcontainer/configs" - "github.com/opencontainers/runc/libcontainer/utils" -) - -func newTestRoot() (string, error) { - dir, err := ioutil.TempDir("", "libcontainer") - if err != nil { - return "", err - } - return dir, nil -} - -func TestFactoryNew(t *testing.T) { - root, rerr := newTestRoot() - if rerr != nil { - t.Fatal(rerr) - } - defer os.RemoveAll(root) - 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) - 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 factory.Type() != "libcontainer" { - t.Fatalf("unexpected factory type: %q, expected %q", factory.Type(), "libcontainer") - } -} - -func TestFactoryNewTmpfs(t *testing.T) { - root, rerr := newTestRoot() - if rerr != nil { - t.Fatal(rerr) - } - defer os.RemoveAll(root) - factory, err := New(root, Cgroupfs, TmpfsRoot) - if err != nil { - t.Fatal(err) - } - if factory == nil { - t.Fatal("factory should not be nil") - } - 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 factory.Type() != "libcontainer" { - t.Fatalf("unexpected factory type: %q, expected %q", factory.Type(), "libcontainer") - } - mounted, err := mount.Mounted(lfactory.Root) - if err != nil { - t.Fatal(err) - } - if !mounted { - t.Fatalf("Factory Root is not mounted") - } - mounts, err := mount.GetMounts() - if err != nil { - t.Fatal(err) - } - var found bool - for _, m := range mounts { - if m.Mountpoint == lfactory.Root { - if m.Fstype != "tmpfs" { - t.Fatalf("Fstype of root: %s, expected %s", m.Fstype, "tmpfs") - } - if m.Source != "tmpfs" { - t.Fatalf("Source of root: %s, expected %s", m.Source, "tmpfs") - } - found = true - } - } - if !found { - t.Fatalf("Factory Root is not listed in mounts list") - } - defer syscall.Unmount(root, syscall.MNT_DETACH) -} - -func TestFactoryLoadNotExists(t *testing.T) { - root, rerr := newTestRoot() - if rerr != nil { - t.Fatal(rerr) - } - defer os.RemoveAll(root) - factory, err := New(root, Cgroupfs) - if err != nil { - t.Fatal(err) - } - _, err = factory.Load("nocontainer") - if err == nil { - t.Fatal("expected nil error loading non-existing container") - } - lerr, ok := err.(Error) - if !ok { - t.Fatal("expected libcontainer error type") - } - if lerr.Code() != ContainerNotExists { - t.Fatalf("expected error code %s but received %s", ContainerNotExists, lerr.Code()) - } -} - -func TestFactoryLoadContainer(t *testing.T) { - root, err := newTestRoot() - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(root) - // setup default container config and state for mocking - var ( - id = "1" - expectedConfig = &configs.Config{ - Rootfs: "/mycontainer/root", - } - expectedState = &State{ - BaseState: BaseState{ - InitProcessPid: 1024, - Config: *expectedConfig, - }, - } - ) - if err := os.Mkdir(filepath.Join(root, id), 0700); err != nil { - t.Fatal(err) - } - if err := marshal(filepath.Join(root, id, stateFilename), expectedState); err != nil { - t.Fatal(err) - } - factory, err := New(root, Cgroupfs) - if err != nil { - t.Fatal(err) - } - container, err := factory.Load(id) - if err != nil { - t.Fatal(err) - } - if container.ID() != id { - t.Fatalf("expected container id %q but received %q", id, container.ID()) - } - config := container.Config() - if config.Rootfs != expectedConfig.Rootfs { - t.Fatalf("expected rootfs %q but received %q", expectedConfig.Rootfs, config.Rootfs) - } - lcontainer, ok := container.(*linuxContainer) - if !ok { - t.Fatal("expected linux container on linux based systems") - } - if lcontainer.initProcess.pid() != expectedState.InitProcessPid { - t.Fatalf("expected init pid %d but received %d", expectedState.InitProcessPid, lcontainer.initProcess.pid()) - } -} - -func marshal(path string, v interface{}) error { - f, err := os.Create(path) - if err != nil { - return err - } - defer f.Close() - return utils.WriteJSON(f, v) -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/generic_error.go b/vendor/src/github.com/opencontainers/runc/libcontainer/generic_error.go index 924d637..93bb757 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/generic_error.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/generic_error.go @@ -14,8 +14,9 @@ type syncType uint8 const ( procReady syncType = iota procError - procStart procRun + procHooks + procResume ) type syncT struct { diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/generic_error_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/generic_error_test.go deleted file mode 100644 index 292d2a3..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/generic_error_test.go +++ /dev/null @@ -1,14 +0,0 @@ -package libcontainer - -import ( - "fmt" - "io/ioutil" - "testing" -) - -func TestErrorDetail(t *testing.T) { - err := newGenericError(fmt.Errorf("test error"), SystemError) - if derr := err.Detail(ioutil.Discard); derr != nil { - t.Fatal(derr) - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/init_linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/init_linux.go index 918f103..8a61516 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/init_linux.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/init_linux.go @@ -48,11 +48,15 @@ type initConfig struct { Env []string `json:"env"` Cwd string `json:"cwd"` Capabilities []string `json:"capabilities"` + ProcessLabel string `json:"process_label"` + AppArmorProfile string `json:"apparmor_profile"` + NoNewPrivileges bool `json:"no_new_privileges"` User string `json:"user"` Config *configs.Config `json:"config"` Console string `json:"console"` Networks []*network `json:"network"` PassedFilesCount int `json:"passed_files_count"` + ContainerId string `json:"containerid"` } type initer interface { @@ -163,20 +167,22 @@ func syncParentReady(pipe io.ReadWriter) error { return nil } -// 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. -func joinExistingNamespaces(namespaces []configs.Namespace) error { - for _, ns := range namespaces { - if ns.Path != "" { - f, err := os.OpenFile(ns.Path, os.O_RDONLY, 0) - if err != nil { - return err - } - err = system.Setns(f.Fd(), uintptr(ns.Syscall())) - f.Close() - if err != nil { - return err - } +// syncParentHooks sends to the given pipe a JSON payload which indicates that +// the parent should execute pre-start hooks. It then waits for the parent to +// indicate that it is cleared to resume. +func syncParentHooks(pipe io.ReadWriter) error { + // Tell parent. + if err := utils.WriteJSON(pipe, syncT{procHooks}); err != nil { + return err + } + // Wait for parent to give the all-clear. + var procSync syncT + if err := json.NewDecoder(pipe).Decode(&procSync); err != nil { + if err == io.EOF { + return fmt.Errorf("parent closed synchronisation channel") + } + if procSync.Type != procResume { + return fmt.Errorf("invalid synchronisation flag from parent") } } return nil @@ -319,9 +325,10 @@ func setupRlimits(config *configs.Config) error { return nil } -func setOomScoreAdj(oomScoreAdj int) error { - path := "/proc/self/oom_score_adj" - return ioutil.WriteFile(path, []byte(strconv.Itoa(oomScoreAdj)), 0700) +func setOomScoreAdj(oomScoreAdj int, pid int) error { + path := fmt.Sprintf("/proc/%d/oom_score_adj", pid) + + return ioutil.WriteFile(path, []byte(strconv.Itoa(oomScoreAdj)), 0600) } // killCgroupProcesses freezes then iterates over all the processes inside the diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/integration/checkpoint_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/integration/checkpoint_test.go deleted file mode 100644 index a71c172..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/integration/checkpoint_test.go +++ /dev/null @@ -1,204 +0,0 @@ -package integration - -import ( - "bufio" - "bytes" - "io/ioutil" - "os" - "path/filepath" - "strings" - "syscall" - "testing" - - "github.com/opencontainers/runc/libcontainer" - "github.com/opencontainers/runc/libcontainer/configs" -) - -func showFile(t *testing.T, fname string) error { - t.Logf("=== %s ===\n", fname) - - f, err := os.Open(fname) - if err != nil { - t.Log(err) - return err - } - defer f.Close() - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - t.Log(scanner.Text()) - } - - if err := scanner.Err(); err != nil { - return err - } - - t.Logf("=== END ===\n") - - return nil -} - -func TestCheckpoint(t *testing.T) { - if testing.Short() { - return - } - root, err := newTestRoot() - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(root) - - rootfs, err := newRootfs() - if err != nil { - t.Fatal(err) - } - defer remove(rootfs) - - config := newTemplateConfig(rootfs) - - config.Mounts = append(config.Mounts, &configs.Mount{ - Destination: "/sys/fs/cgroup", - Device: "cgroup", - Flags: defaultMountFlags | syscall.MS_RDONLY, - }) - - factory, err := libcontainer.New(root, libcontainer.Cgroupfs) - - if err != nil { - t.Fatal(err) - } - - container, err := factory.Create("test", config) - if err != nil { - t.Fatal(err) - } - defer container.Destroy() - - stdinR, stdinW, err := os.Pipe() - if err != nil { - t.Fatal(err) - } - - var stdout bytes.Buffer - - pconfig := libcontainer.Process{ - Cwd: "/", - Args: []string{"cat"}, - Env: standardEnvironment, - Stdin: stdinR, - Stdout: &stdout, - } - - err = container.Start(&pconfig) - stdinR.Close() - defer stdinW.Close() - if err != nil { - t.Fatal(err) - } - - pid, err := pconfig.Pid() - if err != nil { - t.Fatal(err) - } - - process, err := os.FindProcess(pid) - if err != nil { - t.Fatal(err) - } - - imagesDir, err := ioutil.TempDir("", "criu") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(imagesDir) - - checkpointOpts := &libcontainer.CriuOpts{ - ImagesDirectory: imagesDir, - WorkDirectory: imagesDir, - } - dumpLog := filepath.Join(checkpointOpts.WorkDirectory, "dump.log") - restoreLog := filepath.Join(checkpointOpts.WorkDirectory, "restore.log") - - if err := container.Checkpoint(checkpointOpts); err != nil { - showFile(t, dumpLog) - t.Fatal(err) - } - - state, err := container.Status() - if err != nil { - t.Fatal(err) - } - - if state != libcontainer.Running { - t.Fatal("Unexpected state checkpoint: ", state) - } - - stdinW.Close() - _, err = process.Wait() - if err != nil { - t.Fatal(err) - } - - // reload the container - container, err = factory.Load("test") - if err != nil { - t.Fatal(err) - } - - restoreStdinR, restoreStdinW, err := os.Pipe() - if err != nil { - t.Fatal(err) - } - - restoreProcessConfig := &libcontainer.Process{ - Cwd: "/", - Stdin: restoreStdinR, - Stdout: &stdout, - } - - err = container.Restore(restoreProcessConfig, checkpointOpts) - restoreStdinR.Close() - defer restoreStdinW.Close() - if err != nil { - showFile(t, restoreLog) - t.Fatal(err) - } - - state, err = container.Status() - if err != nil { - t.Fatal(err) - } - if state != libcontainer.Running { - t.Fatal("Unexpected restore state: ", state) - } - - pid, err = restoreProcessConfig.Pid() - if err != nil { - t.Fatal(err) - } - - process, err = os.FindProcess(pid) - if err != nil { - t.Fatal(err) - } - - _, err = restoreStdinW.WriteString("Hello!") - if err != nil { - t.Fatal(err) - } - - restoreStdinW.Close() - s, err := process.Wait() - if err != nil { - t.Fatal(err) - } - - if !s.Success() { - t.Fatal(s.String(), pid) - } - - output := string(stdout.Bytes()) - if !strings.Contains(output, "Hello!") { - t.Fatal("Did not restore the pipe correctly:", output) - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/integration/doc.go b/vendor/src/github.com/opencontainers/runc/libcontainer/integration/doc.go deleted file mode 100644 index 87545bc..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/integration/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// integration is used for integration testing of libcontainer -package integration diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/integration/exec_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/integration/exec_test.go deleted file mode 100644 index ca8609c..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/integration/exec_test.go +++ /dev/null @@ -1,1363 +0,0 @@ -package integration - -import ( - "bytes" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "strconv" - "strings" - "syscall" - "testing" - - "github.com/opencontainers/runc/libcontainer" - "github.com/opencontainers/runc/libcontainer/cgroups/systemd" - "github.com/opencontainers/runc/libcontainer/configs" -) - -func TestExecPS(t *testing.T) { - testExecPS(t, false) -} - -func TestUsernsExecPS(t *testing.T) { - if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) { - t.Skip("userns is unsupported") - } - testExecPS(t, true) -} - -func testExecPS(t *testing.T, userns bool) { - if testing.Short() { - return - } - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - config := newTemplateConfig(rootfs) - if userns { - config.UidMappings = []configs.IDMap{{0, 0, 1000}} - config.GidMappings = []configs.IDMap{{0, 0, 1000}} - config.Namespaces = append(config.Namespaces, configs.Namespace{Type: configs.NEWUSER}) - } - - buffers, exitCode, err := runContainer(config, "", "ps") - if err != nil { - t.Fatalf("%s: %s", buffers, err) - } - if exitCode != 0 { - t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr) - } - lines := strings.Split(buffers.Stdout.String(), "\n") - if len(lines) < 2 { - t.Fatalf("more than one process running for output %q", buffers.Stdout.String()) - } - expected := `1 root ps` - actual := strings.Trim(lines[1], "\n ") - if actual != expected { - t.Fatalf("expected output %q but received %q", expected, actual) - } -} - -func TestIPCPrivate(t *testing.T) { - if testing.Short() { - return - } - - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - - l, err := os.Readlink("/proc/1/ns/ipc") - ok(t, err) - - config := newTemplateConfig(rootfs) - buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc") - ok(t, err) - - if exitCode != 0 { - t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr) - } - - if actual := strings.Trim(buffers.Stdout.String(), "\n"); actual == l { - t.Fatalf("ipc link should be private to the container but equals host %q %q", actual, l) - } -} - -func TestIPCHost(t *testing.T) { - if testing.Short() { - return - } - - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - - l, err := os.Readlink("/proc/1/ns/ipc") - ok(t, err) - - config := newTemplateConfig(rootfs) - config.Namespaces.Remove(configs.NEWIPC) - buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc") - ok(t, err) - - if exitCode != 0 { - t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr) - } - - if actual := strings.Trim(buffers.Stdout.String(), "\n"); actual != l { - t.Fatalf("ipc link not equal to host link %q %q", actual, l) - } -} - -func TestIPCJoinPath(t *testing.T) { - if testing.Short() { - return - } - - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - - l, err := os.Readlink("/proc/1/ns/ipc") - ok(t, err) - - config := newTemplateConfig(rootfs) - config.Namespaces.Add(configs.NEWIPC, "/proc/1/ns/ipc") - - buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc") - ok(t, err) - - if exitCode != 0 { - t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr) - } - - if actual := strings.Trim(buffers.Stdout.String(), "\n"); actual != l { - t.Fatalf("ipc link not equal to host link %q %q", actual, l) - } -} - -func TestIPCBadPath(t *testing.T) { - if testing.Short() { - return - } - - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - - config := newTemplateConfig(rootfs) - config.Namespaces.Add(configs.NEWIPC, "/proc/1/ns/ipcc") - - _, _, err = runContainer(config, "", "true") - if err == nil { - t.Fatal("container succeeded with bad ipc path") - } -} - -func TestRlimit(t *testing.T) { - if testing.Short() { - return - } - - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - - config := newTemplateConfig(rootfs) - out, _, err := runContainer(config, "", "/bin/sh", "-c", "ulimit -n") - ok(t, err) - if limit := strings.TrimSpace(out.Stdout.String()); limit != "1025" { - t.Fatalf("expected rlimit to be 1025, got %s", limit) - } -} - -func newTestRoot() (string, error) { - dir, err := ioutil.TempDir("", "libcontainer") - if err != nil { - return "", err - } - if err := os.MkdirAll(dir, 0700); err != nil { - return "", err - } - return dir, nil -} - -func TestEnter(t *testing.T) { - if testing.Short() { - return - } - root, err := newTestRoot() - ok(t, err) - defer os.RemoveAll(root) - - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - - config := newTemplateConfig(rootfs) - - container, err := factory.Create("test", config) - ok(t, err) - defer container.Destroy() - - // Execute a first process in the container - stdinR, stdinW, err := os.Pipe() - ok(t, err) - - var stdout, stdout2 bytes.Buffer - - pconfig := libcontainer.Process{ - Cwd: "/", - Args: []string{"sh", "-c", "cat && readlink /proc/self/ns/pid"}, - Env: standardEnvironment, - Stdin: stdinR, - Stdout: &stdout, - } - err = container.Start(&pconfig) - stdinR.Close() - defer stdinW.Close() - ok(t, err) - pid, err := pconfig.Pid() - ok(t, err) - - // Execute another process in the container - stdinR2, stdinW2, err := os.Pipe() - ok(t, err) - pconfig2 := libcontainer.Process{ - Cwd: "/", - Env: standardEnvironment, - } - pconfig2.Args = []string{"sh", "-c", "cat && readlink /proc/self/ns/pid"} - pconfig2.Stdin = stdinR2 - pconfig2.Stdout = &stdout2 - - err = container.Start(&pconfig2) - stdinR2.Close() - defer stdinW2.Close() - ok(t, err) - - pid2, err := pconfig2.Pid() - ok(t, err) - - processes, err := container.Processes() - ok(t, err) - - n := 0 - for i := range processes { - if processes[i] == pid || processes[i] == pid2 { - n++ - } - } - if n != 2 { - t.Fatal("unexpected number of processes", processes, pid, pid2) - } - - // Wait processes - stdinW2.Close() - waitProcess(&pconfig2, t) - - stdinW.Close() - waitProcess(&pconfig, t) - - // Check that both processes live in the same pidns - pidns := string(stdout.Bytes()) - ok(t, err) - - pidns2 := string(stdout2.Bytes()) - ok(t, err) - - if pidns != pidns2 { - t.Fatal("The second process isn't in the required pid namespace", pidns, pidns2) - } -} - -func TestProcessEnv(t *testing.T) { - if testing.Short() { - return - } - root, err := newTestRoot() - ok(t, err) - defer os.RemoveAll(root) - - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - - config := newTemplateConfig(rootfs) - - container, err := factory.Create("test", config) - ok(t, err) - defer container.Destroy() - - var stdout bytes.Buffer - pconfig := libcontainer.Process{ - Cwd: "/", - Args: []string{"sh", "-c", "env"}, - Env: []string{ - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - "HOSTNAME=integration", - "TERM=xterm", - "FOO=BAR", - }, - Stdin: nil, - Stdout: &stdout, - } - err = container.Start(&pconfig) - ok(t, err) - - // Wait for process - waitProcess(&pconfig, t) - - outputEnv := string(stdout.Bytes()) - - // Check that the environment has the key/value pair we added - if !strings.Contains(outputEnv, "FOO=BAR") { - t.Fatal("Environment doesn't have the expected FOO=BAR key/value pair: ", outputEnv) - } - - // Make sure that HOME is set - if !strings.Contains(outputEnv, "HOME=/root") { - t.Fatal("Environment doesn't have HOME set: ", outputEnv) - } -} - -func TestProcessCaps(t *testing.T) { - if testing.Short() { - return - } - root, err := newTestRoot() - ok(t, err) - defer os.RemoveAll(root) - - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - - config := newTemplateConfig(rootfs) - - container, err := factory.Create("test", config) - ok(t, err) - defer container.Destroy() - - processCaps := append(config.Capabilities, "CAP_NET_ADMIN") - - var stdout bytes.Buffer - pconfig := libcontainer.Process{ - Cwd: "/", - Args: []string{"sh", "-c", "cat /proc/self/status"}, - Env: standardEnvironment, - Capabilities: processCaps, - Stdin: nil, - Stdout: &stdout, - } - err = container.Start(&pconfig) - ok(t, err) - - // Wait for process - waitProcess(&pconfig, t) - - outputStatus := string(stdout.Bytes()) - - lines := strings.Split(outputStatus, "\n") - - effectiveCapsLine := "" - for _, l := range lines { - line := strings.TrimSpace(l) - if strings.Contains(line, "CapEff:") { - effectiveCapsLine = line - break - } - } - - if effectiveCapsLine == "" { - t.Fatal("Couldn't find effective caps: ", outputStatus) - } - - parts := strings.Split(effectiveCapsLine, ":") - effectiveCapsStr := strings.TrimSpace(parts[1]) - - effectiveCaps, err := strconv.ParseUint(effectiveCapsStr, 16, 64) - if err != nil { - t.Fatal("Could not parse effective caps", err) - } - - var netAdminMask uint64 - var netAdminBit uint - netAdminBit = 12 // from capability.h - netAdminMask = 1 << netAdminBit - if effectiveCaps&netAdminMask != netAdminMask { - t.Fatal("CAP_NET_ADMIN is not set as expected") - } -} - -func TestAdditionalGroups(t *testing.T) { - if testing.Short() { - return - } - root, err := newTestRoot() - ok(t, err) - defer os.RemoveAll(root) - - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - - config := newTemplateConfig(rootfs) - config.AdditionalGroups = []string{"plugdev", "audio"} - - factory, err := libcontainer.New(root, libcontainer.Cgroupfs) - ok(t, err) - - container, err := factory.Create("test", config) - ok(t, err) - defer container.Destroy() - - var stdout bytes.Buffer - pconfig := libcontainer.Process{ - Cwd: "/", - Args: []string{"sh", "-c", "id", "-Gn"}, - Env: standardEnvironment, - Stdin: nil, - Stdout: &stdout, - } - err = container.Start(&pconfig) - ok(t, err) - - // Wait for process - waitProcess(&pconfig, t) - - outputGroups := string(stdout.Bytes()) - - // Check that the groups output has the groups that we specified - if !strings.Contains(outputGroups, "audio") { - t.Fatalf("Listed groups do not contain the audio group as expected: %v", outputGroups) - } - - if !strings.Contains(outputGroups, "plugdev") { - t.Fatalf("Listed groups do not contain the plugdev group as expected: %v", outputGroups) - } -} - -func TestFreeze(t *testing.T) { - testFreeze(t, false) -} - -func TestSystemdFreeze(t *testing.T) { - if !systemd.UseSystemd() { - t.Skip("Systemd is unsupported") - } - testFreeze(t, true) -} - -func testFreeze(t *testing.T, systemd bool) { - if testing.Short() { - return - } - root, err := newTestRoot() - ok(t, err) - defer os.RemoveAll(root) - - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - - config := newTemplateConfig(rootfs) - f := factory - if systemd { - f = systemdFactory - } - - container, err := f.Create("test", config) - ok(t, err) - defer container.Destroy() - - stdinR, stdinW, err := os.Pipe() - ok(t, err) - - pconfig := &libcontainer.Process{ - Cwd: "/", - Args: []string{"cat"}, - Env: standardEnvironment, - Stdin: stdinR, - } - err = container.Start(pconfig) - stdinR.Close() - defer stdinW.Close() - ok(t, err) - - err = container.Pause() - ok(t, err) - state, err := container.Status() - ok(t, err) - err = container.Resume() - ok(t, err) - if state != libcontainer.Paused { - t.Fatal("Unexpected state: ", state) - } - - stdinW.Close() - waitProcess(pconfig, t) -} - -func TestCpuShares(t *testing.T) { - testCpuShares(t, false) -} - -func TestCpuSharesSystemd(t *testing.T) { - if !systemd.UseSystemd() { - t.Skip("Systemd is unsupported") - } - testCpuShares(t, true) -} - -func testCpuShares(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.CpuShares = 1 - - _, _, err = runContainer(config, "", "ps") - if err == nil { - t.Fatalf("runContainer should failed with invalid CpuShares") - } -} - -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 + 6 * true + 3). - config.Cgroups.Resources.PidsLimit = 10 - _, ret, err = runContainer(config, "", "/bin/sh", "-c", "/bin/true | /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") - } - ok(t, err) - - if ret != 0 { - t.Fatalf("expected fork() to succeed with permissive pids limit") - } - - // Enforce a restrictive limit (shell + 6 * true + 3). - config.Cgroups.Resources.PidsLimit = 10 - out, ret, err := runContainer(config, "", "/bin/sh", "-c", "/bin/true | /bin/true | /bin/true | /bin/true | /bin/true | /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") - } - - // Minimal restrictions are not really supported, due to quirks in using Go - // due to the fact that it spawns random processes. While we do our best with - // late setting cgroup values, it's just too unreliable with very small pids.max. - // As such, we don't test that case. YMMV. -} - -func TestRunWithKernelMemory(t *testing.T) { - testRunWithKernelMemory(t, false) -} - -func TestRunWithKernelMemorySystemd(t *testing.T) { - if !systemd.UseSystemd() { - t.Skip("Systemd is unsupported") - } - testRunWithKernelMemory(t, true) -} - -func testRunWithKernelMemory(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.KernelMemory = 52428800 - - _, _, err = runContainer(config, "", "ps") - if err != nil { - t.Fatalf("runContainer failed with kernel memory limit: %v", err) - } -} - -func TestContainerState(t *testing.T) { - if testing.Short() { - return - } - root, err := newTestRoot() - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(root) - - rootfs, err := newRootfs() - if err != nil { - t.Fatal(err) - } - defer remove(rootfs) - - l, err := os.Readlink("/proc/1/ns/ipc") - if err != nil { - t.Fatal(err) - } - - config := newTemplateConfig(rootfs) - config.Namespaces = configs.Namespaces([]configs.Namespace{ - {Type: configs.NEWNS}, - {Type: configs.NEWUTS}, - // host for IPC - //{Type: configs.NEWIPC}, - {Type: configs.NEWPID}, - {Type: configs.NEWNET}, - }) - - container, err := factory.Create("test", config) - if err != nil { - t.Fatal(err) - } - defer container.Destroy() - - stdinR, stdinW, err := os.Pipe() - if err != nil { - t.Fatal(err) - } - p := &libcontainer.Process{ - Cwd: "/", - Args: []string{"cat"}, - Env: standardEnvironment, - Stdin: stdinR, - } - err = container.Start(p) - if err != nil { - t.Fatal(err) - } - stdinR.Close() - defer stdinW.Close() - - st, err := container.State() - if err != nil { - t.Fatal(err) - } - - l1, err := os.Readlink(st.NamespacePaths[configs.NEWIPC]) - if err != nil { - t.Fatal(err) - } - if l1 != l { - t.Fatal("Container using non-host ipc namespace") - } - stdinW.Close() - waitProcess(p, t) -} - -func TestPassExtraFiles(t *testing.T) { - if testing.Short() { - return - } - - rootfs, err := newRootfs() - if err != nil { - t.Fatal(err) - } - defer remove(rootfs) - - config := newTemplateConfig(rootfs) - - container, err := factory.Create("test", config) - if err != nil { - t.Fatal(err) - } - defer container.Destroy() - - var stdout bytes.Buffer - pipeout1, pipein1, err := os.Pipe() - pipeout2, pipein2, err := os.Pipe() - process := libcontainer.Process{ - Cwd: "/", - Args: []string{"sh", "-c", "cd /proc/$$/fd; echo -n *; echo -n 1 >3; echo -n 2 >4"}, - Env: []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"}, - ExtraFiles: []*os.File{pipein1, pipein2}, - Stdin: nil, - Stdout: &stdout, - } - err = container.Start(&process) - if err != nil { - t.Fatal(err) - } - - waitProcess(&process, t) - - out := string(stdout.Bytes()) - // fd 5 is the directory handle for /proc/$$/fd - if out != "0 1 2 3 4 5" { - t.Fatalf("expected to have the file descriptors '0 1 2 3 4 5' passed to init, got '%s'", out) - } - var buf = []byte{0} - _, err = pipeout1.Read(buf) - if err != nil { - t.Fatal(err) - } - out1 := string(buf) - if out1 != "1" { - t.Fatalf("expected first pipe to receive '1', got '%s'", out1) - } - - _, err = pipeout2.Read(buf) - if err != nil { - t.Fatal(err) - } - out2 := string(buf) - if out2 != "2" { - t.Fatalf("expected second pipe to receive '2', got '%s'", out2) - } -} - -func TestMountCmds(t *testing.T) { - if testing.Short() { - return - } - root, err := newTestRoot() - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(root) - - rootfs, err := newRootfs() - if err != nil { - t.Fatal(err) - } - defer remove(rootfs) - - tmpDir, err := ioutil.TempDir("", "tmpdir") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - config := newTemplateConfig(rootfs) - config.Mounts = append(config.Mounts, &configs.Mount{ - Source: tmpDir, - Destination: "/tmp", - Device: "bind", - Flags: syscall.MS_BIND | syscall.MS_REC, - PremountCmds: []configs.Command{ - {Path: "touch", Args: []string{filepath.Join(tmpDir, "hello")}}, - {Path: "touch", Args: []string{filepath.Join(tmpDir, "world")}}, - }, - PostmountCmds: []configs.Command{ - {Path: "cp", Args: []string{filepath.Join(rootfs, "tmp", "hello"), filepath.Join(rootfs, "tmp", "hello-backup")}}, - {Path: "cp", Args: []string{filepath.Join(rootfs, "tmp", "world"), filepath.Join(rootfs, "tmp", "world-backup")}}, - }, - }) - - container, err := factory.Create("test", config) - if err != nil { - t.Fatal(err) - } - defer container.Destroy() - - pconfig := libcontainer.Process{ - Cwd: "/", - Args: []string{"sh", "-c", "env"}, - Env: standardEnvironment, - } - err = container.Start(&pconfig) - if err != nil { - t.Fatal(err) - } - - // Wait for process - waitProcess(&pconfig, t) - - entries, err := ioutil.ReadDir(tmpDir) - if err != nil { - t.Fatal(err) - } - expected := []string{"hello", "hello-backup", "world", "world-backup"} - for i, e := range entries { - if e.Name() != expected[i] { - t.Errorf("Got(%s), expect %s", e.Name(), expected[i]) - } - } -} - -func TestSysctl(t *testing.T) { - if testing.Short() { - return - } - root, err := newTestRoot() - ok(t, err) - defer os.RemoveAll(root) - - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - - config := newTemplateConfig(rootfs) - config.Sysctl = map[string]string{ - "kernel.shmmni": "8192", - } - - container, err := factory.Create("test", config) - ok(t, err) - defer container.Destroy() - - var stdout bytes.Buffer - pconfig := libcontainer.Process{ - Cwd: "/", - Args: []string{"sh", "-c", "cat /proc/sys/kernel/shmmni"}, - Env: standardEnvironment, - Stdin: nil, - Stdout: &stdout, - } - err = container.Start(&pconfig) - ok(t, err) - - // Wait for process - waitProcess(&pconfig, t) - - shmmniOutput := strings.TrimSpace(string(stdout.Bytes())) - if shmmniOutput != "8192" { - t.Fatalf("kernel.shmmni property expected to be 8192, but is %s", shmmniOutput) - } -} - -func TestMountCgroupRO(t *testing.T) { - if testing.Short() { - return - } - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - config := newTemplateConfig(rootfs) - - config.Mounts = append(config.Mounts, &configs.Mount{ - Destination: "/sys/fs/cgroup", - Device: "cgroup", - Flags: defaultMountFlags | syscall.MS_RDONLY, - }) - - buffers, exitCode, err := runContainer(config, "", "mount") - if err != nil { - t.Fatalf("%s: %s", buffers, err) - } - if exitCode != 0 { - t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr) - } - mountInfo := buffers.Stdout.String() - lines := strings.Split(mountInfo, "\n") - for _, l := range lines { - if strings.HasPrefix(l, "tmpfs on /sys/fs/cgroup") { - if !strings.Contains(l, "ro") || - !strings.Contains(l, "nosuid") || - !strings.Contains(l, "nodev") || - !strings.Contains(l, "noexec") { - t.Fatalf("Mode expected to contain 'ro,nosuid,nodev,noexec': %s", l) - } - if !strings.Contains(l, "mode=755") { - t.Fatalf("Mode expected to contain 'mode=755': %s", l) - } - continue - } - if !strings.HasPrefix(l, "cgroup") { - continue - } - if !strings.Contains(l, "ro") || - !strings.Contains(l, "nosuid") || - !strings.Contains(l, "nodev") || - !strings.Contains(l, "noexec") { - t.Fatalf("Mode expected to contain 'ro,nosuid,nodev,noexec': %s", l) - } - } -} - -func TestMountCgroupRW(t *testing.T) { - if testing.Short() { - return - } - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - config := newTemplateConfig(rootfs) - - config.Mounts = append(config.Mounts, &configs.Mount{ - Destination: "/sys/fs/cgroup", - Device: "cgroup", - Flags: defaultMountFlags, - }) - - buffers, exitCode, err := runContainer(config, "", "mount") - if err != nil { - t.Fatalf("%s: %s", buffers, err) - } - if exitCode != 0 { - t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr) - } - mountInfo := buffers.Stdout.String() - lines := strings.Split(mountInfo, "\n") - for _, l := range lines { - if strings.HasPrefix(l, "tmpfs on /sys/fs/cgroup") { - if !strings.Contains(l, "rw") || - !strings.Contains(l, "nosuid") || - !strings.Contains(l, "nodev") || - !strings.Contains(l, "noexec") { - t.Fatalf("Mode expected to contain 'rw,nosuid,nodev,noexec': %s", l) - } - if !strings.Contains(l, "mode=755") { - t.Fatalf("Mode expected to contain 'mode=755': %s", l) - } - continue - } - if !strings.HasPrefix(l, "cgroup") { - continue - } - if !strings.Contains(l, "rw") || - !strings.Contains(l, "nosuid") || - !strings.Contains(l, "nodev") || - !strings.Contains(l, "noexec") { - t.Fatalf("Mode expected to contain 'rw,nosuid,nodev,noexec': %s", l) - } - } -} - -func TestOomScoreAdj(t *testing.T) { - if testing.Short() { - return - } - root, err := newTestRoot() - ok(t, err) - defer os.RemoveAll(root) - - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - - config := newTemplateConfig(rootfs) - config.OomScoreAdj = 200 - - factory, err := libcontainer.New(root, libcontainer.Cgroupfs) - ok(t, err) - - container, err := factory.Create("test", config) - ok(t, err) - defer container.Destroy() - - var stdout bytes.Buffer - pconfig := libcontainer.Process{ - Cwd: "/", - Args: []string{"sh", "-c", "cat /proc/self/oom_score_adj"}, - Env: standardEnvironment, - Stdin: nil, - Stdout: &stdout, - } - err = container.Start(&pconfig) - ok(t, err) - - // Wait for process - waitProcess(&pconfig, t) - outputOomScoreAdj := strings.TrimSpace(string(stdout.Bytes())) - - // Check that the oom_score_adj matches the value that was set as part of config. - if outputOomScoreAdj != strconv.Itoa(config.OomScoreAdj) { - t.Fatalf("Expected oom_score_adj %d; got %q", config.OomScoreAdj, outputOomScoreAdj) - } -} - -func TestHook(t *testing.T) { - if testing.Short() { - return - } - root, err := newTestRoot() - ok(t, err) - defer os.RemoveAll(root) - - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - - config := newTemplateConfig(rootfs) - config.Hooks = &configs.Hooks{ - Prestart: []configs.Hook{ - configs.NewFunctionHook(func(s configs.HookState) error { - f, err := os.Create(filepath.Join(s.Root, "test")) - if err != nil { - return err - } - return f.Close() - }), - }, - Poststop: []configs.Hook{ - configs.NewFunctionHook(func(s configs.HookState) error { - return os.RemoveAll(filepath.Join(s.Root, "test")) - }), - }, - } - container, err := factory.Create("test", config) - ok(t, err) - - var stdout bytes.Buffer - pconfig := libcontainer.Process{ - Cwd: "/", - Args: []string{"sh", "-c", "ls /test"}, - Env: standardEnvironment, - Stdin: nil, - Stdout: &stdout, - } - err = container.Start(&pconfig) - ok(t, err) - - // Wait for process - waitProcess(&pconfig, t) - - outputLs := string(stdout.Bytes()) - - // Check that the ls output has the expected file touched by the prestart hook - if !strings.Contains(outputLs, "/test") { - container.Destroy() - t.Fatalf("ls output doesn't have the expected file: %s", outputLs) - } - - if err := container.Destroy(); err != nil { - t.Fatalf("container destory %s", err) - } - fi, err := os.Stat(filepath.Join(rootfs, "test")) - if err == nil || !os.IsNotExist(err) { - t.Fatalf("expected file to not exist, got %s", fi.Name()) - } -} - -func TestSTDIOPermissions(t *testing.T) { - if testing.Short() { - return - } - - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - config := newTemplateConfig(rootfs) - buffers, exitCode, err := runContainer(config, "", "sh", "-c", "echo hi > /dev/stderr") - ok(t, err) - if exitCode != 0 { - t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr) - } - - if actual := strings.Trim(buffers.Stderr.String(), "\n"); actual != "hi" { - t.Fatalf("stderr should equal be equal %q %q", actual, "hi") - } -} - -func unmountOp(path string) error { - if err := syscall.Unmount(path, syscall.MNT_DETACH); err != nil { - return err - } - return nil -} - -// Launch container with rootfsPropagation in rslave mode. Also -// bind mount a volume /mnt1host at /mnt1cont at the time of launch. Now do -// another mount on host (/mnt1host/mnt2host) and this new mount should -// propagate to container (/mnt1cont/mnt2host) -func TestRootfsPropagationSlaveMount(t *testing.T) { - var mountPropagated bool - var dir1cont string - var dir2cont string - - dir1cont = "/root/mnt1cont" - - if testing.Short() { - return - } - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - config := newTemplateConfig(rootfs) - - config.RootPropagation = syscall.MS_SLAVE | syscall.MS_REC - - // Bind mount a volume - dir1host, err := ioutil.TempDir("", "mnt1host") - ok(t, err) - defer os.RemoveAll(dir1host) - - // Make this dir a "shared" mount point. This will make sure a - // slave relationship can be established in container. - err = syscall.Mount(dir1host, dir1host, "bind", syscall.MS_BIND|syscall.MS_REC, "") - ok(t, err) - err = syscall.Mount("", dir1host, "", syscall.MS_SHARED|syscall.MS_REC, "") - ok(t, err) - defer unmountOp(dir1host) - - config.Mounts = append(config.Mounts, &configs.Mount{ - Source: dir1host, - Destination: dir1cont, - Device: "bind", - Flags: syscall.MS_BIND | syscall.MS_REC}) - - // TODO: systemd specific processing - f := factory - - container, err := f.Create("testSlaveMount", config) - ok(t, err) - defer container.Destroy() - - stdinR, stdinW, err := os.Pipe() - ok(t, err) - - pconfig := &libcontainer.Process{ - Cwd: "/", - Args: []string{"cat"}, - Env: standardEnvironment, - Stdin: stdinR, - } - - err = container.Start(pconfig) - stdinR.Close() - defer stdinW.Close() - ok(t, err) - - // Create mnt1host/mnt2host and bind mount itself on top of it. This - // should be visible in container. - dir2host, err := ioutil.TempDir(dir1host, "mnt2host") - ok(t, err) - defer os.RemoveAll(dir2host) - - err = syscall.Mount(dir2host, dir2host, "bind", syscall.MS_BIND, "") - defer unmountOp(dir2host) - ok(t, err) - - // Run "cat /proc/self/mountinfo" in container and look at mount points. - var stdout2 bytes.Buffer - - stdinR2, stdinW2, err := os.Pipe() - ok(t, err) - - pconfig2 := &libcontainer.Process{ - Cwd: "/", - Args: []string{"cat", "/proc/self/mountinfo"}, - Env: standardEnvironment, - Stdin: stdinR2, - Stdout: &stdout2, - } - - err = container.Start(pconfig2) - stdinR2.Close() - defer stdinW2.Close() - ok(t, err) - - // Wait for process - stdinW2.Close() - waitProcess(pconfig2, t) - stdinW.Close() - waitProcess(pconfig, t) - - mountPropagated = false - dir2cont = filepath.Join(dir1cont, filepath.Base(dir2host)) - - propagationInfo := string(stdout2.Bytes()) - lines := strings.Split(propagationInfo, "\n") - for _, l := range lines { - linefields := strings.Split(l, " ") - if len(linefields) < 5 { - continue - } - - if linefields[4] == dir2cont { - mountPropagated = true - break - } - } - - if mountPropagated != true { - t.Fatalf("Mount on host %s did not propagate in container at %s\n", dir2host, dir2cont) - } -} - -// Launch container with rootfsPropagation 0 so no propagation flags are -// applied. Also bind mount a volume /mnt1host at /mnt1cont at the time of -// launch. Now do a mount in container (/mnt1cont/mnt2cont) and this new -// mount should propagate to host (/mnt1host/mnt2cont) - -func TestRootfsPropagationSharedMount(t *testing.T) { - var dir1cont string - var dir2cont string - - dir1cont = "/root/mnt1cont" - - if testing.Short() { - return - } - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - config := newTemplateConfig(rootfs) - config.RootPropagation = syscall.MS_PRIVATE - - // Bind mount a volume - dir1host, err := ioutil.TempDir("", "mnt1host") - ok(t, err) - defer os.RemoveAll(dir1host) - - // Make this dir a "shared" mount point. This will make sure a - // shared relationship can be established in container. - err = syscall.Mount(dir1host, dir1host, "bind", syscall.MS_BIND|syscall.MS_REC, "") - ok(t, err) - err = syscall.Mount("", dir1host, "", syscall.MS_SHARED|syscall.MS_REC, "") - ok(t, err) - defer unmountOp(dir1host) - - config.Mounts = append(config.Mounts, &configs.Mount{ - Source: dir1host, - Destination: dir1cont, - Device: "bind", - Flags: syscall.MS_BIND | syscall.MS_REC}) - - // TODO: systemd specific processing - f := factory - - container, err := f.Create("testSharedMount", config) - ok(t, err) - defer container.Destroy() - - stdinR, stdinW, err := os.Pipe() - ok(t, err) - - pconfig := &libcontainer.Process{ - Cwd: "/", - Args: []string{"cat"}, - Env: standardEnvironment, - Stdin: stdinR, - } - - err = container.Start(pconfig) - stdinR.Close() - defer stdinW.Close() - ok(t, err) - - // Create mnt1host/mnt2cont. This will become visible inside container - // at mnt1cont/mnt2cont. Bind mount itself on top of it. This - // should be visible on host now. - dir2host, err := ioutil.TempDir(dir1host, "mnt2cont") - ok(t, err) - defer os.RemoveAll(dir2host) - - dir2cont = filepath.Join(dir1cont, filepath.Base(dir2host)) - - // Mount something in container and see if it is visible on host. - var stdout2 bytes.Buffer - - stdinR2, stdinW2, err := os.Pipe() - ok(t, err) - - // Provide CAP_SYS_ADMIN - processCaps := append(config.Capabilities, "CAP_SYS_ADMIN") - - pconfig2 := &libcontainer.Process{ - Cwd: "/", - Args: []string{"mount", "--bind", dir2cont, dir2cont}, - Env: standardEnvironment, - Stdin: stdinR2, - Stdout: &stdout2, - Capabilities: processCaps, - } - - err = container.Start(pconfig2) - stdinR2.Close() - defer stdinW2.Close() - ok(t, err) - - // Wait for process - stdinW2.Close() - waitProcess(pconfig2, t) - stdinW.Close() - waitProcess(pconfig, t) - - defer unmountOp(dir2host) - - // Check if mount is visible on host or not. - out, err := exec.Command("findmnt", "-n", "-f", "-oTARGET", dir2host).CombinedOutput() - outtrim := strings.TrimSpace(string(out)) - if err != nil { - t.Logf("findmnt error %q: %q", err, outtrim) - } - - if string(outtrim) != dir2host { - t.Fatalf("Mount in container on %s did not propagate to host on %s. finmnt output=%s", dir2cont, dir2host, outtrim) - } -} - -func TestPIDHost(t *testing.T) { - if testing.Short() { - return - } - - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - - l, err := os.Readlink("/proc/1/ns/pid") - ok(t, err) - - config := newTemplateConfig(rootfs) - config.Namespaces.Remove(configs.NEWPID) - buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/pid") - ok(t, err) - - if exitCode != 0 { - t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr) - } - - if actual := strings.Trim(buffers.Stdout.String(), "\n"); actual != l { - t.Fatalf("ipc link not equal to host link %q %q", actual, l) - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/integration/execin_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/integration/execin_test.go deleted file mode 100644 index a80c958..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/integration/execin_test.go +++ /dev/null @@ -1,402 +0,0 @@ -package integration - -import ( - "bytes" - "io" - "os" - "strconv" - "strings" - "testing" - "time" - - "github.com/opencontainers/runc/libcontainer" -) - -func TestExecIn(t *testing.T) { - if testing.Short() { - return - } - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - config := newTemplateConfig(rootfs) - container, err := newContainer(config) - ok(t, err) - defer container.Destroy() - - // Execute a first process in the container - stdinR, stdinW, err := os.Pipe() - ok(t, err) - process := &libcontainer.Process{ - Cwd: "/", - Args: []string{"cat"}, - Env: standardEnvironment, - Stdin: stdinR, - } - err = container.Start(process) - stdinR.Close() - defer stdinW.Close() - ok(t, err) - - buffers := newStdBuffers() - ps := &libcontainer.Process{ - Cwd: "/", - Args: []string{"ps"}, - Env: standardEnvironment, - Stdin: buffers.Stdin, - Stdout: buffers.Stdout, - Stderr: buffers.Stderr, - } - - err = container.Start(ps) - ok(t, err) - waitProcess(ps, t) - stdinW.Close() - waitProcess(process, t) - - out := buffers.Stdout.String() - if !strings.Contains(out, "cat") || !strings.Contains(out, "ps") { - t.Fatalf("unexpected running process, output %q", out) - } -} - -func TestExecInRlimit(t *testing.T) { - if testing.Short() { - return - } - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - config := newTemplateConfig(rootfs) - container, err := newContainer(config) - ok(t, err) - defer container.Destroy() - - stdinR, stdinW, err := os.Pipe() - ok(t, err) - process := &libcontainer.Process{ - Cwd: "/", - Args: []string{"cat"}, - Env: standardEnvironment, - Stdin: stdinR, - } - err = container.Start(process) - stdinR.Close() - defer stdinW.Close() - ok(t, err) - - buffers := newStdBuffers() - ps := &libcontainer.Process{ - Cwd: "/", - Args: []string{"/bin/sh", "-c", "ulimit -n"}, - Env: standardEnvironment, - Stdin: buffers.Stdin, - Stdout: buffers.Stdout, - Stderr: buffers.Stderr, - } - err = container.Start(ps) - ok(t, err) - waitProcess(ps, t) - - stdinW.Close() - waitProcess(process, t) - - out := buffers.Stdout.String() - if limit := strings.TrimSpace(out); limit != "1025" { - t.Fatalf("expected rlimit to be 1025, got %s", limit) - } -} - -func TestExecInError(t *testing.T) { - if testing.Short() { - return - } - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - config := newTemplateConfig(rootfs) - container, err := newContainer(config) - ok(t, err) - defer container.Destroy() - - // Execute a first process in the container - stdinR, stdinW, err := os.Pipe() - ok(t, err) - process := &libcontainer.Process{ - Cwd: "/", - Args: []string{"cat"}, - Env: standardEnvironment, - Stdin: stdinR, - } - err = container.Start(process) - stdinR.Close() - defer func() { - stdinW.Close() - if _, err := process.Wait(); err != nil { - t.Log(err) - } - }() - ok(t, err) - - for i := 0; i < 42; i++ { - var out bytes.Buffer - unexistent := &libcontainer.Process{ - Cwd: "/", - Args: []string{"unexistent"}, - Env: standardEnvironment, - Stdout: &out, - } - err = container.Start(unexistent) - if err == nil { - t.Fatal("Should be an error") - } - if !strings.Contains(err.Error(), "executable file not found") { - t.Fatalf("Should be error about not found executable, got %s", err) - } - if !bytes.Contains(out.Bytes(), []byte("executable file not found")) { - t.Fatalf("executable file not found error not delivered to stdio:\n%s", out.String()) - } - } -} - -func TestExecInTTY(t *testing.T) { - if testing.Short() { - return - } - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - config := newTemplateConfig(rootfs) - container, err := newContainer(config) - ok(t, err) - defer container.Destroy() - - // Execute a first process in the container - stdinR, stdinW, err := os.Pipe() - ok(t, err) - process := &libcontainer.Process{ - Cwd: "/", - Args: []string{"cat"}, - Env: standardEnvironment, - Stdin: stdinR, - } - err = container.Start(process) - stdinR.Close() - defer stdinW.Close() - ok(t, err) - - var stdout bytes.Buffer - ps := &libcontainer.Process{ - Cwd: "/", - Args: []string{"ps"}, - Env: standardEnvironment, - } - console, err := ps.NewConsole(0) - copy := make(chan struct{}) - go func() { - io.Copy(&stdout, console) - close(copy) - }() - ok(t, err) - err = container.Start(ps) - ok(t, err) - select { - case <-time.After(5 * time.Second): - t.Fatal("Waiting for copy timed out") - case <-copy: - } - waitProcess(ps, t) - - stdinW.Close() - waitProcess(process, t) - - out := stdout.String() - if !strings.Contains(out, "cat") || !strings.Contains(string(out), "ps") { - t.Fatalf("unexpected running process, output %q", out) - } -} - -func TestExecInEnvironment(t *testing.T) { - if testing.Short() { - return - } - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - config := newTemplateConfig(rootfs) - container, err := newContainer(config) - ok(t, err) - defer container.Destroy() - - // Execute a first process in the container - stdinR, stdinW, err := os.Pipe() - ok(t, err) - process := &libcontainer.Process{ - Cwd: "/", - Args: []string{"cat"}, - Env: standardEnvironment, - Stdin: stdinR, - } - err = container.Start(process) - stdinR.Close() - defer stdinW.Close() - ok(t, err) - - buffers := newStdBuffers() - process2 := &libcontainer.Process{ - Cwd: "/", - Args: []string{"env"}, - Env: []string{ - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - "DEBUG=true", - "DEBUG=false", - "ENV=test", - }, - Stdin: buffers.Stdin, - Stdout: buffers.Stdout, - Stderr: buffers.Stderr, - } - err = container.Start(process2) - ok(t, err) - waitProcess(process2, t) - - stdinW.Close() - waitProcess(process, t) - - out := buffers.Stdout.String() - // check execin's process environment - if !strings.Contains(out, "DEBUG=false") || - !strings.Contains(out, "ENV=test") || - !strings.Contains(out, "HOME=/root") || - !strings.Contains(out, "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin") || - strings.Contains(out, "DEBUG=true") { - t.Fatalf("unexpected running process, output %q", out) - } -} - -func TestExecinPassExtraFiles(t *testing.T) { - if testing.Short() { - return - } - rootfs, err := newRootfs() - if err != nil { - t.Fatal(err) - } - defer remove(rootfs) - config := newTemplateConfig(rootfs) - container, err := newContainer(config) - if err != nil { - t.Fatal(err) - } - defer container.Destroy() - - // Execute a first process in the container - stdinR, stdinW, err := os.Pipe() - if err != nil { - t.Fatal(err) - } - process := &libcontainer.Process{ - Cwd: "/", - Args: []string{"cat"}, - Env: standardEnvironment, - Stdin: stdinR, - } - err = container.Start(process) - stdinR.Close() - defer stdinW.Close() - if err != nil { - t.Fatal(err) - } - - var stdout bytes.Buffer - pipeout1, pipein1, err := os.Pipe() - pipeout2, pipein2, err := os.Pipe() - inprocess := &libcontainer.Process{ - Cwd: "/", - Args: []string{"sh", "-c", "cd /proc/$$/fd; echo -n *; echo -n 1 >3; echo -n 2 >4"}, - Env: []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"}, - ExtraFiles: []*os.File{pipein1, pipein2}, - Stdin: nil, - Stdout: &stdout, - } - err = container.Start(inprocess) - if err != nil { - t.Fatal(err) - } - - waitProcess(inprocess, t) - stdinW.Close() - waitProcess(process, t) - - out := string(stdout.Bytes()) - // fd 5 is the directory handle for /proc/$$/fd - if out != "0 1 2 3 4 5" { - t.Fatalf("expected to have the file descriptors '0 1 2 3 4 5' passed to exec, got '%s'", out) - } - var buf = []byte{0} - _, err = pipeout1.Read(buf) - if err != nil { - t.Fatal(err) - } - out1 := string(buf) - if out1 != "1" { - t.Fatalf("expected first pipe to receive '1', got '%s'", out1) - } - - _, err = pipeout2.Read(buf) - if err != nil { - t.Fatal(err) - } - out2 := string(buf) - if out2 != "2" { - t.Fatalf("expected second pipe to receive '2', got '%s'", out2) - } -} - -func TestExecInOomScoreAdj(t *testing.T) { - if testing.Short() { - return - } - rootfs, err := newRootfs() - ok(t, err) - defer remove(rootfs) - config := newTemplateConfig(rootfs) - config.OomScoreAdj = 200 - container, err := newContainer(config) - ok(t, err) - defer container.Destroy() - - stdinR, stdinW, err := os.Pipe() - ok(t, err) - process := &libcontainer.Process{ - Cwd: "/", - Args: []string{"cat"}, - Env: standardEnvironment, - Stdin: stdinR, - } - err = container.Start(process) - stdinR.Close() - defer stdinW.Close() - ok(t, err) - - buffers := newStdBuffers() - ps := &libcontainer.Process{ - Cwd: "/", - Args: []string{"/bin/sh", "-c", "cat /proc/self/oom_score_adj"}, - Env: standardEnvironment, - Stdin: buffers.Stdin, - Stdout: buffers.Stdout, - Stderr: buffers.Stderr, - } - err = container.Start(ps) - ok(t, err) - waitProcess(ps, t) - - stdinW.Close() - waitProcess(process, t) - - out := buffers.Stdout.String() - if oomScoreAdj := strings.TrimSpace(out); oomScoreAdj != strconv.Itoa(config.OomScoreAdj) { - t.Fatalf("expected oomScoreAdj to be %d, got %s", config.OomScoreAdj, oomScoreAdj) - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/integration/init_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/integration/init_test.go deleted file mode 100644 index eaa6caf..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/integration/init_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package integration - -import ( - "os" - "runtime" - "testing" - - "github.com/Sirupsen/logrus" - "github.com/opencontainers/runc/libcontainer" - "github.com/opencontainers/runc/libcontainer/cgroups/systemd" - _ "github.com/opencontainers/runc/libcontainer/nsenter" -) - -// init runs the libcontainer initialization code because of the busybox style needs -// to work around the go runtime and the issues with forking -func init() { - if len(os.Args) < 2 || os.Args[1] != "init" { - return - } - runtime.GOMAXPROCS(1) - runtime.LockOSThread() - factory, err := libcontainer.New("") - if err != nil { - logrus.Fatalf("unable to initialize for container: %s", err) - } - if err := factory.StartInitialization(); err != nil { - logrus.Fatal(err) - } -} - -var ( - factory libcontainer.Factory - systemdFactory libcontainer.Factory -) - -func TestMain(m *testing.M) { - var ( - err error - ret int = 0 - ) - - logrus.SetOutput(os.Stderr) - logrus.SetLevel(logrus.InfoLevel) - - factory, err = libcontainer.New(".", libcontainer.Cgroupfs) - if err != nil { - logrus.Error(err) - os.Exit(1) - } - if systemd.UseSystemd() { - systemdFactory, err = libcontainer.New(".", libcontainer.SystemdCgroups) - if err != nil { - logrus.Error(err) - os.Exit(1) - } - } - - ret = m.Run() - os.Exit(ret) -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/integration/seccomp_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/integration/seccomp_test.go deleted file mode 100644 index 820773e..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/integration/seccomp_test.go +++ /dev/null @@ -1,219 +0,0 @@ -// +build linux,cgo,seccomp - -package integration - -import ( - "strings" - "syscall" - "testing" - - "github.com/opencontainers/runc/libcontainer" - "github.com/opencontainers/runc/libcontainer/configs" - libseccomp "github.com/seccomp/libseccomp-golang" -) - -func TestSeccompDenyGetcwd(t *testing.T) { - if testing.Short() { - return - } - - rootfs, err := newRootfs() - if err != nil { - t.Fatal(err) - } - defer remove(rootfs) - - config := newTemplateConfig(rootfs) - config.Seccomp = &configs.Seccomp{ - DefaultAction: configs.Allow, - Syscalls: []*configs.Syscall{ - { - Name: "getcwd", - Action: configs.Errno, - }, - }, - } - - container, err := newContainer(config) - if err != nil { - t.Fatal(err) - } - defer container.Destroy() - - buffers := newStdBuffers() - pwd := &libcontainer.Process{ - Cwd: "/", - Args: []string{"pwd"}, - Env: standardEnvironment, - Stdin: buffers.Stdin, - Stdout: buffers.Stdout, - Stderr: buffers.Stderr, - } - - err = container.Start(pwd) - if err != nil { - t.Fatal(err) - } - ps, err := pwd.Wait() - if err == nil { - t.Fatal("Expecting error (negative return code); instead exited cleanly!") - } - - var exitCode int - status := ps.Sys().(syscall.WaitStatus) - if status.Exited() { - exitCode = status.ExitStatus() - } else if status.Signaled() { - exitCode = -int(status.Signal()) - } else { - t.Fatalf("Unrecognized exit reason!") - } - - if exitCode == 0 { - t.Fatalf("Getcwd should fail with negative exit code, instead got %d!", exitCode) - } - - expected := "pwd: getcwd: Operation not permitted" - actual := strings.Trim(buffers.Stderr.String(), "\n") - if actual != expected { - t.Fatalf("Expected output %s but got %s\n", expected, actual) - } -} - -func TestSeccompPermitWriteConditional(t *testing.T) { - if testing.Short() { - return - } - - rootfs, err := newRootfs() - if err != nil { - t.Fatal(err) - } - defer remove(rootfs) - - config := newTemplateConfig(rootfs) - config.Seccomp = &configs.Seccomp{ - DefaultAction: configs.Allow, - Syscalls: []*configs.Syscall{ - { - Name: "write", - Action: configs.Errno, - Args: []*configs.Arg{ - { - Index: 0, - Value: 1, - Op: configs.GreaterThan, - }, - }, - }, - }, - } - - container, err := newContainer(config) - if err != nil { - t.Fatal(err) - } - defer container.Destroy() - - buffers := newStdBuffers() - dmesg := &libcontainer.Process{ - Cwd: "/", - Args: []string{"busybox", "ls", "/"}, - Env: standardEnvironment, - Stdin: buffers.Stdin, - Stdout: buffers.Stdout, - Stderr: buffers.Stderr, - } - - err = container.Start(dmesg) - if err != nil { - t.Fatal(err) - } - if _, err := dmesg.Wait(); err != nil { - t.Fatalf("%s: %s", err, buffers.Stderr) - } -} - -func TestSeccompDenyWriteConditional(t *testing.T) { - if testing.Short() { - return - } - - // Only test if library version is v2.2.1 or higher - // Conditional filtering will always error in v2.2.0 and lower - major, minor, micro := libseccomp.GetLibraryVersion() - if (major == 2 && minor < 2) || (major == 2 && minor == 2 && micro < 1) { - return - } - - rootfs, err := newRootfs() - if err != nil { - t.Fatal(err) - } - defer remove(rootfs) - - config := newTemplateConfig(rootfs) - config.Seccomp = &configs.Seccomp{ - DefaultAction: configs.Allow, - Syscalls: []*configs.Syscall{ - { - Name: "write", - Action: configs.Errno, - Args: []*configs.Arg{ - { - Index: 0, - Value: 1, - Op: configs.GreaterThan, - }, - }, - }, - }, - } - - container, err := newContainer(config) - if err != nil { - t.Fatal(err) - } - defer container.Destroy() - - buffers := newStdBuffers() - dmesg := &libcontainer.Process{ - Cwd: "/", - Args: []string{"busybox", "ls", "does_not_exist"}, - Env: standardEnvironment, - Stdin: buffers.Stdin, - Stdout: buffers.Stdout, - Stderr: buffers.Stderr, - } - - err = container.Start(dmesg) - if err != nil { - t.Fatal(err) - } - - ps, err := dmesg.Wait() - if err == nil { - t.Fatal("Expecting negative return, instead got 0!") - } - - var exitCode int - status := ps.Sys().(syscall.WaitStatus) - if status.Exited() { - exitCode = status.ExitStatus() - } else if status.Signaled() { - exitCode = -int(status.Signal()) - } else { - t.Fatalf("Unrecognized exit reason!") - } - - if exitCode == 0 { - t.Fatalf("Busybox should fail with negative exit code, instead got %d!", exitCode) - } - - // We're denying write to stderr, so we expect an empty buffer - expected := "" - actual := strings.Trim(buffers.Stderr.String(), "\n") - if actual != expected { - t.Fatalf("Expected output %s but got %s\n", expected, actual) - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/integration/template_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/integration/template_test.go deleted file mode 100644 index 047a5f1..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/integration/template_test.go +++ /dev/null @@ -1,120 +0,0 @@ -package integration - -import ( - "syscall" - - "github.com/opencontainers/runc/libcontainer/configs" -) - -var standardEnvironment = []string{ - "HOME=/root", - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - "HOSTNAME=integration", - "TERM=xterm", -} - -const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV - -// newTemplateConfig returns a base template for running a container -// -// it uses a network strategy of just setting a loopback interface -// and the default setup for devices -func newTemplateConfig(rootfs string) *configs.Config { - return &configs.Config{ - Rootfs: rootfs, - Capabilities: []string{ - "CAP_CHOWN", - "CAP_DAC_OVERRIDE", - "CAP_FSETID", - "CAP_FOWNER", - "CAP_MKNOD", - "CAP_NET_RAW", - "CAP_SETGID", - "CAP_SETUID", - "CAP_SETFCAP", - "CAP_SETPCAP", - "CAP_NET_BIND_SERVICE", - "CAP_SYS_CHROOT", - "CAP_KILL", - "CAP_AUDIT_WRITE", - }, - Namespaces: configs.Namespaces([]configs.Namespace{ - {Type: configs.NEWNS}, - {Type: configs.NEWUTS}, - {Type: configs.NEWIPC}, - {Type: configs.NEWPID}, - {Type: configs.NEWNET}, - }), - Cgroups: &configs.Cgroup{ - Path: "integration/test", - Resources: &configs.Resources{ - MemorySwappiness: -1, - AllowAllDevices: false, - AllowedDevices: configs.DefaultAllowedDevices, - }, - }, - MaskPaths: []string{ - "/proc/kcore", - }, - ReadonlyPaths: []string{ - "/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus", - }, - Devices: configs.DefaultAutoCreatedDevices, - Hostname: "integration", - Mounts: []*configs.Mount{ - { - Source: "proc", - Destination: "/proc", - Device: "proc", - Flags: defaultMountFlags, - }, - { - Source: "tmpfs", - Destination: "/dev", - Device: "tmpfs", - Flags: syscall.MS_NOSUID | syscall.MS_STRICTATIME, - Data: "mode=755", - }, - { - Source: "devpts", - Destination: "/dev/pts", - Device: "devpts", - Flags: syscall.MS_NOSUID | syscall.MS_NOEXEC, - Data: "newinstance,ptmxmode=0666,mode=0620,gid=5", - }, - { - Device: "tmpfs", - Source: "shm", - Destination: "/dev/shm", - Data: "mode=1777,size=65536k", - Flags: defaultMountFlags, - }, - { - Source: "mqueue", - Destination: "/dev/mqueue", - Device: "mqueue", - Flags: defaultMountFlags, - }, - { - Source: "sysfs", - Destination: "/sys", - Device: "sysfs", - Flags: defaultMountFlags | syscall.MS_RDONLY, - }, - }, - Networks: []*configs.Network{ - { - Type: "loopback", - Address: "127.0.0.1/0", - Gateway: "localhost", - }, - }, - Rlimits: []configs.Rlimit{ - { - Type: syscall.RLIMIT_NOFILE, - Hard: uint64(1025), - Soft: uint64(1025), - }, - }, - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/integration/utils_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/integration/utils_test.go deleted file mode 100644 index 3dcd0bb..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/integration/utils_test.go +++ /dev/null @@ -1,141 +0,0 @@ -package integration - -import ( - "bytes" - "fmt" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "runtime" - "strings" - "syscall" - "testing" - - "github.com/opencontainers/runc/libcontainer" - "github.com/opencontainers/runc/libcontainer/configs" -) - -func newStdBuffers() *stdBuffers { - return &stdBuffers{ - Stdin: bytes.NewBuffer(nil), - Stdout: bytes.NewBuffer(nil), - Stderr: bytes.NewBuffer(nil), - } -} - -type stdBuffers struct { - Stdin *bytes.Buffer - Stdout *bytes.Buffer - Stderr *bytes.Buffer -} - -func (b *stdBuffers) String() string { - s := []string{} - if b.Stderr != nil { - s = append(s, b.Stderr.String()) - } - if b.Stdout != nil { - s = append(s, b.Stdout.String()) - } - return strings.Join(s, "|") -} - -// ok fails the test if an err is not nil. -func ok(t testing.TB, err error) { - if err != nil { - _, file, line, _ := runtime.Caller(1) - t.Fatalf("%s:%d: unexpected error: %s\n\n", filepath.Base(file), line, err.Error()) - } -} - -func waitProcess(p *libcontainer.Process, t *testing.T) { - _, file, line, _ := runtime.Caller(1) - status, err := p.Wait() - - if err != nil { - t.Fatalf("%s:%d: unexpected error: %s\n\n", filepath.Base(file), line, err.Error()) - } - - if !status.Success() { - t.Fatalf("%s:%d: unexpected status: %s\n\n", filepath.Base(file), line, status.String()) - } -} - -// newRootfs creates a new tmp directory and copies the busybox root filesystem -func newRootfs() (string, error) { - dir, err := ioutil.TempDir("", "") - if err != nil { - return "", err - } - if err := os.MkdirAll(dir, 0700); err != nil { - return "", err - } - if err := copyBusybox(dir); err != nil { - return "", err - } - return dir, nil -} - -func remove(dir string) { - os.RemoveAll(dir) -} - -// copyBusybox copies the rootfs for a busybox container created for the test image -// into the new directory for the specific test -func copyBusybox(dest string) error { - out, err := exec.Command("sh", "-c", fmt.Sprintf("cp -R /busybox/* %s/", dest)).CombinedOutput() - if err != nil { - return fmt.Errorf("copy error %q: %q", err, out) - } - return nil -} - -func newContainer(config *configs.Config) (libcontainer.Container, error) { - f := factory - - if config.Cgroups != nil && config.Cgroups.Parent == "system.slice" { - f = systemdFactory - } - - return f.Create("testCT", config) -} - -// runContainer runs the container with the specific config and arguments -// -// buffers are returned containing the STDOUT and STDERR output for the run -// along with the exit code and any go error -func runContainer(config *configs.Config, console string, args ...string) (buffers *stdBuffers, exitCode int, err error) { - container, err := newContainer(config) - if err != nil { - return nil, -1, err - } - defer container.Destroy() - buffers = newStdBuffers() - process := &libcontainer.Process{ - Cwd: "/", - Args: args, - Env: standardEnvironment, - Stdin: buffers.Stdin, - Stdout: buffers.Stdout, - Stderr: buffers.Stderr, - } - - err = container.Start(process) - if err != nil { - return buffers, -1, err - } - ps, err := process.Wait() - if err != nil { - return buffers, -1, err - } - status := ps.Sys().(syscall.WaitStatus) - if status.Exited() { - exitCode = status.ExitStatus() - } else if status.Signaled() { - exitCode = -int(status.Signal()) - } else { - return buffers, -1, err - } - return -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/label/label_selinux_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/label/label_selinux_test.go deleted file mode 100644 index c2a19f5..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/label/label_selinux_test.go +++ /dev/null @@ -1,144 +0,0 @@ -// +build selinux,linux - -package label - -import ( - "os" - "strings" - "testing" - - "github.com/opencontainers/runc/libcontainer/selinux" -) - -func TestInit(t *testing.T) { - if selinux.SelinuxEnabled() { - var testNull []string - plabel, mlabel, err := InitLabels(testNull) - if err != nil { - t.Log("InitLabels Failed") - t.Fatal(err) - } - testDisabled := []string{"disable"} - plabel, mlabel, err = InitLabels(testDisabled) - if err != nil { - t.Log("InitLabels Disabled Failed") - t.Fatal(err) - } - if plabel != "" { - t.Log("InitLabels Disabled Failed") - t.Fatal() - } - testUser := []string{"user:user_u", "role:user_r", "type:user_t", "level:s0:c1,c15"} - plabel, mlabel, err = InitLabels(testUser) - if err != nil { - t.Log("InitLabels User Failed") - t.Fatal(err) - } - if plabel != "user_u:user_r:user_t:s0:c1,c15" || mlabel != "user_u:object_r:svirt_sandbox_file_t:s0:c1,c15" { - t.Log("InitLabels User Match Failed") - t.Log(plabel, mlabel) - t.Fatal(err) - } - - testBadData := []string{"user", "role:user_r", "type:user_t", "level:s0:c1,c15"} - plabel, mlabel, err = InitLabels(testBadData) - if err == nil { - t.Log("InitLabels Bad Failed") - t.Fatal(err) - } - } -} -func TestDuplicateLabel(t *testing.T) { - secopt := DupSecOpt("system_u:system_r:svirt_lxc_net_t:s0:c1,c2") - t.Log(secopt) - for _, opt := range secopt { - con := strings.SplitN(opt, ":", 3) - if len(con) != 3 || con[0] != "label" { - t.Errorf("Invalid DupSecOpt return value") - continue - } - if con[1] == "user" { - if con[2] != "system_u" { - t.Errorf("DupSecOpt Failed user incorrect") - } - continue - } - if con[1] == "role" { - if con[2] != "system_r" { - t.Errorf("DupSecOpt Failed role incorrect") - } - continue - } - if con[1] == "type" { - if con[2] != "svirt_lxc_net_t" { - t.Errorf("DupSecOpt Failed type incorrect") - } - continue - } - if con[1] == "level" { - if con[2] != "s0:c1,c2" { - t.Errorf("DupSecOpt Failed level incorrect") - } - continue - } - t.Errorf("DupSecOpt Failed invalid field %q", con[1]) - } - secopt = DisableSecOpt() - if secopt[0] != "label:disable" { - t.Errorf("DisableSecOpt Failed level incorrect") - } -} -func TestRelabel(t *testing.T) { - testdir := "/tmp/test" - if err := os.Mkdir(testdir, 0755); err != nil { - t.Fatal(err) - } - defer os.RemoveAll(testdir) - label := "system_u:system_r:svirt_sandbox_file_t:s0:c1,c2" - if err := Relabel(testdir, "", true); err != nil { - t.Fatal("Relabel with no label failed: %v", err) - } - if err := Relabel(testdir, label, true); err != nil { - t.Fatal("Relabel shared failed: %v", err) - } - if err := Relabel(testdir, label, false); err != nil { - t.Fatal("Relabel unshared failed: %v", err) - } - if err := Relabel("/etc", label, false); err == nil { - t.Fatal("Relabel /etc succeeded") - } - if err := Relabel("/", label, false); err == nil { - t.Fatal("Relabel / succeeded") - } - if err := Relabel("/usr", label, false); err == nil { - t.Fatal("Relabel /usr succeeded") - } -} - -func TestValidate(t *testing.T) { - if err := Validate("zZ"); err != ErrIncompatibleLabel { - t.Fatalf("Expected incompatible error, got %v", err) - } - if err := Validate("Z"); err != nil { - t.Fatal(err) - } - if err := Validate("z"); err != nil { - t.Fatal(err) - } - if err := Validate(""); err != nil { - t.Fatal(err) - } -} - -func TestIsShared(t *testing.T) { - if shared := IsShared("Z"); shared { - t.Fatal("Expected label `Z` to not be shared, got %v", shared) - } - if shared := IsShared("z"); !shared { - t.Fatal("Expected label `z` to be shared, got %v", shared) - } - if shared := IsShared("Zz"); !shared { - t.Fatal("Expected label `Zz` to be shared, got %v", shared) - } - -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/message_linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/message_linux.go index 0c3301f..1663013 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/message_linux.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/message_linux.go @@ -12,8 +12,12 @@ import ( // The number is randomly chosen to not conflict with known netlink types const ( InitMsg uint16 = 62000 - PidAttr uint16 = 27281 + CloneFlagsAttr uint16 = 27281 ConsolePathAttr uint16 = 27282 + NsPathsAttr uint16 = 27283 + UidmapAttr uint16 = 27284 + GidmapAttr uint16 = 27285 + SetgroupAttr uint16 = 27286 // When syscall.NLA_HDRLEN is in gccgo, take this out. syscall_NLA_HDRLEN = (syscall.SizeofNlAttr + syscall.NLA_ALIGNTO - 1) & ^(syscall.NLA_ALIGNTO - 1) ) @@ -60,3 +64,25 @@ func (msg *Bytemsg) Serialize() []byte { func (msg *Bytemsg) Len() int { return syscall_NLA_HDRLEN + len(msg.Value) + 1 // null-terminated } + +type Boolmsg struct { + Type uint16 + Value bool +} + +func (msg *Boolmsg) Serialize() []byte { + buf := make([]byte, msg.Len()) + native := nl.NativeEndian() + native.PutUint16(buf[0:2], uint16(msg.Len())) + native.PutUint16(buf[2:4], msg.Type) + if msg.Value { + buf[4] = 1 + } else { + buf[4] = 0 + } + return buf +} + +func (msg *Boolmsg) Len() int { + return syscall_NLA_HDRLEN + 1 +} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/notify_linux_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/notify_linux_test.go deleted file mode 100644 index 9aa4f3b..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/notify_linux_test.go +++ /dev/null @@ -1,128 +0,0 @@ -// +build linux - -package libcontainer - -import ( - "encoding/binary" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "syscall" - "testing" - "time" -) - -type notifyFunc func(paths map[string]string) (<-chan struct{}, error) - -func testMemoryNotification(t *testing.T, evName string, notify notifyFunc, targ string) { - memoryPath, err := ioutil.TempDir("", "testmemnotification-"+evName) - if err != nil { - t.Fatal(err) - } - evFile := filepath.Join(memoryPath, evName) - eventPath := filepath.Join(memoryPath, "cgroup.event_control") - if err := ioutil.WriteFile(evFile, []byte{}, 0700); err != nil { - t.Fatal(err) - } - if err := ioutil.WriteFile(eventPath, []byte{}, 0700); err != nil { - t.Fatal(err) - } - paths := map[string]string{ - "memory": memoryPath, - } - ch, err := notify(paths) - if err != nil { - t.Fatal("expected no error, got:", err) - } - - data, err := ioutil.ReadFile(eventPath) - if err != nil { - t.Fatal("couldn't read event control file:", err) - } - - var eventFd, evFd int - var arg string - if targ != "" { - _, err = fmt.Sscanf(string(data), "%d %d %s", &eventFd, &evFd, &arg) - } else { - _, err = fmt.Sscanf(string(data), "%d %d", &eventFd, &evFd) - } - if err != nil || arg != targ { - t.Fatalf("invalid control data %q: %s", data, err) - } - - // re-open the eventfd - efd, err := syscall.Dup(eventFd) - if err != nil { - t.Fatal("unable to reopen eventfd:", err) - } - defer syscall.Close(efd) - - if err != nil { - t.Fatal("unable to dup event fd:", err) - } - - buf := make([]byte, 8) - binary.LittleEndian.PutUint64(buf, 1) - - if _, err := syscall.Write(efd, buf); err != nil { - t.Fatal("unable to write to eventfd:", err) - } - - select { - case <-ch: - case <-time.After(100 * time.Millisecond): - t.Fatal("no notification on channel after 100ms") - } - - // simulate what happens when a cgroup is destroyed by cleaning up and then - // writing to the eventfd. - if err := os.RemoveAll(memoryPath); err != nil { - t.Fatal(err) - } - if _, err := syscall.Write(efd, buf); err != nil { - t.Fatal("unable to write to eventfd:", err) - } - - // give things a moment to shut down - select { - case _, ok := <-ch: - if ok { - t.Fatal("expected no notification to be triggered") - } - case <-time.After(100 * time.Millisecond): - } - - if _, _, err := syscall.Syscall(syscall.SYS_FCNTL, uintptr(evFd), syscall.F_GETFD, 0); err != syscall.EBADF { - t.Error("expected event control to be closed") - } - - if _, _, err := syscall.Syscall(syscall.SYS_FCNTL, uintptr(eventFd), syscall.F_GETFD, 0); err != syscall.EBADF { - t.Error("expected event fd to be closed") - } -} - -func TestNotifyOnOOM(t *testing.T) { - f := func(paths map[string]string) (<-chan struct{}, error) { - return notifyOnOOM(paths) - } - - testMemoryNotification(t, "memory.oom_control", f, "") -} - -func TestNotifyMemoryPressure(t *testing.T) { - tests := map[PressureLevel]string{ - LowPressure: "low", - MediumPressure: "medium", - CriticalPressure: "critical", - } - - for level, arg := range tests { - f := func(paths map[string]string) (<-chan struct{}, error) { - return notifyMemoryPressure(paths, level) - } - - testMemoryNotification(t, "memory.pressure_level", f, arg) - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/nsenter/README.md b/vendor/src/github.com/opencontainers/runc/libcontainer/nsenter/README.md deleted file mode 100644 index d1a60ef..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/nsenter/README.md +++ /dev/null @@ -1,25 +0,0 @@ -## nsenter - -The `nsenter` package registers a special init constructor that is called before -the Go runtime has a chance to boot. This provides us the ability to `setns` on -existing namespaces and avoid the issues that the Go runtime has with multiple -threads. This constructor will be called if this package is registered, -imported, in your go application. - -The `nsenter` package will `import "C"` and it uses [cgo](https://golang.org/cmd/cgo/) -package. In cgo, if the import of "C" is immediately preceded by a comment, that comment, -called the preamble, is used as a header when compiling the C parts of the package. -So every time we import package `nsenter`, the C code function `nsexec()` would be -called. And package `nsenter` is now only imported in Docker execdriver, so every time -before we call `execdriver.Exec()`, that C code would run. - -`nsexec()` will first check the environment variable `_LIBCONTAINER_INITPID` -which will give the process of the container that should be joined. Namespaces fd will -be found from `/proc/[pid]/ns` and set by `setns` syscall. - -And then get the pipe number from `_LIBCONTAINER_INITPIPE`, error message could -be transfered through it. If tty is added, `_LIBCONTAINER_CONSOLE_PATH` will -have value and start a console for output. - -Finally, `nsexec()` will clone a child process , exit the parent process and let -the Go runtime take over. diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/nsenter/nsenter.go b/vendor/src/github.com/opencontainers/runc/libcontainer/nsenter/nsenter.go deleted file mode 100644 index 07f4d63..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/nsenter/nsenter.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build linux,!gccgo - -package nsenter - -/* -#cgo CFLAGS: -Wall -extern void nsexec(); -void __attribute__((constructor)) init(void) { - nsexec(); -} -*/ -import "C" diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_gccgo.go b/vendor/src/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_gccgo.go deleted file mode 100644 index 63c7a3e..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_gccgo.go +++ /dev/null @@ -1,25 +0,0 @@ -// +build linux,gccgo - -package nsenter - -/* -#cgo CFLAGS: -Wall -extern void nsexec(); -void __attribute__((constructor)) init(void) { - nsexec(); -} -*/ -import "C" - -// AlwaysFalse is here to stay false -// (and be exported so the compiler doesn't optimize out its reference) -var AlwaysFalse bool - -func init() { - if AlwaysFalse { - // by referencing this C init() in a noop test, it will ensure the compiler - // links in the C function. - // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65134 - C.init() - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_test.go deleted file mode 100644 index 976ae6b..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_test.go +++ /dev/null @@ -1,143 +0,0 @@ -package nsenter - -import ( - "bytes" - "encoding/json" - "io" - "os" - "os/exec" - "strings" - "syscall" - "testing" - - "github.com/opencontainers/runc/libcontainer" - "github.com/vishvananda/netlink/nl" -) - -type pid struct { - Pid int `json:"Pid"` -} - -func TestNsenterAlivePid(t *testing.T) { - args := []string{"nsenter-exec"} - parent, child, err := newPipe() - if err != nil { - t.Fatalf("failed to create pipe %v", err) - } - - cmd := &exec.Cmd{ - Path: os.Args[0], - Args: args, - ExtraFiles: []*os.File{child}, - Env: []string{"_LIBCONTAINER_INITTYPE=setns", "_LIBCONTAINER_INITPIPE=3"}, - } - - if err := cmd.Start(); err != nil { - t.Fatalf("nsenter failed to start %v", err) - } - r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0) - r.AddData(&libcontainer.Int32msg{ - Type: libcontainer.PidAttr, - Value: uint32(os.Getpid()), - }) - if _, err := io.Copy(parent, bytes.NewReader(r.Serialize())); err != nil { - t.Fatal(err) - } - decoder := json.NewDecoder(parent) - var pid *pid - - if err := decoder.Decode(&pid); err != nil { - t.Fatalf("%v", err) - } - - if err := cmd.Wait(); err != nil { - t.Fatalf("nsenter exits with a non-zero exit status") - } - p, err := os.FindProcess(pid.Pid) - if err != nil { - t.Fatalf("%v", err) - } - p.Wait() -} - -func TestNsenterInvalidPid(t *testing.T) { - args := []string{"nsenter-exec"} - parent, child, err := newPipe() - if err != nil { - t.Fatalf("failed to create pipe %v", err) - } - - cmd := &exec.Cmd{ - Path: os.Args[0], - Args: args, - ExtraFiles: []*os.File{child}, - Env: []string{"_LIBCONTAINER_INITTYPE=setns", "_LIBCONTAINER_INITPIPE=3"}, - } - - if err := cmd.Start(); err != nil { - t.Fatal("nsenter exits with a zero exit status") - } - r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0) - r.AddData(&libcontainer.Int32msg{ - Type: libcontainer.PidAttr, - Value: 0, - }) - if _, err := io.Copy(parent, bytes.NewReader(r.Serialize())); err != nil { - t.Fatal(err) - } - - if err := cmd.Wait(); err == nil { - t.Fatal("nsenter exits with a zero exit status") - } -} - -func TestNsenterDeadPid(t *testing.T) { - deadCmd := exec.Command("true") - if err := deadCmd.Run(); err != nil { - t.Fatal(err) - } - args := []string{"nsenter-exec"} - parent, child, err := newPipe() - if err != nil { - t.Fatalf("failed to create pipe %v", err) - } - - cmd := &exec.Cmd{ - Path: os.Args[0], - Args: args, - ExtraFiles: []*os.File{child}, - Env: []string{"_LIBCONTAINER_INITTYPE=setns", "_LIBCONTAINER_INITPIPE=3"}, - } - - if err := cmd.Start(); err != nil { - t.Fatal("nsenter exits with a zero exit status") - } - - r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0) - r.AddData(&libcontainer.Int32msg{ - Type: libcontainer.PidAttr, - Value: uint32(deadCmd.Process.Pid), - }) - if _, err := io.Copy(parent, bytes.NewReader(r.Serialize())); err != nil { - t.Fatal(err) - } - - if err := cmd.Wait(); err == nil { - t.Fatal("nsenter exits with a zero exit status") - } -} - -func init() { - if strings.HasPrefix(os.Args[0], "nsenter-") { - os.Exit(0) - } - return -} - -func newPipe() (parent *os.File, child *os.File, err error) { - fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM|syscall.SOCK_CLOEXEC, 0) - if err != nil { - return nil, nil, err - } - return os.NewFile(uintptr(fds[1]), "parent"), os.NewFile(uintptr(fds[0]), "child"), nil -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_unsupported.go b/vendor/src/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_unsupported.go deleted file mode 100644 index ac701ca..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_unsupported.go +++ /dev/null @@ -1,5 +0,0 @@ -// +build !linux !cgo - -package nsenter - -import "C" diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c b/vendor/src/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c deleted file mode 100644 index 6634afc..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c +++ /dev/null @@ -1,261 +0,0 @@ -#define _GNU_SOURCE -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* All arguments should be above stack, because it grows down */ -struct clone_arg { - /* - * Reserve some space for clone() to locate arguments - * and retcode in this place - */ - char stack[4096] __attribute__ ((aligned(16))); - char stack_ptr[0]; - jmp_buf *env; -}; - -#define pr_perror(fmt, ...) fprintf(stderr, "nsenter: " fmt ": %m\n", ##__VA_ARGS__) - -static int child_func(void *_arg) -{ - struct clone_arg *arg = (struct clone_arg *)_arg; - longjmp(*arg->env, 1); -} - -// Use raw setns syscall for versions of glibc that don't include it (namely glibc-2.12) -#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 14 -#define _GNU_SOURCE -#include "syscall.h" -#if defined(__NR_setns) && !defined(SYS_setns) -#define SYS_setns __NR_setns -#endif -#ifdef SYS_setns -int setns(int fd, int nstype) -{ - return syscall(SYS_setns, fd, nstype); -} -#endif -#endif - -static int clone_parent(jmp_buf * env) __attribute__ ((noinline)); -static int clone_parent(jmp_buf * env) -{ - struct clone_arg ca; - int child; - - ca.env = env; - child = clone(child_func, ca.stack_ptr, CLONE_PARENT | SIGCHLD, &ca); - - return child; -} - -static uint32_t readint32(char *buf) -{ - return *(uint32_t *) buf; -} - -// list of known message types we want to send to bootstrap program -// These are defined in libcontainer/message_linux.go -#define INIT_MSG 62000 -#define PID_ATTR 27281 -#define CONSOLE_PATH_ATTR 27282 - -void nsexec() -{ - char *namespaces[] = { "ipc", "uts", "net", "pid", "mnt", "user" }; - const int num = sizeof(namespaces) / sizeof(char *); - jmp_buf env; - char buf[PATH_MAX], *val; - int i, tfd, self_tfd, child, n, len, pipenum, consolefd = -1; - pid_t pid = 0; - - // if we dont have INITTYPE or this is the init process, skip the bootstrap process - val = getenv("_LIBCONTAINER_INITTYPE"); - if (val == NULL || strcmp(val, "standard") == 0) { - return; - } - if (strcmp(val, "setns") != 0) { - pr_perror("Invalid inittype %s", val); - exit(1); - } - - val = getenv("_LIBCONTAINER_INITPIPE"); - if (val == NULL) { - pr_perror("Child pipe not found"); - exit(1); - } - pipenum = atoi(val); - snprintf(buf, sizeof(buf), "%d", pipenum); - if (strcmp(val, buf)) { - pr_perror("Unable to parse _LIBCONTAINER_INITPIPE"); - exit(1); - } - - char nlbuf[NLMSG_HDRLEN]; - struct nlmsghdr *nh; - if ((n = read(pipenum, nlbuf, NLMSG_HDRLEN)) != NLMSG_HDRLEN) { - pr_perror("Failed to read netlink header, got %d", n); - exit(1); - } - - nh = (struct nlmsghdr *)nlbuf; - if (nh->nlmsg_type == NLMSG_ERROR) { - pr_perror("Invalid netlink header message"); - exit(1); - } - if (nh->nlmsg_type != INIT_MSG) { - pr_perror("Unexpected netlink message type %d", nh->nlmsg_type); - exit(1); - } - // read the netlink payload - len = NLMSG_PAYLOAD(nh, 0); - char data[len]; - if ((n = read(pipenum, data, len)) != len) { - pr_perror("Failed to read netlink payload, got %d", n); - exit(1); - } - - int start = 0; - struct nlattr *attr; - while (start < len) { - int payload_len; - attr = (struct nlattr *)((void *)data + start); - start += NLA_HDRLEN; - payload_len = attr->nla_len - NLA_HDRLEN; - switch (attr->nla_type) { - case PID_ATTR: - pid = (pid_t) readint32(data + start); - break; - case CONSOLE_PATH_ATTR: - consolefd = open((char *)data + start, O_RDWR); - if (consolefd < 0) { - pr_perror("Failed to open console %s", (char *)data + start); - exit(1); - } - break; - } - start += NLA_ALIGN(payload_len); - } - - // required pid to be passed - if (pid == 0) { - pr_perror("missing pid"); - exit(1); - } - - /* Check that the specified process exists */ - snprintf(buf, PATH_MAX - 1, "/proc/%d/ns", pid); - tfd = open(buf, O_DIRECTORY | O_RDONLY); - if (tfd == -1) { - pr_perror("Failed to open \"%s\"", buf); - exit(1); - } - - self_tfd = open("/proc/self/ns", O_DIRECTORY | O_RDONLY); - if (self_tfd == -1) { - pr_perror("Failed to open /proc/self/ns"); - exit(1); - } - - for (i = 0; i < num; i++) { - struct stat st; - struct stat self_st; - int fd; - - /* Symlinks on all namespaces exist for dead processes, but they can't be opened */ - if (fstatat(tfd, namespaces[i], &st, 0) == -1) { - // Ignore nonexistent namespaces. - if (errno == ENOENT) - continue; - } - - /* Skip namespaces we're already part of */ - if (fstatat(self_tfd, namespaces[i], &self_st, 0) != -1 && st.st_ino == self_st.st_ino) { - continue; - } - - fd = openat(tfd, namespaces[i], O_RDONLY); - if (fd == -1) { - pr_perror("Failed to open ns file %s for ns %s", buf, namespaces[i]); - exit(1); - } - // Set the namespace. - if (setns(fd, 0) == -1) { - pr_perror("Failed to setns for %s", namespaces[i]); - exit(1); - } - close(fd); - } - - close(self_tfd); - close(tfd); - - if (setjmp(env) == 1) { - // Child - - if (setsid() == -1) { - pr_perror("setsid failed"); - exit(1); - } - if (consolefd != -1) { - if (ioctl(consolefd, TIOCSCTTY, 0) == -1) { - pr_perror("ioctl TIOCSCTTY failed"); - exit(1); - } - if (dup3(consolefd, STDIN_FILENO, 0) != STDIN_FILENO) { - pr_perror("Failed to dup 0"); - exit(1); - } - if (dup3(consolefd, STDOUT_FILENO, 0) != STDOUT_FILENO) { - pr_perror("Failed to dup 1"); - exit(1); - } - if (dup3(consolefd, STDERR_FILENO, 0) != STDERR_FILENO) { - pr_perror("Failed to dup 2"); - exit(1); - } - } - // Finish executing, let the Go runtime take over. - return; - } - // Parent - - // We must fork to actually enter the PID namespace, use CLONE_PARENT - // so the child can have the right parent, and we don't need to forward - // the child's exit code or resend its death signal. - child = clone_parent(&env); - if (child < 0) { - pr_perror("Unable to fork"); - exit(1); - } - - len = snprintf(buf, sizeof(buf), "{ \"pid\" : %d }\n", child); - - if (write(pipenum, buf, len) != len) { - pr_perror("Unable to send a child pid"); - kill(child, SIGKILL); - exit(1); - } - - exit(0); -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/process.go b/vendor/src/github.com/opencontainers/runc/libcontainer/process.go index 8b4c558..9b82cfa 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/process.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/process.go @@ -48,6 +48,16 @@ type Process struct { // All capabilities not specified will be dropped from the processes capability mask Capabilities []string + // AppArmorProfile specifies the profile to apply to the process and is + // changed at the time the process is execed + AppArmorProfile string + + // Label specifies the label to apply to the process. It is commonly used by selinux + Label string + + // NoNewPrivileges controls whether processes can gain additional privileges. + NoNewPrivileges *bool + ops processOperations } diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/process_linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/process_linux.go index 353c87e..9ff4386 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/process_linux.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/process_linux.go @@ -88,6 +88,10 @@ func (p *setnsProcess) start() (err error) { if err := utils.WriteJSON(p.parentPipe, p.config); err != nil { return newSystemError(err) } + // set oom_score_adj + if err := setOomScoreAdj(p.config.Config.OomScoreAdj, p.pid()); err != nil { + return newSystemError(err) + } if err := syscall.Shutdown(int(p.parentPipe.Fd()), syscall.SHUT_WR); err != nil { return newSystemError(err) @@ -167,14 +171,16 @@ func (p *setnsProcess) setExternalDescriptors(newFds []string) { } type initProcess struct { - cmd *exec.Cmd - parentPipe *os.File - childPipe *os.File - config *initConfig - manager cgroups.Manager - container *linuxContainer - fds []string - process *Process + cmd *exec.Cmd + parentPipe *os.File + childPipe *os.File + config *initConfig + manager cgroups.Manager + container *linuxContainer + fds []string + process *Process + bootstrapData io.Reader + sharePidns bool } func (p *initProcess) pid() int { @@ -185,15 +191,49 @@ func (p *initProcess) externalDescriptors() []string { return p.fds } -func (p *initProcess) start() (err error) { +// execSetns runs the process that executes C code to perform the setns calls +// because setns support requires the C process to fork off a child and perform the setns +// before the go runtime boots, we wait on the process to die and receive the child's pid +// over the provided pipe. +// This is called by initProcess.start function +func (p *initProcess) execSetns() error { + status, err := p.cmd.Process.Wait() + if err != nil { + p.cmd.Wait() + return err + } + if !status.Success() { + p.cmd.Wait() + return &exec.ExitError{ProcessState: status} + } + var pid *pid + if err := json.NewDecoder(p.parentPipe).Decode(&pid); err != nil { + p.cmd.Wait() + return err + } + process, err := os.FindProcess(pid.Pid) + if err != nil { + return err + } + p.cmd.Process = process + return nil +} + +func (p *initProcess) start() error { defer p.parentPipe.Close() - err = p.cmd.Start() + err := p.cmd.Start() p.process.ops = p p.childPipe.Close() if err != nil { p.process.ops = nil return newSystemError(err) } + if _, err := io.Copy(p.parentPipe, p.bootstrapData); err != nil { + return err + } + if err := p.execSetns(); err != nil { + return newSystemError(err) + } // Save the standard descriptor names before the container process // can potentially move them (e.g., via dup2()). If we don't do this now, // we won't know at checkpoint time which file descriptor to look up. @@ -213,19 +253,6 @@ func (p *initProcess) start() (err error) { p.manager.Destroy() } }() - if p.config.Config.Hooks != nil { - s := configs.HookState{ - Version: p.container.config.Version, - ID: p.container.id, - Pid: p.pid(), - Root: p.config.Config.Rootfs, - } - for _, hook := range p.config.Config.Hooks.Prestart { - if err := hook.Run(s); err != nil { - return newSystemError(err) - } - } - } if err := p.createNetworkInterfaces(); err != nil { return newSystemError(err) } @@ -233,35 +260,74 @@ func (p *initProcess) start() (err error) { return newSystemError(err) } var ( - procSync syncT - sentRun bool - ierr *genericError + procSync syncT + sentRun bool + sentResume bool + ierr *genericError ) + dec := json.NewDecoder(p.parentPipe) loop: for { - if err := json.NewDecoder(p.parentPipe).Decode(&procSync); err != nil { + if err := dec.Decode(&procSync); err != nil { if err == io.EOF { break loop } return newSystemError(err) } switch procSync.Type { - case procStart: - break loop case procReady: if err := p.manager.Set(p.config.Config); err != nil { return newSystemError(err) } + // set oom_score_adj + if err := setOomScoreAdj(p.config.Config.OomScoreAdj, p.pid()); err != nil { + return newSystemError(err) + } + // call prestart hooks + if !p.config.Config.Namespaces.Contains(configs.NEWNS) { + if p.config.Config.Hooks != nil { + s := configs.HookState{ + Version: p.container.config.Version, + ID: p.container.id, + Pid: p.pid(), + Root: p.config.Config.Rootfs, + } + for _, hook := range p.config.Config.Hooks.Prestart { + if err := hook.Run(s); err != nil { + return newSystemError(err) + } + } + } + } // Sync with child. if err := utils.WriteJSON(p.parentPipe, syncT{procRun}); err != nil { return newSystemError(err) } sentRun = true + case procHooks: + if p.config.Config.Hooks != nil { + s := configs.HookState{ + Version: p.container.config.Version, + ID: p.container.id, + Pid: p.pid(), + Root: p.config.Config.Rootfs, + } + for _, hook := range p.config.Config.Hooks.Prestart { + if err := hook.Run(s); err != nil { + return newSystemError(err) + } + } + } + // Sync with child. + if err := utils.WriteJSON(p.parentPipe, syncT{procResume}); err != nil { + return newSystemError(err) + } + sentResume = 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 { + if err := dec.Decode(&ierr); err != nil && err != io.EOF { return newSystemError(err) } if ierr != nil { @@ -276,6 +342,9 @@ loop: if !sentRun { return newSystemError(fmt.Errorf("could not synchronise with container process")) } + if p.config.Config.Namespaces.Contains(configs.NEWNS) && !sentResume { + return newSystemError(fmt.Errorf("could not synchronise after executing prestart hooks with container process")) + } if err := syscall.Shutdown(int(p.parentPipe.Fd()), syscall.SHUT_WR); err != nil { return newSystemError(err) } @@ -293,7 +362,7 @@ func (p *initProcess) wait() (*os.ProcessState, error) { return p.cmd.ProcessState, err } // we should kill all processes in cgroup when init is died if we use host PID namespace - if p.cmd.SysProcAttr.Cloneflags&syscall.CLONE_NEWPID == 0 { + if p.sharePidns { killCgroupProcesses(p.manager) } return p.cmd.ProcessState, nil diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go index 5ea6ff0..1a880fe 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go @@ -4,6 +4,7 @@ package libcontainer import ( "fmt" + "io" "io/ioutil" "os" "os/exec" @@ -26,7 +27,7 @@ const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NOD // setupRootfs sets up the devices, mount points, and filesystems for use inside a // new mount namespace. -func setupRootfs(config *configs.Config, console *linuxConsole) (err error) { +func setupRootfs(config *configs.Config, console *linuxConsole, pipe io.ReadWriter) (err error) { if err := prepareRoot(config); err != nil { return newSystemError(err) } @@ -59,6 +60,13 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) { return newSystemError(err) } } + // Signal the parent to run the pre-start hooks. + // The hooks are run after the mounts are setup, but before we switch to the new + // root, so that the old root is still available in the hooks for any mount + // manipulations. + if err := syncParentHooks(pipe); err != nil { + return err + } if err := syscall.Chdir(config.Rootfs); err != nil { return newSystemError(err) } @@ -75,6 +83,18 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) { return newSystemError(err) } } + // remount dev as ro if specifed + for _, m := range config.Mounts { + if m.Destination == "/dev" { + if m.Flags&syscall.MS_RDONLY != 0 { + if err := remountReadonly(m.Destination); err != nil { + return newSystemError(err) + } + } + break + } + } + // set rootfs ( / ) as readonly if config.Readonlyfs { if err := setReadonly(); err != nil { return newSystemError(err) @@ -138,16 +158,6 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { } } return nil - case "devpts": - if err := os.MkdirAll(dest, 0755); err != nil { - return err - } - return mountPropagate(m, rootfs, mountLabel) - case "securityfs": - if err := os.MkdirAll(dest, 0755); err != nil { - return err - } - return mountPropagate(m, rootfs, mountLabel) case "bind": stat, err := os.Stat(m.Source) if err != nil { @@ -253,7 +263,10 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { } } default: - return fmt.Errorf("unknown mount device %q to %q", m.Device, m.Destination) + if err := os.MkdirAll(dest, 0755); err != nil { + return err + } + return mountPropagate(m, rootfs, mountLabel) } return nil } @@ -308,7 +321,8 @@ func checkMountDestination(rootfs, dest string) error { "/proc/cpuinfo", "/proc/diskstats", "/proc/meminfo", - "/proc/stats", + "/proc/stat", + "/proc/net/dev", } for _, valid := range validDestinations { path, err := filepath.Rel(filepath.Join(rootfs, valid), dest) @@ -341,7 +355,7 @@ func setupDevSymlinks(rootfs string) error { // kcore support can be toggled with CONFIG_PROC_KCORE; only create a symlink // in /dev if it exists in /proc. if _, err := os.Stat("/proc/kcore"); err == nil { - links = append(links, [2]string{"/proc/kcore", "/dev/kcore"}) + links = append(links, [2]string{"/proc/kcore", "/dev/core"}) } for _, link := range links { var ( @@ -551,7 +565,7 @@ func setupPtmx(config *configs.Config, console *linuxConsole) error { return nil } -func pivotRoot(rootfs, pivotBaseDir string) error { +func pivotRoot(rootfs, pivotBaseDir string) (err error) { if pivotBaseDir == "" { pivotBaseDir = "/" } @@ -563,6 +577,12 @@ func pivotRoot(rootfs, pivotBaseDir string) error { if err != nil { return fmt.Errorf("can't create pivot_root dir %s, error %v", pivotDir, err) } + defer func() { + errVal := os.Remove(pivotDir) + if err == nil { + err = errVal + } + }() if err := syscall.PivotRoot(rootfs, pivotDir); err != nil { return fmt.Errorf("pivot_root %s", err) } @@ -581,7 +601,7 @@ func pivotRoot(rootfs, pivotBaseDir string) error { if err := syscall.Unmount(pivotDir, syscall.MNT_DETACH); err != nil { return fmt.Errorf("unmount pivot_root dir %s", err) } - return os.Remove(pivotDir) + return nil } func msMoveRoot(rootfs string) error { @@ -670,14 +690,18 @@ func remount(m *configs.Mount, rootfs string) error { // of propagation flags. func mountPropagate(m *configs.Mount, rootfs string, mountLabel string) error { var ( - dest = m.Destination - data = label.FormatMountLabel(m.Data, mountLabel) + dest = m.Destination + data = label.FormatMountLabel(m.Data, mountLabel) + flags = m.Flags ) + if dest == "/dev" { + flags &= ^syscall.MS_RDONLY + } if !strings.HasPrefix(dest, rootfs) { dest = filepath.Join(rootfs, dest) } - if err := syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), data); err != nil { + if err := syscall.Mount(m.Source, dest, m.Device, uintptr(flags), data); err != nil { return err } diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux_test.go deleted file mode 100644 index a3bb077..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// +build linux - -package libcontainer - -import "testing" - -func TestCheckMountDestOnProc(t *testing.T) { - dest := "/rootfs/proc/" - err := checkMountDestination("/rootfs", dest) - if err == nil { - t.Fatal("destination inside proc should return an error") - } -} - -func TestCheckMountDestInSys(t *testing.T) { - dest := "/rootfs//sys/fs/cgroup" - err := checkMountDestination("/rootfs", dest) - if err != nil { - t.Fatal("destination inside /sys should not return an error") - } -} - -func TestCheckMountDestFalsePositive(t *testing.T) { - dest := "/rootfs/sysfiles/fs/cgroup" - err := checkMountDestination("/rootfs", dest) - if err != nil { - t.Fatal(err) - } -} - -func TestCheckMountRoot(t *testing.T) { - dest := "/rootfs" - err := checkMountDestination("/rootfs", dest) - if err == nil { - t.Fatal(err) - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/seccomp/fixtures/proc_self_status b/vendor/src/github.com/opencontainers/runc/libcontainer/seccomp/fixtures/proc_self_status deleted file mode 100644 index 0e0084f..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/seccomp/fixtures/proc_self_status +++ /dev/null @@ -1,47 +0,0 @@ -Name: cat -State: R (running) -Tgid: 19383 -Ngid: 0 -Pid: 19383 -PPid: 19275 -TracerPid: 0 -Uid: 1000 1000 1000 1000 -Gid: 1000 1000 1000 1000 -FDSize: 256 -Groups: 24 25 27 29 30 44 46 102 104 108 111 1000 1001 -NStgid: 19383 -NSpid: 19383 -NSpgid: 19383 -NSsid: 19275 -VmPeak: 5944 kB -VmSize: 5944 kB -VmLck: 0 kB -VmPin: 0 kB -VmHWM: 744 kB -VmRSS: 744 kB -VmData: 324 kB -VmStk: 136 kB -VmExe: 48 kB -VmLib: 1776 kB -VmPTE: 32 kB -VmPMD: 12 kB -VmSwap: 0 kB -Threads: 1 -SigQ: 0/30067 -SigPnd: 0000000000000000 -ShdPnd: 0000000000000000 -SigBlk: 0000000000000000 -SigIgn: 0000000000000080 -SigCgt: 0000000000000000 -CapInh: 0000000000000000 -CapPrm: 0000000000000000 -CapEff: 0000000000000000 -CapBnd: 0000003fffffffff -CapAmb: 0000000000000000 -Seccomp: 0 -Cpus_allowed: f -Cpus_allowed_list: 0-3 -Mems_allowed: 00000000,00000001 -Mems_allowed_list: 0 -voluntary_ctxt_switches: 0 -nonvoluntary_ctxt_switches: 1 diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux_test.go deleted file mode 100644 index 67a2ef6..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux_test.go +++ /dev/null @@ -1,17 +0,0 @@ -// +build linux,cgo,seccomp - -package seccomp - -import "testing" - -func TestParseStatusFile(t *testing.T) { - s, err := parseStatusFile("fixtures/proc_self_status") - if err != nil { - t.Fatal(err) - } - - if _, ok := s["Seccomp"]; !ok { - - t.Fatal("expected to find 'Seccomp' in the map but did not.") - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/selinux/selinux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/selinux/selinux.go deleted file mode 100644 index 88d612c..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/selinux/selinux.go +++ /dev/null @@ -1,477 +0,0 @@ -// +build linux - -package selinux - -import ( - "bufio" - "crypto/rand" - "encoding/binary" - "fmt" - "io" - "os" - "path/filepath" - "regexp" - "strconv" - "strings" - "syscall" - - "github.com/docker/docker/pkg/mount" - "github.com/opencontainers/runc/libcontainer/system" -) - -const ( - Enforcing = 1 - Permissive = 0 - Disabled = -1 - selinuxDir = "/etc/selinux/" - selinuxConfig = selinuxDir + "config" - selinuxTypeTag = "SELINUXTYPE" - selinuxTag = "SELINUX" - selinuxPath = "/sys/fs/selinux" - xattrNameSelinux = "security.selinux" - stRdOnly = 0x01 -) - -var ( - assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`) - mcsList = make(map[string]bool) - selinuxfs = "unknown" - selinuxEnabled = false // Stores whether selinux is currently enabled - selinuxEnabledChecked = false // Stores whether selinux enablement has been checked or established yet -) - -type SELinuxContext map[string]string - -// SetDisabled disables selinux support for the package -func SetDisabled() { - selinuxEnabled, selinuxEnabledChecked = false, true -} - -// getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs -// filesystem or an empty string if no mountpoint is found. Selinuxfs is -// a proc-like pseudo-filesystem that exposes the selinux policy API to -// processes. The existence of an selinuxfs mount is used to determine -// whether selinux is currently enabled or not. -func getSelinuxMountPoint() string { - if selinuxfs != "unknown" { - return selinuxfs - } - selinuxfs = "" - - mounts, err := mount.GetMounts() - if err != nil { - return selinuxfs - } - for _, mount := range mounts { - if mount.Fstype == "selinuxfs" { - selinuxfs = mount.Mountpoint - break - } - } - if selinuxfs != "" { - var buf syscall.Statfs_t - syscall.Statfs(selinuxfs, &buf) - if (buf.Flags & stRdOnly) == 1 { - selinuxfs = "" - } - } - return selinuxfs -} - -// SelinuxEnabled returns whether selinux is currently enabled. -func SelinuxEnabled() bool { - if selinuxEnabledChecked { - return selinuxEnabled - } - selinuxEnabledChecked = true - if fs := getSelinuxMountPoint(); fs != "" { - if con, _ := Getcon(); con != "kernel" { - selinuxEnabled = true - } - } - return selinuxEnabled -} - -func readConfig(target string) (value string) { - var ( - val, key string - bufin *bufio.Reader - ) - - in, err := os.Open(selinuxConfig) - if err != nil { - return "" - } - defer in.Close() - - bufin = bufio.NewReader(in) - - for done := false; !done; { - var line string - if line, err = bufin.ReadString('\n'); err != nil { - if err != io.EOF { - return "" - } - done = true - } - line = strings.TrimSpace(line) - if len(line) == 0 { - // Skip blank lines - continue - } - if line[0] == ';' || line[0] == '#' { - // Skip comments - continue - } - if groups := assignRegex.FindStringSubmatch(line); groups != nil { - key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) - if key == target { - return strings.Trim(val, "\"") - } - } - } - return "" -} - -func getSELinuxPolicyRoot() string { - return selinuxDir + readConfig(selinuxTypeTag) -} - -func readCon(name string) (string, error) { - var val string - - in, err := os.Open(name) - if err != nil { - return "", err - } - defer in.Close() - - _, err = fmt.Fscanf(in, "%s", &val) - return val, err -} - -// Setfilecon sets the SELinux label for this path or returns an error. -func Setfilecon(path string, scon string) error { - return system.Lsetxattr(path, xattrNameSelinux, []byte(scon), 0) -} - -// Getfilecon returns the SELinux label for this path or returns an error. -func Getfilecon(path string) (string, error) { - con, err := system.Lgetxattr(path, xattrNameSelinux) - - // Trim the NUL byte at the end of the byte buffer, if present. - if con[len(con)-1] == '\x00' { - con = con[:len(con)-1] - } - return string(con), err -} - -func Setfscreatecon(scon string) error { - return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", syscall.Gettid()), scon) -} - -func Getfscreatecon() (string, error) { - return readCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", syscall.Gettid())) -} - -// Getcon returns the SELinux label of the current process thread, or an error. -func Getcon() (string, error) { - return readCon(fmt.Sprintf("/proc/self/task/%d/attr/current", syscall.Gettid())) -} - -// Getpidcon returns the SELinux label of the given pid, or an error. -func Getpidcon(pid int) (string, error) { - return readCon(fmt.Sprintf("/proc/%d/attr/current", pid)) -} - -func Getexeccon() (string, error) { - return readCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid())) -} - -func writeCon(name string, val string) error { - out, err := os.OpenFile(name, os.O_WRONLY, 0) - if err != nil { - return err - } - defer out.Close() - - if val != "" { - _, err = out.Write([]byte(val)) - } else { - _, err = out.Write(nil) - } - return err -} - -func Setexeccon(scon string) error { - return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()), scon) -} - -func (c SELinuxContext) Get() string { - return fmt.Sprintf("%s:%s:%s:%s", c["user"], c["role"], c["type"], c["level"]) -} - -func NewContext(scon string) SELinuxContext { - c := make(SELinuxContext) - - if len(scon) != 0 { - con := strings.SplitN(scon, ":", 4) - c["user"] = con[0] - c["role"] = con[1] - c["type"] = con[2] - c["level"] = con[3] - } - return c -} - -func ReserveLabel(scon string) { - if len(scon) != 0 { - con := strings.SplitN(scon, ":", 4) - mcsAdd(con[3]) - } -} - -func selinuxEnforcePath() string { - return fmt.Sprintf("%s/enforce", selinuxPath) -} - -func SelinuxGetEnforce() int { - var enforce int - - enforceS, err := readCon(selinuxEnforcePath()) - if err != nil { - return -1 - } - - enforce, err = strconv.Atoi(string(enforceS)) - if err != nil { - return -1 - } - return enforce -} - -func SelinuxSetEnforce(mode int) error { - return writeCon(selinuxEnforcePath(), fmt.Sprintf("%d", mode)) -} - -func SelinuxGetEnforceMode() int { - switch readConfig(selinuxTag) { - case "enforcing": - return Enforcing - case "permissive": - return Permissive - } - return Disabled -} - -func mcsAdd(mcs string) error { - if mcsList[mcs] { - return fmt.Errorf("MCS Label already exists") - } - mcsList[mcs] = true - return nil -} - -func mcsDelete(mcs string) { - mcsList[mcs] = false -} - -func IntToMcs(id int, catRange uint32) string { - var ( - SETSIZE = int(catRange) - TIER = SETSIZE - ORD = id - ) - - if id < 1 || id > 523776 { - return "" - } - - for ORD > TIER { - ORD = ORD - TIER - TIER -= 1 - } - TIER = SETSIZE - TIER - ORD = ORD + TIER - return fmt.Sprintf("s0:c%d,c%d", TIER, ORD) -} - -func uniqMcs(catRange uint32) string { - var ( - n uint32 - c1, c2 uint32 - mcs string - ) - - for { - binary.Read(rand.Reader, binary.LittleEndian, &n) - c1 = n % catRange - binary.Read(rand.Reader, binary.LittleEndian, &n) - c2 = n % catRange - if c1 == c2 { - continue - } else { - if c1 > c2 { - t := c1 - c1 = c2 - c2 = t - } - } - mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2) - if err := mcsAdd(mcs); err != nil { - continue - } - break - } - return mcs -} - -func FreeLxcContexts(scon string) { - if len(scon) != 0 { - con := strings.SplitN(scon, ":", 4) - mcsDelete(con[3]) - } -} - -func GetLxcContexts() (processLabel string, fileLabel string) { - var ( - val, key string - bufin *bufio.Reader - ) - - if !SelinuxEnabled() { - return "", "" - } - lxcPath := fmt.Sprintf("%s/contexts/lxc_contexts", getSELinuxPolicyRoot()) - in, err := os.Open(lxcPath) - if err != nil { - return "", "" - } - defer in.Close() - - bufin = bufio.NewReader(in) - - for done := false; !done; { - var line string - if line, err = bufin.ReadString('\n'); err != nil { - if err == io.EOF { - done = true - } else { - goto exit - } - } - line = strings.TrimSpace(line) - if len(line) == 0 { - // Skip blank lines - continue - } - if line[0] == ';' || line[0] == '#' { - // Skip comments - continue - } - if groups := assignRegex.FindStringSubmatch(line); groups != nil { - key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) - if key == "process" { - processLabel = strings.Trim(val, "\"") - } - if key == "file" { - fileLabel = strings.Trim(val, "\"") - } - } - } - - if processLabel == "" || fileLabel == "" { - return "", "" - } - -exit: - // mcs := IntToMcs(os.Getpid(), 1024) - mcs := uniqMcs(1024) - scon := NewContext(processLabel) - scon["level"] = mcs - processLabel = scon.Get() - scon = NewContext(fileLabel) - scon["level"] = mcs - fileLabel = scon.Get() - return processLabel, fileLabel -} - -func SecurityCheckContext(val string) error { - return writeCon(fmt.Sprintf("%s.context", selinuxPath), val) -} - -func CopyLevel(src, dest string) (string, error) { - if src == "" { - return "", nil - } - if err := SecurityCheckContext(src); err != nil { - return "", err - } - if err := SecurityCheckContext(dest); err != nil { - return "", err - } - scon := NewContext(src) - tcon := NewContext(dest) - mcsDelete(tcon["level"]) - mcsAdd(scon["level"]) - tcon["level"] = scon["level"] - return tcon.Get(), nil -} - -// Prevent users from relabing system files -func badPrefix(fpath string) error { - var badprefixes = []string{"/usr"} - - for _, prefix := range badprefixes { - if fpath == prefix || strings.HasPrefix(fpath, fmt.Sprintf("%s/", prefix)) { - return fmt.Errorf("Relabeling content in %s is not allowed.", prefix) - } - } - return nil -} - -// Change the fpath file object to the SELinux label scon. -// If the fpath is a directory and recurse is true Chcon will walk the -// directory tree setting the label -func Chcon(fpath string, scon string, recurse bool) error { - if scon == "" { - return nil - } - if err := badPrefix(fpath); err != nil { - return err - } - callback := func(p string, info os.FileInfo, err error) error { - return Setfilecon(p, scon) - } - - if recurse { - return filepath.Walk(fpath, callback) - } - - return Setfilecon(fpath, scon) -} - -// DupSecOpt takes an SELinux process label and returns security options that -// can will set the SELinux Type and Level for future container processes -func DupSecOpt(src string) []string { - if src == "" { - return nil - } - con := NewContext(src) - if con["user"] == "" || - con["role"] == "" || - con["type"] == "" || - con["level"] == "" { - return nil - } - return []string{"label:user:" + con["user"], - "label:role:" + con["role"], - "label:type:" + con["type"], - "label:level:" + con["level"]} -} - -// DisableSecOpt returns a security opt that can be used to disabling SELinux -// labeling support for future container processes -func DisableSecOpt() []string { - return []string{"label:disable"} -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/selinux/selinux_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/selinux/selinux_test.go deleted file mode 100644 index c2d561b..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/selinux/selinux_test.go +++ /dev/null @@ -1,75 +0,0 @@ -// +build linux,selinux - -package selinux_test - -import ( - "os" - "testing" - - "github.com/opencontainers/runc/libcontainer/selinux" -) - -func TestSetfilecon(t *testing.T) { - if selinux.SelinuxEnabled() { - tmp := "selinux_test" - out, _ := os.OpenFile(tmp, os.O_WRONLY|os.O_CREATE, 0) - out.Close() - err := selinux.Setfilecon(tmp, "system_u:object_r:bin_t:s0") - if err != nil { - t.Log("Setfilecon failed") - t.Fatal(err) - } - os.Remove(tmp) - } -} - -func TestSELinux(t *testing.T) { - var ( - err error - plabel, flabel string - ) - - if selinux.SelinuxEnabled() { - t.Log("Enabled") - plabel, flabel = selinux.GetLxcContexts() - t.Log(plabel) - t.Log(flabel) - selinux.FreeLxcContexts(plabel) - plabel, flabel = selinux.GetLxcContexts() - t.Log(plabel) - t.Log(flabel) - selinux.FreeLxcContexts(plabel) - t.Log("getenforce ", selinux.SelinuxGetEnforce()) - mode := selinux.SelinuxGetEnforceMode() - t.Log("getenforcemode ", mode) - - defer selinux.SelinuxSetEnforce(mode) - if err := selinux.SelinuxSetEnforce(selinux.Enforcing); err != nil { - t.Fatalf("enforcing selinux failed: %v", err) - } - if err := selinux.SelinuxSetEnforce(selinux.Permissive); err != nil { - t.Fatalf("setting selinux mode to permissive failed: %v", err) - } - selinux.SelinuxSetEnforce(mode) - - pid := os.Getpid() - t.Logf("PID:%d MCS:%s\n", pid, selinux.IntToMcs(pid, 1023)) - err = selinux.Setfscreatecon("unconfined_u:unconfined_r:unconfined_t:s0") - if err == nil { - t.Log(selinux.Getfscreatecon()) - } else { - t.Log("setfscreatecon failed", err) - t.Fatal(err) - } - err = selinux.Setfscreatecon("") - if err == nil { - t.Log(selinux.Getfscreatecon()) - } else { - t.Log("setfscreatecon failed", err) - t.Fatal(err) - } - t.Log(selinux.Getpidcon(1)) - } else { - t.Log("Disabled") - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/setns_init_linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/setns_init_linux.go index cb9af7d..5d78cc5 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/setns_init_linux.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/setns_init_linux.go @@ -3,6 +3,7 @@ package libcontainer import ( + "fmt" "os" "github.com/opencontainers/runc/libcontainer/apparmor" @@ -18,16 +19,22 @@ type linuxSetnsInit struct { config *initConfig } +func (l *linuxSetnsInit) getSessionRingName() string { + return fmt.Sprintf("_ses.%s", l.config.ContainerId) +} + func (l *linuxSetnsInit) Init() error { // do not inherit the parent's session keyring - if _, err := keyctl.JoinSessionKeyring("_ses"); err != nil { + if _, err := keyctl.JoinSessionKeyring(l.getSessionRingName()); err != nil { return err } if err := setupRlimits(l.config.Config); err != nil { return err } - if err := setOomScoreAdj(l.config.Config.OomScoreAdj); err != nil { - return err + if l.config.NoNewPrivileges { + if err := system.Prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil { + return err + } } if l.config.Config.Seccomp != nil { if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil { @@ -37,11 +44,11 @@ func (l *linuxSetnsInit) Init() error { if err := finalizeNamespace(l.config); err != nil { return err } - if err := apparmor.ApplyProfile(l.config.Config.AppArmorProfile); err != nil { + if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil { return err } - if l.config.Config.ProcessLabel != "" { - if err := label.SetProcessLabel(l.config.Config.ProcessLabel); err != nil { + if l.config.ProcessLabel != "" { + if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil { return err } } diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/stacktrace/capture_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/stacktrace/capture_test.go deleted file mode 100644 index 8337930..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/stacktrace/capture_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package stacktrace - -import "testing" - -func captureFunc() Stacktrace { - return Capture(0) -} - -func TestCaptureTestFunc(t *testing.T) { - stack := captureFunc() - - if len(stack.Frames) == 0 { - t.Fatal("expected stack frames to be returned") - } - - // the first frame is the caller - frame := stack.Frames[0] - if expected := "captureFunc"; frame.Function != expected { - t.Fatalf("expteced function %q but recevied %q", expected, frame.Function) - } - if expected := "github.com/opencontainers/runc/libcontainer/stacktrace"; frame.Package != expected { - t.Fatalf("expected package %q but received %q", expected, frame.Package) - } - if expected := "capture_test.go"; frame.File != expected { - t.Fatalf("expected file %q but received %q", expected, frame.File) - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/stacktrace/frame_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/stacktrace/frame_test.go deleted file mode 100644 index c6fc78e..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/stacktrace/frame_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package stacktrace - -import "testing" - -func TestParsePackageName(t *testing.T) { - var ( - name = "github.com/opencontainers/runc/libcontainer/stacktrace.captureFunc" - expectedPackage = "github.com/opencontainers/runc/libcontainer/stacktrace" - expectedFunction = "captureFunc" - ) - - pack, funcName := parseFunctionName(name) - if pack != expectedPackage { - t.Fatalf("expected package %q but received %q", expectedPackage, pack) - } - - if funcName != expectedFunction { - t.Fatalf("expected function %q but received %q", expectedFunction, funcName) - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/standard_init_linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/standard_init_linux.go index c17031d..2360419 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/standard_init_linux.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/standard_init_linux.go @@ -3,6 +3,7 @@ package libcontainer import ( + "fmt" "io" "os" "syscall" @@ -21,23 +22,39 @@ type linuxStandardInit struct { config *initConfig } +func (l *linuxStandardInit) getSessionRingParams() (string, uint32, uint32) { + var newperms uint32 + + if l.config.Config.Namespaces.Contains(configs.NEWUSER) { + // with user ns we need 'other' search permissions + newperms = 0x8 + } else { + // without user ns we need 'UID' search permissions + newperms = 0x80000 + } + + // create a unique per session container name that we can + // join in setns; however, other containers can also join it + return fmt.Sprintf("_ses.%s", l.config.ContainerId), 0xffffffff, newperms +} + +// PR_SET_NO_NEW_PRIVS isn't exposed in Golang so we define it ourselves copying the value +// the kernel +const PR_SET_NO_NEW_PRIVS = 0x26 + func (l *linuxStandardInit) Init() error { + ringname, keepperms, newperms := l.getSessionRingParams() + // do not inherit the parent's session keyring - sessKeyId, err := keyctl.JoinSessionKeyring("") + sessKeyId, err := keyctl.JoinSessionKeyring(ringname) if err != nil { return err } // make session keyring searcheable - // without user ns we need 'UID' search permissions - // with user ns we need 'other' search permissions - if err := keyctl.ModKeyringPerm(sessKeyId, 0xffffffff, 0x080008); err != nil { + if err := keyctl.ModKeyringPerm(sessKeyId, keepperms, newperms); err != nil { return err } - // join any namespaces via a path to the namespace fd if provided - if err := joinExistingNamespaces(l.config.Config.Namespaces); err != nil { - return err - } var console *linuxConsole if l.config.Console != "" { console = newConsoleFromPath(l.config.Console) @@ -45,9 +62,6 @@ func (l *linuxStandardInit) Init() error { return err } } - if _, err := syscall.Setsid(); err != nil { - return err - } if console != nil { if err := system.Setctty(); err != nil { return err @@ -62,13 +76,11 @@ func (l *linuxStandardInit) Init() error { if err := setupRlimits(l.config.Config); err != nil { return err } - if err := setOomScoreAdj(l.config.Config.OomScoreAdj); err != nil { - return err - } + label.Init() // InitializeMountNamespace() can be executed only for a new mount namespace if l.config.Config.Namespaces.Contains(configs.NEWNS) { - if err := setupRootfs(l.config.Config, console); err != nil { + if err := setupRootfs(l.config.Config, console, l.pipe); err != nil { return err } } @@ -77,10 +89,10 @@ func (l *linuxStandardInit) Init() error { return err } } - if err := apparmor.ApplyProfile(l.config.Config.AppArmorProfile); err != nil { + if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil { return err } - if err := label.SetProcessLabel(l.config.Config.ProcessLabel); err != nil { + if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil { return err } @@ -103,6 +115,11 @@ func (l *linuxStandardInit) Init() error { if err != nil { return err } + if l.config.NoNewPrivileges { + if err := system.Prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil { + 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. @@ -128,5 +145,6 @@ func (l *linuxStandardInit) Init() error { if syscall.Getppid() != l.parentPid { return syscall.Kill(syscall.Getpid(), syscall.SIGKILL) } + return system.Execv(l.config.Args[0], l.config.Args[0:], os.Environ()) } diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/state_linux_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/state_linux_test.go deleted file mode 100644 index 417d9c2..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/state_linux_test.go +++ /dev/null @@ -1,79 +0,0 @@ -// +build linux - -package libcontainer - -import "testing" - -func TestStateStatus(t *testing.T) { - states := map[containerState]Status{ - &stoppedState{}: Destroyed, - &runningState{}: Running, - &restoredState{}: Running, - &pausedState{}: Paused, - } - for s, status := range states { - if s.status() != status { - t.Fatalf("state returned %s but expected %s", s.status(), status) - } - } -} - -func isStateTransitionError(err error) bool { - _, ok := err.(*stateTransitionError) - return ok -} - -func TestStoppedStateTransition(t *testing.T) { - s := &stoppedState{c: &linuxContainer{}} - valid := []containerState{ - &stoppedState{}, - &runningState{}, - &restoredState{}, - } - for _, v := range valid { - if err := s.transition(v); err != nil { - t.Fatal(err) - } - } - err := s.transition(&pausedState{}) - if err == nil { - t.Fatal("transition to paused state should fail") - } - if !isStateTransitionError(err) { - t.Fatal("expected stateTransitionError") - } -} - -func TestPausedStateTransition(t *testing.T) { - s := &pausedState{c: &linuxContainer{}} - valid := []containerState{ - &pausedState{}, - &runningState{}, - &stoppedState{}, - } - for _, v := range valid { - if err := s.transition(v); err != nil { - t.Fatal(err) - } - } -} - -func TestRestoredStateTransition(t *testing.T) { - s := &restoredState{c: &linuxContainer{}} - valid := []containerState{ - &stoppedState{}, - &runningState{}, - } - for _, v := range valid { - if err := s.transition(v); err != nil { - t.Fatal(err) - } - } - err := s.transition(&createdState{}) - if err == nil { - t.Fatal("transition to created state should fail") - } - if !isStateTransitionError(err) { - t.Fatal("expected stateTransitionError") - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/system/linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/system/linux.go index 6c835e6..babf550 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/system/linux.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/system/linux.go @@ -112,3 +112,11 @@ func RunningInUserNS() bool { } return true } + +func Prctl(option int, arg2, arg3, arg4, arg5 uintptr) (err error) { + _, _, e1 := syscall.Syscall6(syscall.SYS_PRCTL, uintptr(option), arg2, arg3, arg4, arg5, 0) + if e1 != 0 { + err = e1 + } + return +} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/user/user_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/user/user_test.go deleted file mode 100644 index 53b2289..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/user/user_test.go +++ /dev/null @@ -1,472 +0,0 @@ -package user - -import ( - "io" - "reflect" - "sort" - "strconv" - "strings" - "testing" -) - -func TestUserParseLine(t *testing.T) { - var ( - a, b string - c []string - d int - ) - - parseLine("", &a, &b) - if a != "" || b != "" { - t.Fatalf("a and b should be empty ('%v', '%v')", a, b) - } - - parseLine("a", &a, &b) - if a != "a" || b != "" { - t.Fatalf("a should be 'a' and b should be empty ('%v', '%v')", a, b) - } - - parseLine("bad boys:corny cows", &a, &b) - if a != "bad boys" || b != "corny cows" { - t.Fatalf("a should be 'bad boys' and b should be 'corny cows' ('%v', '%v')", a, b) - } - - parseLine("", &c) - if len(c) != 0 { - t.Fatalf("c should be empty (%#v)", c) - } - - parseLine("d,e,f:g:h:i,j,k", &c, &a, &b, &c) - if a != "g" || b != "h" || len(c) != 3 || c[0] != "i" || c[1] != "j" || c[2] != "k" { - t.Fatalf("a should be 'g', b should be 'h', and c should be ['i','j','k'] ('%v', '%v', '%#v')", a, b, c) - } - - parseLine("::::::::::", &a, &b, &c) - if a != "" || b != "" || len(c) != 0 { - t.Fatalf("a, b, and c should all be empty ('%v', '%v', '%#v')", a, b, c) - } - - parseLine("not a number", &d) - if d != 0 { - t.Fatalf("d should be 0 (%v)", d) - } - - parseLine("b:12:c", &a, &d, &b) - if a != "b" || b != "c" || d != 12 { - t.Fatalf("a should be 'b' and b should be 'c', and d should be 12 ('%v', '%v', %v)", a, b, d) - } -} - -func TestUserParsePasswd(t *testing.T) { - users, err := ParsePasswdFilter(strings.NewReader(` -root:x:0:0:root:/root:/bin/bash -adm:x:3:4:adm:/var/adm:/bin/false -this is just some garbage data -`), nil) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - if len(users) != 3 { - t.Fatalf("Expected 3 users, got %v", len(users)) - } - if users[0].Uid != 0 || users[0].Name != "root" { - t.Fatalf("Expected users[0] to be 0 - root, got %v - %v", users[0].Uid, users[0].Name) - } - if users[1].Uid != 3 || users[1].Name != "adm" { - t.Fatalf("Expected users[1] to be 3 - adm, got %v - %v", users[1].Uid, users[1].Name) - } -} - -func TestUserParseGroup(t *testing.T) { - groups, err := ParseGroupFilter(strings.NewReader(` -root:x:0:root -adm:x:4:root,adm,daemon -this is just some garbage data -`), nil) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - if len(groups) != 3 { - t.Fatalf("Expected 3 groups, got %v", len(groups)) - } - if groups[0].Gid != 0 || groups[0].Name != "root" || len(groups[0].List) != 1 { - t.Fatalf("Expected groups[0] to be 0 - root - 1 member, got %v - %v - %v", groups[0].Gid, groups[0].Name, len(groups[0].List)) - } - if groups[1].Gid != 4 || groups[1].Name != "adm" || len(groups[1].List) != 3 { - t.Fatalf("Expected groups[1] to be 4 - adm - 3 members, got %v - %v - %v", groups[1].Gid, groups[1].Name, len(groups[1].List)) - } -} - -func TestValidGetExecUser(t *testing.T) { - const passwdContent = ` -root:x:0:0:root user:/root:/bin/bash -adm:x:42:43:adm:/var/adm:/bin/false -this is just some garbage data -` - const groupContent = ` -root:x:0:root -adm:x:43: -grp:x:1234:root,adm -this is just some garbage data -` - defaultExecUser := ExecUser{ - Uid: 8888, - Gid: 8888, - Sgids: []int{8888}, - Home: "/8888", - } - - tests := []struct { - ref string - expected ExecUser - }{ - { - ref: "root", - expected: ExecUser{ - Uid: 0, - Gid: 0, - Sgids: []int{0, 1234}, - Home: "/root", - }, - }, - { - ref: "adm", - expected: ExecUser{ - Uid: 42, - Gid: 43, - Sgids: []int{1234}, - Home: "/var/adm", - }, - }, - { - ref: "root:adm", - expected: ExecUser{ - Uid: 0, - Gid: 43, - Sgids: defaultExecUser.Sgids, - Home: "/root", - }, - }, - { - ref: "adm:1234", - expected: ExecUser{ - Uid: 42, - Gid: 1234, - Sgids: defaultExecUser.Sgids, - Home: "/var/adm", - }, - }, - { - ref: "42:1234", - expected: ExecUser{ - Uid: 42, - Gid: 1234, - Sgids: defaultExecUser.Sgids, - Home: "/var/adm", - }, - }, - { - ref: "1337:1234", - expected: ExecUser{ - Uid: 1337, - Gid: 1234, - Sgids: defaultExecUser.Sgids, - Home: defaultExecUser.Home, - }, - }, - { - ref: "1337", - expected: ExecUser{ - Uid: 1337, - Gid: defaultExecUser.Gid, - Sgids: defaultExecUser.Sgids, - Home: defaultExecUser.Home, - }, - }, - { - ref: "", - expected: ExecUser{ - Uid: defaultExecUser.Uid, - Gid: defaultExecUser.Gid, - Sgids: defaultExecUser.Sgids, - Home: defaultExecUser.Home, - }, - }, - } - - for _, test := range tests { - passwd := strings.NewReader(passwdContent) - group := strings.NewReader(groupContent) - - execUser, err := GetExecUser(test.ref, &defaultExecUser, passwd, group) - if err != nil { - t.Logf("got unexpected error when parsing '%s': %s", test.ref, err.Error()) - t.Fail() - continue - } - - if !reflect.DeepEqual(test.expected, *execUser) { - t.Logf("got: %#v", execUser) - t.Logf("expected: %#v", test.expected) - t.Fail() - continue - } - } -} - -func TestInvalidGetExecUser(t *testing.T) { - const passwdContent = ` -root:x:0:0:root user:/root:/bin/bash -adm:x:42:43:adm:/var/adm:/bin/false -this is just some garbage data -` - const groupContent = ` -root:x:0:root -adm:x:43: -grp:x:1234:root,adm -this is just some garbage data -` - - tests := []string{ - // No such user/group. - "notuser", - "notuser:notgroup", - "root:notgroup", - "notuser:adm", - "8888:notgroup", - "notuser:8888", - - // Invalid user/group values. - "-1:0", - "0:-3", - "-5:-2", - } - - for _, test := range tests { - passwd := strings.NewReader(passwdContent) - group := strings.NewReader(groupContent) - - execUser, err := GetExecUser(test, nil, passwd, group) - if err == nil { - t.Logf("got unexpected success when parsing '%s': %#v", test, execUser) - t.Fail() - continue - } - } -} - -func TestGetExecUserNilSources(t *testing.T) { - const passwdContent = ` -root:x:0:0:root user:/root:/bin/bash -adm:x:42:43:adm:/var/adm:/bin/false -this is just some garbage data -` - const groupContent = ` -root:x:0:root -adm:x:43: -grp:x:1234:root,adm -this is just some garbage data -` - - defaultExecUser := ExecUser{ - Uid: 8888, - Gid: 8888, - Sgids: []int{8888}, - Home: "/8888", - } - - tests := []struct { - ref string - passwd, group bool - expected ExecUser - }{ - { - ref: "", - passwd: false, - group: false, - expected: ExecUser{ - Uid: 8888, - Gid: 8888, - Sgids: []int{8888}, - Home: "/8888", - }, - }, - { - ref: "root", - passwd: true, - group: false, - expected: ExecUser{ - Uid: 0, - Gid: 0, - Sgids: []int{8888}, - Home: "/root", - }, - }, - { - ref: "0", - passwd: false, - group: false, - expected: ExecUser{ - Uid: 0, - Gid: 8888, - Sgids: []int{8888}, - Home: "/8888", - }, - }, - { - ref: "0:0", - passwd: false, - group: false, - expected: ExecUser{ - Uid: 0, - Gid: 0, - Sgids: []int{8888}, - Home: "/8888", - }, - }, - } - - for _, test := range tests { - var passwd, group io.Reader - - if test.passwd { - passwd = strings.NewReader(passwdContent) - } - - if test.group { - group = strings.NewReader(groupContent) - } - - execUser, err := GetExecUser(test.ref, &defaultExecUser, passwd, group) - if err != nil { - t.Logf("got unexpected error when parsing '%s': %s", test.ref, err.Error()) - t.Fail() - continue - } - - if !reflect.DeepEqual(test.expected, *execUser) { - t.Logf("got: %#v", execUser) - t.Logf("expected: %#v", test.expected) - t.Fail() - continue - } - } -} - -func TestGetAdditionalGroups(t *testing.T) { - const groupContent = ` -root:x:0:root -adm:x:43: -grp:x:1234:root,adm -adm:x:4343:root,adm-duplicate -this is just some garbage data -` - tests := []struct { - groups []string - expected []int - hasError bool - }{ - { - // empty group - groups: []string{}, - expected: []int{}, - }, - { - // single group - groups: []string{"adm"}, - expected: []int{43}, - }, - { - // multiple groups - groups: []string{"adm", "grp"}, - expected: []int{43, 1234}, - }, - { - // invalid group - groups: []string{"adm", "grp", "not-exist"}, - expected: nil, - hasError: true, - }, - { - // group with numeric id - groups: []string{"43"}, - expected: []int{43}, - }, - { - // group with unknown numeric id - groups: []string{"adm", "10001"}, - expected: []int{43, 10001}, - }, - { - // groups specified twice with numeric and name - groups: []string{"adm", "43"}, - expected: []int{43}, - }, - { - // groups with too small id - groups: []string{"-1"}, - expected: nil, - hasError: true, - }, - { - // groups with too large id - groups: []string{strconv.Itoa(1 << 31)}, - expected: nil, - hasError: true, - }, - } - - for _, test := range tests { - group := strings.NewReader(groupContent) - - gids, err := GetAdditionalGroups(test.groups, group) - if test.hasError && err == nil { - t.Errorf("Parse(%#v) expects error but has none", test) - continue - } - if !test.hasError && err != nil { - t.Errorf("Parse(%#v) has error %v", test, err) - continue - } - sort.Sort(sort.IntSlice(gids)) - if !reflect.DeepEqual(gids, test.expected) { - t.Errorf("Gids(%v), expect %v from groups %v", gids, test.expected, test.groups) - } - } -} - -func TestGetAdditionalGroupsNumeric(t *testing.T) { - tests := []struct { - groups []string - expected []int - hasError bool - }{ - { - // numeric groups only - groups: []string{"1234", "5678"}, - expected: []int{1234, 5678}, - }, - { - // numeric and alphabetic - groups: []string{"1234", "fake"}, - expected: nil, - hasError: true, - }, - } - - for _, test := range tests { - gids, err := GetAdditionalGroups(test.groups, nil) - if test.hasError && err == nil { - t.Errorf("Parse(%#v) expects error but has none", test) - continue - } - if !test.hasError && err != nil { - t.Errorf("Parse(%#v) has error %v", test, err) - continue - } - sort.Sort(sort.IntSlice(gids)) - if !reflect.DeepEqual(gids, test.expected) { - t.Errorf("Gids(%v), expect %v from groups %v", gids, test.expected, test.groups) - } - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/utils/utils.go b/vendor/src/github.com/opencontainers/runc/libcontainer/utils/utils.go index 1f5528f..68ae3c4 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/utils/utils.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/utils/utils.go @@ -63,6 +63,11 @@ func WriteJSON(w io.Writer, v interface{}) error { // be a subdirectory of the prefixed path. This is all done lexically, so paths // that include symlinks won't be safe as a result of using CleanPath. func CleanPath(path string) string { + // Deal with empty strings nicely. + if path == "" { + return "" + } + // Ensure that all paths are cleaned (especially problematic ones like // "/../../../../../" which can cause lots of issues). path = filepath.Clean(path) diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/utils/utils_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/utils/utils_test.go deleted file mode 100644 index 813180a..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/utils/utils_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package utils - -import "testing" - -func TestGenerateName(t *testing.T) { - name, err := GenerateRandomName("veth", 5) - if err != nil { - t.Fatal(err) - } - - expected := 5 + len("veth") - if len(name) != expected { - t.Fatalf("expected name to be %d chars but received %d", expected, len(name)) - } - - name, err = GenerateRandomName("veth", 65) - if err != nil { - t.Fatal(err) - } - - expected = 64 + len("veth") - if len(name) != expected { - t.Fatalf("expected name to be %d chars but received %d", expected, len(name)) - } -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/xattr/errors.go b/vendor/src/github.com/opencontainers/runc/libcontainer/xattr/errors.go deleted file mode 100644 index 8cd7741..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/xattr/errors.go +++ /dev/null @@ -1,8 +0,0 @@ -package xattr - -import ( - "fmt" - "runtime" -) - -var ErrNotSupportedPlatform = fmt.Errorf("platform and architecture is not supported %s %s", runtime.GOOS, runtime.GOARCH) diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/xattr/xattr_linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/xattr/xattr_linux.go deleted file mode 100644 index 933a752..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/xattr/xattr_linux.go +++ /dev/null @@ -1,53 +0,0 @@ -// +build linux - -package xattr - -import ( - "syscall" - - "github.com/opencontainers/runc/libcontainer/system" -) - -func XattrEnabled(path string) bool { - if Setxattr(path, "user.test", "") == syscall.ENOTSUP { - return false - } - return true -} - -func stringsfromByte(buf []byte) (result []string) { - offset := 0 - for index, b := range buf { - if b == 0 { - result = append(result, string(buf[offset:index])) - offset = index + 1 - } - } - return -} - -func Listxattr(path string) ([]string, error) { - size, err := system.Llistxattr(path, nil) - if err != nil { - return nil, err - } - buf := make([]byte, size) - read, err := system.Llistxattr(path, buf) - if err != nil { - return nil, err - } - names := stringsfromByte(buf[:read]) - return names, nil -} - -func Getxattr(path, attr string) (string, error) { - value, err := system.Lgetxattr(path, attr) - if err != nil { - return "", err - } - return string(value), nil -} - -func Setxattr(path, xattr, value string) error { - return system.Lsetxattr(path, xattr, []byte(value), 0) -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/xattr/xattr_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/xattr/xattr_test.go deleted file mode 100644 index 1805568..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/xattr/xattr_test.go +++ /dev/null @@ -1,78 +0,0 @@ -// +build linux - -package xattr_test - -import ( - "os" - "testing" - - "github.com/opencontainers/runc/libcontainer/xattr" -) - -func TestXattr(t *testing.T) { - tmp := "xattr_test" - out, err := os.OpenFile(tmp, os.O_WRONLY|os.O_CREATE, 0) - if err != nil { - t.Fatal("failed") - } - defer os.Remove(tmp) - attr := "user.test" - out.Close() - - if !xattr.XattrEnabled(tmp) { - t.Log("Disabled") - t.Fatal("failed") - } - t.Log("Success") - - err = xattr.Setxattr(tmp, attr, "test") - if err != nil { - t.Fatal("failed") - } - - var value string - value, err = xattr.Getxattr(tmp, attr) - if err != nil { - t.Fatal("failed") - } - if value != "test" { - t.Fatal("failed") - } - t.Log("Success") - - var names []string - names, err = xattr.Listxattr(tmp) - if err != nil { - t.Fatal("failed") - } - - var found int - for _, name := range names { - if name == attr { - found = 1 - } - } - // Listxattr doesn't return trusted.* and system.* namespace - // attrs when run in unprevileged mode. - if found != 1 { - t.Fatal("failed") - } - t.Log("Success") - - big := "0000000000000000000000000000000000000000000000000000000000000000000008c6419ad822dfe29283fb3ac98dcc5908810cb31f4cfe690040c42c144b7492eicompslf20dxmlpgz" - // Test for long xattrs larger than 128 bytes - err = xattr.Setxattr(tmp, attr, big) - if err != nil { - t.Fatal("failed to add long value") - } - value, err = xattr.Getxattr(tmp, attr) - if err != nil { - t.Fatal("failed to get long value") - } - t.Log("Success") - - if value != big { - t.Fatal("failed, value doesn't match") - } - t.Log("Success") -} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/xattr/xattr_unsupported.go b/vendor/src/github.com/opencontainers/runc/libcontainer/xattr/xattr_unsupported.go deleted file mode 100644 index 821dea3..0000000 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/xattr/xattr_unsupported.go +++ /dev/null @@ -1,15 +0,0 @@ -// +build !linux - -package xattr - -func Listxattr(path string) ([]string, error) { - return nil, ErrNotSupportedPlatform -} - -func Getxattr(path, attr string) (string, error) { - return "", ErrNotSupportedPlatform -} - -func Setxattr(path, xattr, value string) error { - return ErrNotSupportedPlatform -} diff --git a/vendor/src/github.com/opencontainers/runc/list.go b/vendor/src/github.com/opencontainers/runc/list.go deleted file mode 100644 index 484d2bc..0000000 --- a/vendor/src/github.com/opencontainers/runc/list.go +++ /dev/null @@ -1,71 +0,0 @@ -// +build linux - -package main - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "text/tabwriter" - "time" - - "github.com/Sirupsen/logrus" - "github.com/codegangsta/cli" - "github.com/opencontainers/runc/libcontainer" -) - -var listCommand = cli.Command{ - Name: "list", - Usage: "lists containers started by runc with the given root", - Action: func(context *cli.Context) { - factory, err := loadFactory(context) - if err != nil { - logrus.Fatal(err) - } - // get the list of containers - root := context.GlobalString("root") - absRoot, err := filepath.Abs(root) - if err != nil { - logrus.Fatal(err) - } - list, err := ioutil.ReadDir(absRoot) - if err != nil { - logrus.Fatal(err) - } - w := tabwriter.NewWriter(os.Stdout, 12, 1, 3, ' ', 0) - fmt.Fprint(w, "ID\tPID\tSTATUS\tCREATED\n") - // output containers - for _, item := range list { - if item.IsDir() { - if err := outputListInfo(item.Name(), factory, w); err != nil { - logrus.Fatal(err) - } - } - } - if err := w.Flush(); err != nil { - logrus.Fatal(err) - } - }, -} - -func outputListInfo(id string, factory libcontainer.Factory, w *tabwriter.Writer) error { - container, err := factory.Load(id) - if err != nil { - return err - } - containerStatus, err := container.Status() - if err != nil { - return err - } - state, err := container.State() - if err != nil { - return err - } - fmt.Fprintf(w, "%s\t%d\t%s\t%s\n", - container.ID(), - state.BaseState.InitProcessPid, - containerStatus.String(), - state.BaseState.Created.Format(time.RFC3339Nano)) - return nil -} diff --git a/vendor/src/github.com/opencontainers/runc/main.go b/vendor/src/github.com/opencontainers/runc/main.go deleted file mode 100644 index f6412f8..0000000 --- a/vendor/src/github.com/opencontainers/runc/main.go +++ /dev/null @@ -1,103 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "github.com/Sirupsen/logrus" - "github.com/codegangsta/cli" - "github.com/opencontainers/specs" -) - -const ( - version = "0.0.8" - specConfig = "config.json" - usage = `Open Container Initiative runtime - -runc is a command line client for running applications packaged according to -the Open Container Format (OCF) and is a compliant implementation of the -Open Container Initiative specification. - -runc integrates well with existing process supervisors to provide a production -container runtime environment for applications. It can be used with your -existing process monitoring tools and the container will be spawned as a -direct child of the process supervisor. - -After creating config files for your root filesystem with runc, you can execute -a container in your shell by running: - - # cd /mycontainer - # runc start [ -b bundle ] - -If not specified, the default value for the 'bundle' is the current directory. -'Bundle' is the directory where '` + specConfig + `' must be located.` -) - -func main() { - app := cli.NewApp() - app.Name = "runc" - app.Usage = usage - app.Version = fmt.Sprintf("%s\nspec version %s", version, specs.Version) - app.Flags = []cli.Flag{ - cli.BoolFlag{ - Name: "debug", - Usage: "enable debug output for logging", - }, - cli.StringFlag{ - Name: "log", - Usage: "set the log file path where internal debug information is written", - }, - cli.StringFlag{ - Name: "log-format", - Value: "text", - Usage: "set the format used by logs ('text' (default), or 'json')", - }, - cli.StringFlag{ - Name: "root", - Value: specs.LinuxStateDirectory, - Usage: "root directory for storage of container state (this should be located in tmpfs)", - }, - cli.StringFlag{ - Name: "criu", - Value: "criu", - Usage: "path to the criu binary used for checkpoint and restore", - }, - } - app.Commands = []cli.Command{ - checkpointCommand, - deleteCommand, - eventsCommand, - execCommand, - killCommand, - listCommand, - pauseCommand, - restoreCommand, - resumeCommand, - specCommand, - startCommand, - } - app.Before = func(context *cli.Context) error { - if context.GlobalBool("debug") { - logrus.SetLevel(logrus.DebugLevel) - } - if path := context.GlobalString("log"); path != "" { - f, err := os.Create(path) - if err != nil { - return err - } - logrus.SetOutput(f) - } - switch context.GlobalString("log-format") { - case "text": - // retain logrus's default. - case "json": - logrus.SetFormatter(new(logrus.JSONFormatter)) - default: - logrus.Fatalf("unknown log-format %q", context.GlobalString("log-format")) - } - return nil - } - if err := app.Run(os.Args); err != nil { - logrus.Fatal(err) - } -} diff --git a/vendor/src/github.com/opencontainers/runc/main_unix.go b/vendor/src/github.com/opencontainers/runc/main_unix.go deleted file mode 100644 index 7bbec9f..0000000 --- a/vendor/src/github.com/opencontainers/runc/main_unix.go +++ /dev/null @@ -1,5 +0,0 @@ -// +build linux - -package main - -import _ "github.com/opencontainers/runc/libcontainer/nsenter" diff --git a/vendor/src/github.com/opencontainers/runc/main_unsupported.go b/vendor/src/github.com/opencontainers/runc/main_unsupported.go deleted file mode 100644 index 6100120..0000000 --- a/vendor/src/github.com/opencontainers/runc/main_unsupported.go +++ /dev/null @@ -1,20 +0,0 @@ -// +build !linux - -package main - -import ( - "github.com/Sirupsen/logrus" - "github.com/codegangsta/cli" -) - -var ( - checkpointCommand cli.Command - eventsCommand cli.Command - restoreCommand cli.Command - specCommand cli.Command - killCommand cli.Command -) - -func runAction(*cli.Context) { - logrus.Fatal("Current OS is not supported yet") -} diff --git a/vendor/src/github.com/opencontainers/runc/pause.go b/vendor/src/github.com/opencontainers/runc/pause.go deleted file mode 100644 index 28545c5..0000000 --- a/vendor/src/github.com/opencontainers/runc/pause.go +++ /dev/null @@ -1,33 +0,0 @@ -// +build linux - -package main - -import "github.com/codegangsta/cli" - -var pauseCommand = cli.Command{ - Name: "pause", - Usage: "pause suspends all processes inside the container", - Action: func(context *cli.Context) { - container, err := getContainer(context) - if err != nil { - fatal(err) - } - if err := container.Pause(); err != nil { - fatal(err) - } - }, -} - -var resumeCommand = cli.Command{ - Name: "resume", - Usage: "resumes all processes that have been previously paused", - Action: func(context *cli.Context) { - container, err := getContainer(context) - if err != nil { - fatal(err) - } - if err := container.Resume(); err != nil { - fatal(err) - } - }, -} diff --git a/vendor/src/github.com/opencontainers/runc/restore.go b/vendor/src/github.com/opencontainers/runc/restore.go deleted file mode 100644 index 067c13d..0000000 --- a/vendor/src/github.com/opencontainers/runc/restore.go +++ /dev/null @@ -1,171 +0,0 @@ -// +build linux - -package main - -import ( - "fmt" - "os" - "syscall" - - "github.com/Sirupsen/logrus" - "github.com/codegangsta/cli" - "github.com/opencontainers/runc/libcontainer" - "github.com/opencontainers/runc/libcontainer/configs" - "github.com/opencontainers/specs" -) - -var restoreCommand = cli.Command{ - Name: "restore", - Usage: "restore a container from a previous checkpoint", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "image-path", - Value: "", - Usage: "path to criu image files for restoring", - }, - cli.StringFlag{ - Name: "work-path", - Value: "", - Usage: "path for saving work files and logs", - }, - cli.BoolFlag{ - Name: "tcp-established", - Usage: "allow open tcp connections", - }, - cli.BoolFlag{ - Name: "ext-unix-sk", - Usage: "allow external unix sockets", - }, - cli.BoolFlag{ - Name: "shell-job", - Usage: "allow shell jobs", - }, - cli.BoolFlag{ - Name: "file-locks", - Usage: "handle file locks, for safety", - }, - cli.StringFlag{ - Name: "manage-cgroups-mode", - Value: "", - Usage: "cgroups mode: 'soft' (default), 'full' and 'strict'.", - }, - cli.StringFlag{ - Name: "bundle, b", - Value: "", - Usage: "path to the root of the bundle directory", - }, - cli.BoolFlag{ - Name: "detach,d", - Usage: "detach from the container's process", - }, - cli.StringFlag{ - Name: "pid-file", - Value: "", - Usage: "specify the file to write the process id to", - }, - }, - Action: func(context *cli.Context) { - imagePath := context.String("image-path") - id := context.Args().First() - if id == "" { - fatal(errEmptyID) - } - if imagePath == "" { - imagePath = getDefaultImagePath(context) - } - bundle := context.String("bundle") - if bundle != "" { - if err := os.Chdir(bundle); err != nil { - fatal(err) - } - } - spec, err := loadSpec(specConfig) - if err != nil { - fatal(err) - } - config, err := createLibcontainerConfig(id, spec) - if err != nil { - fatal(err) - } - status, err := restoreContainer(context, spec, config, imagePath) - if err != nil { - fatal(err) - } - os.Exit(status) - }, -} - -func restoreContainer(context *cli.Context, spec *specs.LinuxSpec, config *configs.Config, imagePath string) (code int, err error) { - var ( - rootuid = 0 - id = context.Args().First() - ) - factory, err := loadFactory(context) - if err != nil { - return -1, err - } - container, err := factory.Load(id) - if err != nil { - container, err = factory.Create(id, config) - if err != nil { - return -1, err - } - } - options := criuOptions(context) - - status, err := container.Status() - if err != nil { - logrus.Error(err) - } - if status == libcontainer.Running { - fatal(fmt.Errorf("Container with id %s already running", id)) - } - - setManageCgroupsMode(context, options) - - // ensure that the container is always removed if we were the process - // that created it. - detach := context.Bool("detach") - if !detach { - defer destroy(container) - } - process := &libcontainer.Process{} - tty, err := setupIO(process, rootuid, "", false, detach) - if err != nil { - return -1, err - } - if err := container.Restore(process, options); err != nil { - tty.Close() - return -1, err - } - if pidFile := context.String("pid-file"); pidFile != "" { - if err := createPidFile(pidFile, process); err != nil { - process.Signal(syscall.SIGKILL) - process.Wait() - tty.Close() - return -1, err - } - } - if detach { - return 0, nil - } - handler := newSignalHandler(tty) - defer handler.Close() - return handler.forward(process) -} - -func criuOptions(context *cli.Context) *libcontainer.CriuOpts { - imagePath := getCheckpointImagePath(context) - if err := os.MkdirAll(imagePath, 0655); err != nil { - fatal(err) - } - return &libcontainer.CriuOpts{ - ImagesDirectory: imagePath, - WorkDirectory: context.String("work-path"), - LeaveRunning: context.Bool("leave-running"), - TcpEstablished: context.Bool("tcp-established"), - ExternalUnixConnections: context.Bool("ext-unix-sk"), - ShellJob: context.Bool("shell-job"), - FileLocks: context.Bool("file-locks"), - } -} diff --git a/vendor/src/github.com/opencontainers/runc/rlimit_linux.go b/vendor/src/github.com/opencontainers/runc/rlimit_linux.go deleted file mode 100644 index a296828..0000000 --- a/vendor/src/github.com/opencontainers/runc/rlimit_linux.go +++ /dev/null @@ -1,49 +0,0 @@ -package main - -import "fmt" - -const ( - RLIMIT_CPU = iota // CPU time in sec - RLIMIT_FSIZE // Maximum filesize - RLIMIT_DATA // max data size - RLIMIT_STACK // max stack size - RLIMIT_CORE // max core file size - RLIMIT_RSS // max resident set size - RLIMIT_NPROC // max number of processes - RLIMIT_NOFILE // max number of open files - RLIMIT_MEMLOCK // max locked-in-memory address space - RLIMIT_AS // address space limit - RLIMIT_LOCKS // maximum file locks held - RLIMIT_SIGPENDING // max number of pending signals - RLIMIT_MSGQUEUE // maximum bytes in POSIX mqueues - RLIMIT_NICE // max nice prio allowed to raise to - RLIMIT_RTPRIO // maximum realtime priority - RLIMIT_RTTIME // timeout for RT tasks in us -) - -var rlimitMap = map[string]int{ - "RLIMIT_CPU": RLIMIT_CPU, - "RLIMIT_FSIZE": RLIMIT_FSIZE, - "RLIMIT_DATA": RLIMIT_DATA, - "RLIMIT_STACK": RLIMIT_STACK, - "RLIMIT_CORE": RLIMIT_CORE, - "RLIMIT_RSS": RLIMIT_RSS, - "RLIMIT_NPROC": RLIMIT_NPROC, - "RLIMIT_NOFILE": RLIMIT_NOFILE, - "RLIMIT_MEMLOCK": RLIMIT_MEMLOCK, - "RLIMIT_AS": RLIMIT_AS, - "RLIMIT_LOCKS": RLIMIT_LOCKS, - "RLIMIT_SGPENDING": RLIMIT_SIGPENDING, - "RLIMIT_MSGQUEUE": RLIMIT_MSGQUEUE, - "RLIMIT_NICE": RLIMIT_NICE, - "RLIMIT_RTPRIO": RLIMIT_RTPRIO, - "RLIMIT_RTTIME": RLIMIT_RTTIME, -} - -func strToRlimit(key string) (int, error) { - rl, ok := rlimitMap[key] - if !ok { - return 0, fmt.Errorf("Wrong rlimit value: %s", key) - } - return rl, nil -} diff --git a/vendor/src/github.com/opencontainers/runc/script/.validate b/vendor/src/github.com/opencontainers/runc/script/.validate deleted file mode 100644 index 170d674..0000000 --- a/vendor/src/github.com/opencontainers/runc/script/.validate +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -if [ -z "$VALIDATE_UPSTREAM" ]; then - # this is kind of an expensive check, so let's not do this twice if we - # are running more than one validate bundlescript - - VALIDATE_REPO='https://github.com/opencontainers/runc.git' - VALIDATE_BRANCH='master' - - if [ "$TRAVIS" = 'true' -a "$TRAVIS_PULL_REQUEST" != 'false' ]; then - VALIDATE_REPO="https://github.com/${TRAVIS_REPO_SLUG}.git" - VALIDATE_BRANCH="${TRAVIS_BRANCH}" - fi - - VALIDATE_HEAD="$(git rev-parse --verify HEAD)" - - git fetch -q "$VALIDATE_REPO" "refs/heads/$VALIDATE_BRANCH" - VALIDATE_UPSTREAM="$(git rev-parse --verify FETCH_HEAD)" - - VALIDATE_COMMIT_LOG="$VALIDATE_UPSTREAM..$VALIDATE_HEAD" - VALIDATE_COMMIT_DIFF="$VALIDATE_UPSTREAM...$VALIDATE_HEAD" - - validate_diff() { - if [ "$VALIDATE_UPSTREAM" != "$VALIDATE_HEAD" ]; then - git diff "$VALIDATE_COMMIT_DIFF" "$@" - fi - } - validate_log() { - if [ "$VALIDATE_UPSTREAM" != "$VALIDATE_HEAD" ]; then - git log "$VALIDATE_COMMIT_LOG" "$@" - fi - } -fi diff --git a/vendor/src/github.com/opencontainers/runc/script/test_Dockerfile b/vendor/src/github.com/opencontainers/runc/script/test_Dockerfile deleted file mode 100644 index 2fe7358..0000000 --- a/vendor/src/github.com/opencontainers/runc/script/test_Dockerfile +++ /dev/null @@ -1,32 +0,0 @@ -FROM golang:1.5.3 - -RUN echo "deb http://ftp.us.debian.org/debian testing main contrib" >> /etc/apt/sources.list -RUN apt-get update && apt-get install -y \ - build-essential \ - curl \ - iptables \ - libaio-dev \ - libcap-dev \ - libprotobuf-dev \ - libprotobuf-c0-dev \ - libseccomp2 \ - libseccomp-dev \ - protobuf-c-compiler \ - protobuf-compiler \ - python-minimal \ - --no-install-recommends - -# install criu -ENV CRIU_VERSION 1.7 -RUN mkdir -p /usr/src/criu \ - && curl -sSL https://github.com/xemul/criu/archive/v${CRIU_VERSION}.tar.gz | tar -v -C /usr/src/criu/ -xz --strip-components=1 \ - && cd /usr/src/criu \ - && make install-criu - -# setup a playground for us to spawn containers in -RUN mkdir /busybox && \ - curl -sSL 'https://github.com/jpetazzo/docker-busybox/raw/buildroot-2014.11/rootfs.tar' | tar -xC /busybox - -COPY script/tmpmount / -WORKDIR /go/src/github.com/opencontainers/runc -ENTRYPOINT ["/tmpmount"] diff --git a/vendor/src/github.com/opencontainers/runc/script/tmpmount b/vendor/src/github.com/opencontainers/runc/script/tmpmount deleted file mode 100755 index 5ac6bc2..0000000 --- a/vendor/src/github.com/opencontainers/runc/script/tmpmount +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -mount -t tmpfs none /tmp -exec "$@" diff --git a/vendor/src/github.com/opencontainers/runc/script/validate-gofmt b/vendor/src/github.com/opencontainers/runc/script/validate-gofmt deleted file mode 100755 index c565976..0000000 --- a/vendor/src/github.com/opencontainers/runc/script/validate-gofmt +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -source "$(dirname "$BASH_SOURCE")/.validate" - -IFS=$'\n' -files=( $(validate_diff --diff-filter=ACMR --name-only -- '*.go' | grep -v '^Godeps/' || true) ) -unset IFS - -badFiles=() -for f in "${files[@]}"; do - # we use "git show" here to validate that what's committed is formatted - if [ "$(git show "$VALIDATE_HEAD:$f" | gofmt -s -l)" ]; then - badFiles+=( "$f" ) - fi -done - -if [ ${#badFiles[@]} -eq 0 ]; then - echo 'Congratulations! All Go source files are properly formatted.' -else - { - echo "These files are not properly gofmt'd:" - for f in "${badFiles[@]}"; do - echo " - $f" - done - echo - echo 'Please reformat the above files using "gofmt -s -w" and commit the result.' - echo - } >&2 - false -fi diff --git a/vendor/src/github.com/opencontainers/runc/signals.go b/vendor/src/github.com/opencontainers/runc/signals.go deleted file mode 100644 index 3a06d29..0000000 --- a/vendor/src/github.com/opencontainers/runc/signals.go +++ /dev/null @@ -1,113 +0,0 @@ -// +build linux - -package main - -import ( - "os" - "os/signal" - "syscall" - - "github.com/Sirupsen/logrus" - "github.com/opencontainers/runc/libcontainer" - "github.com/opencontainers/runc/libcontainer/utils" -) - -const signalBufferSize = 2048 - -// newSignalHandler returns a signal handler for processing SIGCHLD and SIGWINCH signals -// while still forwarding all other signals to the process. -func newSignalHandler(tty *tty) *signalHandler { - // ensure that we have a large buffer size so that we do not miss any signals - // incase we are not processing them fast enough. - s := make(chan os.Signal, signalBufferSize) - // handle all signals for the process. - signal.Notify(s) - return &signalHandler{ - tty: tty, - signals: s, - } -} - -// exit models a process exit status with the pid and -// exit status. -type exit struct { - pid int - status int -} - -type signalHandler struct { - signals chan os.Signal - tty *tty -} - -// forward handles the main signal event loop forwarding, resizing, or reaping depending -// on the signal received. -func (h *signalHandler) forward(process *libcontainer.Process) (int, error) { - // make sure we know the pid of our main process so that we can return - // after it dies. - pid1, err := process.Pid() - if err != nil { - return -1, err - } - // perform the initial tty resize. - h.tty.resize() - for s := range h.signals { - switch s { - case syscall.SIGWINCH: - h.tty.resize() - case syscall.SIGCHLD: - exits, err := h.reap() - if err != nil { - logrus.Error(err) - } - for _, e := range exits { - logrus.WithFields(logrus.Fields{ - "pid": e.pid, - "status": e.status, - }).Debug("process exited") - if e.pid == pid1 { - // call Wait() on the process even though we already have the exit - // status because we must ensure that any of the go specific process - // fun such as flushing pipes are complete before we return. - process.Wait() - return e.status, nil - } - } - default: - logrus.Debugf("sending signal to process %s", s) - if err := syscall.Kill(pid1, s.(syscall.Signal)); err != nil { - logrus.Error(err) - } - } - } - return -1, nil -} - -// reap runs wait4 in a loop until we have finished processing any existing exits -// then returns all exits to the main event loop for further processing. -func (h *signalHandler) reap() (exits []exit, err error) { - var ( - ws syscall.WaitStatus - rus syscall.Rusage - ) - for { - pid, err := syscall.Wait4(-1, &ws, syscall.WNOHANG, &rus) - if err != nil { - if err == syscall.ECHILD { - return exits, nil - } - return nil, err - } - if pid <= 0 { - return exits, nil - } - exits = append(exits, exit{ - pid: pid, - status: utils.ExitStatus(ws), - }) - } -} - -func (h *signalHandler) Close() error { - return h.tty.Close() -} diff --git a/vendor/src/github.com/opencontainers/runc/spec.go b/vendor/src/github.com/opencontainers/runc/spec.go deleted file mode 100644 index 2836e7c..0000000 --- a/vendor/src/github.com/opencontainers/runc/spec.go +++ /dev/null @@ -1,783 +0,0 @@ -// +build linux - -package main - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "runtime" - "strconv" - "strings" - "syscall" - - "github.com/Sirupsen/logrus" - "github.com/codegangsta/cli" - "github.com/opencontainers/runc/libcontainer/cgroups" - "github.com/opencontainers/runc/libcontainer/configs" - "github.com/opencontainers/runc/libcontainer/seccomp" - libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils" - "github.com/opencontainers/specs" -) - -var specCommand = cli.Command{ - Name: "spec", - Usage: "create a new specification file", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "bundle, b", - Value: "", - Usage: "path to the root of the bundle directory", - }, - }, - Action: func(context *cli.Context) { - spec := specs.LinuxSpec{ - Spec: specs.Spec{ - Version: specs.Version, - Platform: specs.Platform{ - OS: runtime.GOOS, - Arch: runtime.GOARCH, - }, - Root: specs.Root{ - Path: "rootfs", - Readonly: true, - }, - Process: specs.Process{ - Terminal: true, - User: specs.User{}, - Args: []string{ - "sh", - }, - Env: []string{ - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - "TERM=xterm", - }, - Cwd: "/", - }, - Hostname: "shell", - Mounts: []specs.Mount{ - { - Destination: "/proc", - Type: "proc", - Source: "proc", - Options: nil, - }, - { - Destination: "/dev", - Type: "tmpfs", - Source: "tmpfs", - Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"}, - }, - { - Destination: "/dev/pts", - Type: "devpts", - Source: "devpts", - Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"}, - }, - { - Destination: "/dev/shm", - Type: "tmpfs", - Source: "shm", - Options: []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"}, - }, - { - Destination: "/dev/mqueue", - Type: "mqueue", - Source: "mqueue", - Options: []string{"nosuid", "noexec", "nodev"}, - }, - { - Destination: "/sys", - Type: "sysfs", - Source: "sysfs", - Options: []string{"nosuid", "noexec", "nodev"}, - }, - { - Destination: "/sys/fs/cgroup", - Type: "cgroup", - Source: "cgroup", - Options: []string{"nosuid", "noexec", "nodev", "relatime", "ro"}, - }, - }, - }, - Linux: specs.Linux{ - Capabilities: []string{ - "CAP_AUDIT_WRITE", - "CAP_KILL", - "CAP_NET_BIND_SERVICE", - }, - Resources: &specs.Resources{ - Devices: []specs.DeviceCgroup{ - { - Allow: false, - Access: sPtr("rwm"), - }, - }, - }, - Namespaces: []specs.Namespace{ - { - Type: "pid", - }, - { - Type: "network", - }, - { - Type: "ipc", - }, - { - Type: "uts", - }, - { - Type: "mount", - }, - }, - Rlimits: []specs.Rlimit{ - { - Type: "RLIMIT_NOFILE", - Hard: uint64(1024), - Soft: uint64(1024), - }, - }, - }, - } - - checkNoFile := func(name string) error { - _, err := os.Stat(name) - if err == nil { - return fmt.Errorf("File %s exists. Remove it first", name) - } - if !os.IsNotExist(err) { - return err - } - return nil - } - bundle := context.String("bundle") - if bundle != "" { - if err := os.Chdir(bundle); err != nil { - fatal(err) - } - } - if err := checkNoFile(specConfig); err != nil { - logrus.Fatal(err) - } - data, err := json.MarshalIndent(&spec, "", "\t") - if err != nil { - logrus.Fatal(err) - } - if err := ioutil.WriteFile(specConfig, data, 0666); err != nil { - logrus.Fatal(err) - } - }, -} - -func sPtr(s string) *string { return &s } -func rPtr(r rune) *rune { return &r } -func iPtr(i int64) *int64 { return &i } -func u32Ptr(i int64) *uint32 { u := uint32(i); return &u } -func fmPtr(i int64) *os.FileMode { fm := os.FileMode(i); return &fm } - -var namespaceMapping = map[specs.NamespaceType]configs.NamespaceType{ - specs.PIDNamespace: configs.NEWPID, - specs.NetworkNamespace: configs.NEWNET, - specs.MountNamespace: configs.NEWNS, - specs.UserNamespace: configs.NEWUSER, - specs.IPCNamespace: configs.NEWIPC, - specs.UTSNamespace: configs.NEWUTS, -} - -var mountPropagationMapping = map[string]int{ - "rprivate": syscall.MS_PRIVATE | syscall.MS_REC, - "private": syscall.MS_PRIVATE, - "rslave": syscall.MS_SLAVE | syscall.MS_REC, - "slave": syscall.MS_SLAVE, - "rshared": syscall.MS_SHARED | syscall.MS_REC, - "shared": syscall.MS_SHARED, - "": syscall.MS_PRIVATE | syscall.MS_REC, -} - -// validateSpec validates the fields in the spec -// TODO: Add validation for other fields where applicable -func validateSpec(spec *specs.LinuxSpec) error { - if spec.Process.Cwd == "" { - return fmt.Errorf("Cwd property must not be empty") - } - if !filepath.IsAbs(spec.Process.Cwd) { - return fmt.Errorf("Cwd must be an absolute path") - } - return nil -} - -// loadSpec loads the specification from the provided path. -// If the path is empty then the default path will be "config.json" -func loadSpec(cPath string) (spec *specs.LinuxSpec, err error) { - cf, err := os.Open(cPath) - if err != nil { - if os.IsNotExist(err) { - return nil, fmt.Errorf("JSON specification file %s not found", cPath) - } - return spec, err - } - defer cf.Close() - - if err = json.NewDecoder(cf).Decode(&spec); err != nil { - return spec, err - } - return spec, validateSpec(spec) -} - -func createLibcontainerConfig(cgroupName string, spec *specs.LinuxSpec) (*configs.Config, error) { - cwd, err := os.Getwd() - if err != nil { - return nil, err - } - rootfsPath := spec.Root.Path - if !filepath.IsAbs(rootfsPath) { - rootfsPath = filepath.Join(cwd, rootfsPath) - } - config := &configs.Config{ - Rootfs: rootfsPath, - Capabilities: spec.Linux.Capabilities, - Readonlyfs: spec.Root.Readonly, - Hostname: spec.Hostname, - } - - exists := false - if config.RootPropagation, exists = mountPropagationMapping[spec.Linux.RootfsPropagation]; !exists { - return nil, fmt.Errorf("rootfsPropagation=%v is not supported", spec.Linux.RootfsPropagation) - } - - for _, ns := range spec.Linux.Namespaces { - t, exists := namespaceMapping[ns.Type] - if !exists { - return nil, fmt.Errorf("namespace %q does not exist", ns) - } - config.Namespaces.Add(t, ns.Path) - } - if config.Namespaces.Contains(configs.NEWNET) { - config.Networks = []*configs.Network{ - { - Type: "loopback", - }, - } - } - for _, m := range spec.Mounts { - config.Mounts = append(config.Mounts, createLibcontainerMount(cwd, m)) - } - if err := createDevices(spec, config); err != nil { - return nil, err - } - if err := setupUserNamespace(spec, config); err != nil { - return nil, err - } - for _, rlimit := range spec.Linux.Rlimits { - rl, err := createLibContainerRlimit(rlimit) - if err != nil { - return nil, err - } - config.Rlimits = append(config.Rlimits, rl) - } - c, err := createCgroupConfig(cgroupName, spec) - if err != nil { - return nil, err - } - config.Cgroups = c - if config.Readonlyfs { - setReadonly(config) - config.MaskPaths = []string{ - "/proc/kcore", - } - config.ReadonlyPaths = []string{ - "/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus", - } - } - seccomp, err := setupSeccomp(&spec.Linux.Seccomp) - if err != nil { - return nil, err - } - config.Seccomp = seccomp - config.Sysctl = spec.Linux.Sysctl - config.ProcessLabel = spec.Linux.SelinuxProcessLabel - config.AppArmorProfile = spec.Linux.ApparmorProfile - for _, g := range spec.Process.User.AdditionalGids { - config.AdditionalGroups = append(config.AdditionalGroups, strconv.FormatUint(uint64(g), 10)) - } - createHooks(spec, config) - config.Version = specs.Version - return config, nil -} - -func createLibcontainerMount(cwd string, m specs.Mount) *configs.Mount { - flags, pgflags, data := parseMountOptions(m.Options) - source := m.Source - if m.Type == "bind" { - if !filepath.IsAbs(source) { - source = filepath.Join(cwd, m.Source) - } - } - return &configs.Mount{ - Device: m.Type, - Source: source, - Destination: m.Destination, - Data: data, - Flags: flags, - PropagationFlags: pgflags, - } -} - -func createCgroupConfig(name string, spec *specs.LinuxSpec) (*configs.Cgroup, error) { - var ( - err error - myCgroupPath string - ) - - if spec.Linux.CgroupsPath != nil { - myCgroupPath = libcontainerUtils.CleanPath(*spec.Linux.CgroupsPath) - } else { - myCgroupPath, err = cgroups.GetThisCgroupDir("devices") - if err != nil { - return nil, err - } - } - - c := &configs.Cgroup{ - Path: filepath.Join(myCgroupPath, name), - Resources: &configs.Resources{}, - } - c.Resources.AllowedDevices = allowedDevices - r := spec.Linux.Resources - if r == nil { - return c, nil - } - for i, d := range spec.Linux.Resources.Devices { - var ( - t = 'a' - major = int64(-1) - minor = int64(-1) - ) - if d.Type != nil { - t = *d.Type - } - if d.Major != nil { - major = *d.Major - } - if d.Minor != nil { - minor = *d.Minor - } - if d.Access == nil || *d.Access == "" { - return nil, fmt.Errorf("device access at %d field canot be empty", i) - } - dd := &configs.Device{ - Type: t, - Major: major, - Minor: minor, - Permissions: *d.Access, - Allow: d.Allow, - } - c.Resources.Devices = append(c.Resources.Devices, dd) - } - // append the default allowed devices to the end of the list - c.Resources.Devices = append(c.Resources.Devices, allowedDevices...) - if r.Memory != nil { - if r.Memory.Limit != nil { - c.Resources.Memory = int64(*r.Memory.Limit) - } - if r.Memory.Reservation != nil { - c.Resources.MemoryReservation = int64(*r.Memory.Reservation) - } - if r.Memory.Swap != nil { - c.Resources.MemorySwap = int64(*r.Memory.Swap) - } - if r.Memory.Kernel != nil { - c.Resources.KernelMemory = int64(*r.Memory.Kernel) - } - if r.Memory.Swappiness != nil { - c.Resources.MemorySwappiness = int64(*r.Memory.Swappiness) - } - } - if r.CPU != nil { - if r.CPU.Shares != nil { - c.Resources.CpuShares = int64(*r.CPU.Shares) - } - if r.CPU.Quota != nil { - c.Resources.CpuQuota = int64(*r.CPU.Quota) - } - if r.CPU.Period != nil { - c.Resources.CpuPeriod = int64(*r.CPU.Period) - } - if r.CPU.RealtimeRuntime != nil { - c.Resources.CpuRtRuntime = int64(*r.CPU.RealtimeRuntime) - } - if r.CPU.RealtimePeriod != nil { - c.Resources.CpuRtPeriod = int64(*r.CPU.RealtimePeriod) - } - if r.CPU.Cpus != nil { - c.Resources.CpusetCpus = *r.CPU.Cpus - } - if r.CPU.Mems != nil { - c.Resources.CpusetMems = *r.CPU.Mems - } - } - if r.Pids != nil { - c.Resources.PidsLimit = *r.Pids.Limit - } - if r.BlockIO != nil { - if r.BlockIO.Weight != nil { - c.Resources.BlkioWeight = *r.BlockIO.Weight - } - if r.BlockIO.LeafWeight != nil { - c.Resources.BlkioLeafWeight = *r.BlockIO.LeafWeight - } - if r.BlockIO.WeightDevice != nil { - for _, wd := range r.BlockIO.WeightDevice { - weightDevice := configs.NewWeightDevice(wd.Major, wd.Minor, *wd.Weight, *wd.LeafWeight) - c.Resources.BlkioWeightDevice = append(c.Resources.BlkioWeightDevice, weightDevice) - } - } - if r.BlockIO.ThrottleReadBpsDevice != nil { - for _, td := range r.BlockIO.ThrottleReadBpsDevice { - throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, *td.Rate) - c.Resources.BlkioThrottleReadBpsDevice = append(c.Resources.BlkioThrottleReadBpsDevice, throttleDevice) - } - } - if r.BlockIO.ThrottleWriteBpsDevice != nil { - for _, td := range r.BlockIO.ThrottleWriteBpsDevice { - throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, *td.Rate) - c.Resources.BlkioThrottleWriteBpsDevice = append(c.Resources.BlkioThrottleWriteBpsDevice, throttleDevice) - } - } - if r.BlockIO.ThrottleReadIOPSDevice != nil { - for _, td := range r.BlockIO.ThrottleReadIOPSDevice { - throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, *td.Rate) - c.Resources.BlkioThrottleReadIOPSDevice = append(c.Resources.BlkioThrottleReadIOPSDevice, throttleDevice) - } - } - if r.BlockIO.ThrottleWriteIOPSDevice != nil { - for _, td := range r.BlockIO.ThrottleWriteIOPSDevice { - throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, *td.Rate) - c.Resources.BlkioThrottleWriteIOPSDevice = append(c.Resources.BlkioThrottleWriteIOPSDevice, throttleDevice) - } - } - } - for _, l := range r.HugepageLimits { - c.Resources.HugetlbLimit = append(c.Resources.HugetlbLimit, &configs.HugepageLimit{ - Pagesize: *l.Pagesize, - Limit: *l.Limit, - }) - } - if r.DisableOOMKiller != nil { - c.Resources.OomKillDisable = *r.DisableOOMKiller - } - if r.Network != nil { - if r.Network.ClassID != nil { - c.Resources.NetClsClassid = string(*r.Network.ClassID) - } - for _, m := range r.Network.Priorities { - c.Resources.NetPrioIfpriomap = append(c.Resources.NetPrioIfpriomap, &configs.IfPrioMap{ - Interface: m.Name, - Priority: int64(m.Priority), - }) - } - } - return c, nil -} - -func createDevices(spec *specs.LinuxSpec, config *configs.Config) error { - // add whitelisted devices - config.Devices = []*configs.Device{ - { - Type: 'c', - Path: "/dev/null", - Major: 1, - Minor: 3, - FileMode: 0666, - Uid: 0, - Gid: 0, - }, - { - Type: 'c', - Path: "/dev/random", - Major: 1, - Minor: 8, - FileMode: 0666, - Uid: 0, - Gid: 0, - }, - { - Type: 'c', - Path: "/dev/full", - Major: 1, - Minor: 7, - FileMode: 0666, - Uid: 0, - Gid: 0, - }, - { - Type: 'c', - Path: "/dev/tty", - Major: 5, - Minor: 0, - FileMode: 0666, - Uid: 0, - Gid: 0, - }, - { - Type: 'c', - Path: "/dev/zero", - Major: 1, - Minor: 5, - FileMode: 0666, - Uid: 0, - Gid: 0, - }, - { - Type: 'c', - Path: "/dev/urandom", - Major: 1, - Minor: 9, - FileMode: 0666, - Uid: 0, - Gid: 0, - }, - } - // merge in additional devices from the spec - for _, d := range spec.Linux.Devices { - var uid, gid uint32 - if d.UID != nil { - uid = *d.UID - } - if d.GID != nil { - gid = *d.GID - } - device := &configs.Device{ - Type: d.Type, - Path: d.Path, - Major: d.Major, - Minor: d.Minor, - FileMode: *d.FileMode, - Uid: uid, - Gid: gid, - } - config.Devices = append(config.Devices, device) - } - return nil -} - -func setReadonly(config *configs.Config) { - for _, m := range config.Mounts { - if m.Device == "sysfs" { - m.Flags |= syscall.MS_RDONLY - } - } -} - -func setupUserNamespace(spec *specs.LinuxSpec, config *configs.Config) error { - if len(spec.Linux.UIDMappings) == 0 { - return nil - } - config.Namespaces.Add(configs.NEWUSER, "") - create := func(m specs.IDMapping) configs.IDMap { - return configs.IDMap{ - HostID: int(m.HostID), - ContainerID: int(m.ContainerID), - Size: int(m.Size), - } - } - for _, m := range spec.Linux.UIDMappings { - config.UidMappings = append(config.UidMappings, create(m)) - } - for _, m := range spec.Linux.GIDMappings { - config.GidMappings = append(config.GidMappings, create(m)) - } - rootUID, err := config.HostUID() - if err != nil { - return err - } - rootGID, err := config.HostGID() - if err != nil { - return err - } - for _, node := range config.Devices { - node.Uid = uint32(rootUID) - node.Gid = uint32(rootGID) - } - return nil -} - -func createLibContainerRlimit(rlimit specs.Rlimit) (configs.Rlimit, error) { - rl, err := strToRlimit(rlimit.Type) - if err != nil { - return configs.Rlimit{}, err - } - return configs.Rlimit{ - Type: rl, - Hard: uint64(rlimit.Hard), - Soft: uint64(rlimit.Soft), - }, nil -} - -// parseMountOptions parses the string and returns the flags, propagation -// flags and any mount data that it contains. -func parseMountOptions(options []string) (int, []int, string) { - var ( - flag int - pgflag []int - data []string - ) - flags := map[string]struct { - clear bool - flag int - }{ - "async": {true, syscall.MS_SYNCHRONOUS}, - "atime": {true, syscall.MS_NOATIME}, - "bind": {false, syscall.MS_BIND}, - "defaults": {false, 0}, - "dev": {true, syscall.MS_NODEV}, - "diratime": {true, syscall.MS_NODIRATIME}, - "dirsync": {false, syscall.MS_DIRSYNC}, - "exec": {true, syscall.MS_NOEXEC}, - "mand": {false, syscall.MS_MANDLOCK}, - "noatime": {false, syscall.MS_NOATIME}, - "nodev": {false, syscall.MS_NODEV}, - "nodiratime": {false, syscall.MS_NODIRATIME}, - "noexec": {false, syscall.MS_NOEXEC}, - "nomand": {true, syscall.MS_MANDLOCK}, - "norelatime": {true, syscall.MS_RELATIME}, - "nostrictatime": {true, syscall.MS_STRICTATIME}, - "nosuid": {false, syscall.MS_NOSUID}, - "rbind": {false, syscall.MS_BIND | syscall.MS_REC}, - "relatime": {false, syscall.MS_RELATIME}, - "remount": {false, syscall.MS_REMOUNT}, - "ro": {false, syscall.MS_RDONLY}, - "rw": {true, syscall.MS_RDONLY}, - "strictatime": {false, syscall.MS_STRICTATIME}, - "suid": {true, syscall.MS_NOSUID}, - "sync": {false, syscall.MS_SYNCHRONOUS}, - } - propagationFlags := map[string]struct { - clear bool - flag int - }{ - "private": {false, syscall.MS_PRIVATE}, - "shared": {false, syscall.MS_SHARED}, - "slave": {false, syscall.MS_SLAVE}, - "unbindable": {false, syscall.MS_UNBINDABLE}, - "rprivate": {false, syscall.MS_PRIVATE | syscall.MS_REC}, - "rshared": {false, syscall.MS_SHARED | syscall.MS_REC}, - "rslave": {false, syscall.MS_SLAVE | syscall.MS_REC}, - "runbindable": {false, syscall.MS_UNBINDABLE | syscall.MS_REC}, - } - for _, o := range options { - // If the option does not exist in the flags table or the flag - // is not supported on the platform, - // then it is a data value for a specific fs type - if f, exists := flags[o]; exists && f.flag != 0 { - if f.clear { - flag &= ^f.flag - } else { - flag |= f.flag - } - } else if f, exists := propagationFlags[o]; exists && f.flag != 0 { - pgflag = append(pgflag, f.flag) - } else { - data = append(data, o) - } - } - return flag, pgflag, strings.Join(data, ",") -} - -func setupSeccomp(config *specs.Seccomp) (*configs.Seccomp, error) { - if config == nil { - return nil, nil - } - - // No default action specified, no syscalls listed, assume seccomp disabled - if config.DefaultAction == "" && len(config.Syscalls) == 0 { - return nil, nil - } - - newConfig := new(configs.Seccomp) - newConfig.Syscalls = []*configs.Syscall{} - - if len(config.Architectures) > 0 { - newConfig.Architectures = []string{} - for _, arch := range config.Architectures { - newArch, err := seccomp.ConvertStringToArch(string(arch)) - if err != nil { - return nil, err - } - newConfig.Architectures = append(newConfig.Architectures, newArch) - } - } - - // Convert default action from string representation - newDefaultAction, err := seccomp.ConvertStringToAction(string(config.DefaultAction)) - if err != nil { - return nil, err - } - newConfig.DefaultAction = newDefaultAction - - // Loop through all syscall blocks and convert them to libcontainer format - for _, call := range config.Syscalls { - newAction, err := seccomp.ConvertStringToAction(string(call.Action)) - if err != nil { - return nil, err - } - - newCall := configs.Syscall{ - Name: call.Name, - Action: newAction, - Args: []*configs.Arg{}, - } - - // Loop through all the arguments of the syscall and convert them - for _, arg := range call.Args { - newOp, err := seccomp.ConvertStringToOperator(string(arg.Op)) - if err != nil { - return nil, err - } - - newArg := configs.Arg{ - Index: arg.Index, - Value: arg.Value, - ValueTwo: arg.ValueTwo, - Op: newOp, - } - - newCall.Args = append(newCall.Args, &newArg) - } - - newConfig.Syscalls = append(newConfig.Syscalls, &newCall) - } - - return newConfig, nil -} - -func createHooks(rspec *specs.LinuxSpec, config *configs.Config) { - config.Hooks = &configs.Hooks{} - for _, h := range rspec.Hooks.Prestart { - cmd := configs.Command{ - Path: h.Path, - Args: h.Args, - Env: h.Env, - } - config.Hooks.Prestart = append(config.Hooks.Prestart, configs.NewCommandHook(cmd)) - } - for _, h := range rspec.Hooks.Poststart { - cmd := configs.Command{ - Path: h.Path, - Args: h.Args, - Env: h.Env, - } - config.Hooks.Poststart = append(config.Hooks.Poststart, configs.NewCommandHook(cmd)) - } - for _, h := range rspec.Hooks.Poststop { - cmd := configs.Command{ - Path: h.Path, - Args: h.Args, - Env: h.Env, - } - config.Hooks.Poststop = append(config.Hooks.Poststop, configs.NewCommandHook(cmd)) - } -} diff --git a/vendor/src/github.com/opencontainers/runc/start.go b/vendor/src/github.com/opencontainers/runc/start.go deleted file mode 100644 index 6d8238e..0000000 --- a/vendor/src/github.com/opencontainers/runc/start.go +++ /dev/null @@ -1,108 +0,0 @@ -// +build linux - -package main - -import ( - "os" - "runtime" - - "github.com/Sirupsen/logrus" - "github.com/codegangsta/cli" - "github.com/coreos/go-systemd/activation" - "github.com/opencontainers/runc/libcontainer" - "github.com/opencontainers/specs" -) - -// default action is to start a container -var startCommand = cli.Command{ - Name: "start", - Usage: "create and run a container", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "bundle, b", - Value: "", - Usage: "path to the root of the bundle directory", - }, - cli.StringFlag{ - Name: "console", - Value: "", - Usage: "specify the pty slave path for use with the container", - }, - cli.BoolFlag{ - Name: "detach,d", - Usage: "detach from the container's process", - }, - cli.StringFlag{ - Name: "pid-file", - Value: "", - Usage: "specify the file to write the process id to", - }, - }, - Action: func(context *cli.Context) { - bundle := context.String("bundle") - if bundle != "" { - if err := os.Chdir(bundle); err != nil { - fatal(err) - } - } - spec, err := loadSpec(specConfig) - if err != nil { - fatal(err) - } - - notifySocket := os.Getenv("NOTIFY_SOCKET") - if notifySocket != "" { - setupSdNotify(spec, notifySocket) - } - - if os.Geteuid() != 0 { - logrus.Fatal("runc should be run as root") - } - - status, err := startContainer(context, spec) - if err != nil { - logrus.Fatalf("Container start failed: %v", err) - } - // exit with the container's exit status so any external supervisor is - // notified of the exit with the correct exit status. - os.Exit(status) - }, -} - -func init() { - if len(os.Args) > 1 && os.Args[1] == "init" { - runtime.GOMAXPROCS(1) - runtime.LockOSThread() - factory, _ := libcontainer.New("") - if err := factory.StartInitialization(); err != nil { - fatal(err) - } - panic("--this line should have never been executed, congratulations--") - } -} - -func startContainer(context *cli.Context, spec *specs.LinuxSpec) (int, error) { - id := context.Args().First() - if id == "" { - return -1, errEmptyID - } - container, err := createContainer(context, id, spec) - if err != nil { - return -1, err - } - - // ensure that the container is always removed if we were the process - // that created it. - detach := context.Bool("detach") - if !detach { - defer destroy(container) - } - - // Support on-demand socket activation by passing file descriptors into the container init process. - listenFDs := []*os.File{} - if os.Getenv("LISTEN_FDS") != "" { - listenFDs = activation.Files(false) - } - - return runProcess(container, &spec.Process, listenFDs, context.String("console"), context.String("pid-file"), detach) -} diff --git a/vendor/src/github.com/opencontainers/runc/tty.go b/vendor/src/github.com/opencontainers/runc/tty.go deleted file mode 100644 index b552621..0000000 --- a/vendor/src/github.com/opencontainers/runc/tty.go +++ /dev/null @@ -1,100 +0,0 @@ -// +build linux - -package main - -import ( - "fmt" - "io" - "os" - - "github.com/docker/docker/pkg/term" - "github.com/opencontainers/runc/libcontainer" -) - -// newTty creates a new tty for use with the container. If a tty is not to be -// created for the process, pipes are created so that the TTY of the parent -// process are not inherited by the container. -func newTty(create bool, p *libcontainer.Process, rootuid int, console string) (*tty, error) { - if create { - return createTty(p, rootuid, console) - } - return createStdioPipes(p, rootuid) -} - -// setup standard pipes so that the TTY of the calling runc process -// is not inherited by the container. -func createStdioPipes(p *libcontainer.Process, rootuid int) (*tty, error) { - i, err := p.InitializeIO(rootuid) - if err != nil { - return nil, err - } - t := &tty{ - closers: []io.Closer{ - i.Stdin, - i.Stdout, - i.Stderr, - }, - } - go func() { - io.Copy(i.Stdin, os.Stdin) - i.Stdin.Close() - }() - go io.Copy(os.Stdout, i.Stdout) - go io.Copy(os.Stderr, i.Stderr) - return t, nil -} - -func createTty(p *libcontainer.Process, rootuid int, consolePath string) (*tty, error) { - if consolePath != "" { - if err := p.ConsoleFromPath(consolePath); err != nil { - return nil, err - } - return &tty{}, nil - } - console, err := p.NewConsole(rootuid) - if err != nil { - return nil, err - } - go io.Copy(console, os.Stdin) - go io.Copy(os.Stdout, console) - - state, err := term.SetRawTerminal(os.Stdin.Fd()) - if err != nil { - return nil, fmt.Errorf("failed to set the terminal from the stdin: %v", err) - } - t := &tty{ - console: console, - state: state, - closers: []io.Closer{ - console, - }, - } - return t, nil -} - -type tty struct { - console libcontainer.Console - state *term.State - closers []io.Closer -} - -func (t *tty) Close() error { - for _, c := range t.closers { - c.Close() - } - if t.state != nil { - term.RestoreTerminal(os.Stdin.Fd(), t.state) - } - return nil -} - -func (t *tty) resize() error { - if t.console == nil { - return nil - } - ws, err := term.GetWinsize(os.Stdin.Fd()) - if err != nil { - return err - } - return term.SetWinsize(t.console.Fd(), ws) -} diff --git a/vendor/src/github.com/opencontainers/runc/utils.go b/vendor/src/github.com/opencontainers/runc/utils.go deleted file mode 100644 index fe52b1b..0000000 --- a/vendor/src/github.com/opencontainers/runc/utils.go +++ /dev/null @@ -1,330 +0,0 @@ -// +build linux - -package main - -import ( - "errors" - "fmt" - "os" - "path/filepath" - "syscall" - - "github.com/Sirupsen/logrus" - "github.com/codegangsta/cli" - "github.com/opencontainers/runc/libcontainer" - "github.com/opencontainers/runc/libcontainer/configs" - "github.com/opencontainers/specs" -) - -const wildcard = -1 - -var errEmptyID = errors.New("container id cannot be empty") - -var allowedDevices = []*configs.Device{ - // allow mknod for any device - { - Type: 'c', - Major: wildcard, - Minor: wildcard, - Permissions: "m", - Allow: true, - }, - { - Type: 'b', - Major: wildcard, - Minor: wildcard, - Permissions: "m", - Allow: true, - }, - { - Type: 'c', - Path: "/dev/null", - Major: 1, - Minor: 3, - Permissions: "rwm", - Allow: true, - }, - { - Type: 'c', - Path: "/dev/random", - Major: 1, - Minor: 8, - Permissions: "rwm", - Allow: true, - }, - { - Type: 'c', - Path: "/dev/full", - Major: 1, - Minor: 7, - Permissions: "rwm", - Allow: true, - }, - { - Type: 'c', - Path: "/dev/tty", - Major: 5, - Minor: 0, - Permissions: "rwm", - Allow: true, - }, - { - Type: 'c', - Path: "/dev/zero", - Major: 1, - Minor: 5, - Permissions: "rwm", - Allow: true, - }, - { - Type: 'c', - Path: "/dev/urandom", - Major: 1, - Minor: 9, - Permissions: "rwm", - Allow: true, - }, - { - Path: "/dev/console", - Type: 'c', - Major: 5, - Minor: 1, - Permissions: "rwm", - Allow: true, - }, - { - Path: "/dev/tty0", - Type: 'c', - Major: 4, - Minor: 0, - Permissions: "rwm", - Allow: true, - }, - { - Path: "/dev/tty1", - Type: 'c', - Major: 4, - Minor: 1, - Permissions: "rwm", - Allow: true, - }, - // /dev/pts/ - pts namespaces are "coming soon" - { - Path: "", - Type: 'c', - Major: 136, - Minor: wildcard, - Permissions: "rwm", - Allow: true, - }, - { - Path: "", - Type: 'c', - Major: 5, - Minor: 2, - Permissions: "rwm", - Allow: true, - }, - // tuntap - { - Path: "", - Type: 'c', - Major: 10, - Minor: 200, - Permissions: "rwm", - Allow: true, - }, -} - -var container libcontainer.Container - -func containerPreload(context *cli.Context) error { - c, err := getContainer(context) - if err != nil { - return err - } - container = c - return nil -} - -// loadFactory returns the configured factory instance for execing containers. -func loadFactory(context *cli.Context) (libcontainer.Factory, error) { - root := context.GlobalString("root") - abs, err := filepath.Abs(root) - if err != nil { - return nil, err - } - return libcontainer.New(abs, libcontainer.Cgroupfs, func(l *libcontainer.LinuxFactory) error { - l.CriuPath = context.GlobalString("criu") - return nil - }) -} - -// getContainer returns the specified container instance by loading it from state -// with the default factory. -func getContainer(context *cli.Context) (libcontainer.Container, error) { - id := context.Args().First() - if id == "" { - return nil, errEmptyID - } - factory, err := loadFactory(context) - if err != nil { - return nil, err - } - return factory.Load(id) -} - -// fatal prints the error's details if it is a libcontainer specific error type -// then exits the program with an exit status of 1. -func fatal(err error) { - if lerr, ok := err.(libcontainer.Error); ok { - lerr.Detail(os.Stderr) - os.Exit(1) - } - fmt.Fprintln(os.Stderr, err) - os.Exit(1) -} - -func getDefaultImagePath(context *cli.Context) string { - cwd, err := os.Getwd() - if err != nil { - panic(err) - } - return filepath.Join(cwd, "checkpoint") -} - -// newProcess returns a new libcontainer Process with the arguments from the -// spec and stdio from the current process. -func newProcess(p specs.Process) *libcontainer.Process { - return &libcontainer.Process{ - Args: p.Args, - Env: p.Env, - // TODO: fix libcontainer's API to better support uid/gid in a typesafe way. - User: fmt.Sprintf("%d:%d", p.User.UID, p.User.GID), - Cwd: p.Cwd, - } -} - -func dupStdio(process *libcontainer.Process, rootuid int) error { - process.Stdin = os.Stdin - process.Stdout = os.Stdout - process.Stderr = os.Stderr - for _, fd := range []uintptr{ - os.Stdin.Fd(), - os.Stdout.Fd(), - os.Stderr.Fd(), - } { - if err := syscall.Fchown(int(fd), rootuid, rootuid); err != nil { - return err - } - } - return nil -} - -// If systemd is supporting sd_notify protocol, this function will add support -// for sd_notify protocol from within the container. -func setupSdNotify(spec *specs.LinuxSpec, notifySocket string) { - spec.Mounts = append(spec.Mounts, specs.Mount{Destination: notifySocket, Type: "bind", Source: notifySocket, Options: []string{"bind"}}) - spec.Process.Env = append(spec.Process.Env, fmt.Sprintf("NOTIFY_SOCKET=%s", notifySocket)) -} - -func destroy(container libcontainer.Container) { - if err := container.Destroy(); err != nil { - logrus.Error(err) - } -} - -func setupIO(process *libcontainer.Process, rootuid int, console string, createTTY, detach bool) (*tty, error) { - // detach and createTty will not work unless a console path is passed - // so error out here before changing any terminal settings - if createTTY && detach && console == "" { - return nil, fmt.Errorf("cannot allocate tty if runc will detach") - } - if createTTY { - return createTty(process, rootuid, console) - } - if detach { - if err := dupStdio(process, rootuid); err != nil { - return nil, err - } - return nil, nil - } - return createStdioPipes(process, rootuid) -} - -func createPidFile(path string, process *libcontainer.Process) error { - pid, err := process.Pid() - if err != nil { - return err - } - f, err := os.Create(path) - if err != nil { - return err - } - defer f.Close() - _, err = fmt.Fprintf(f, "%d", pid) - return err -} - -func createContainer(context *cli.Context, id string, spec *specs.LinuxSpec) (libcontainer.Container, error) { - config, err := createLibcontainerConfig(id, spec) - if err != nil { - return nil, err - } - - if _, err := os.Stat(config.Rootfs); err != nil { - if os.IsNotExist(err) { - return nil, fmt.Errorf("rootfs (%q) does not exist", config.Rootfs) - } - return nil, err - } - - factory, err := loadFactory(context) - if err != nil { - return nil, err - } - return factory.Create(id, config) -} - -// runProcess will create a new process in the specified container -// by executing the process specified in the 'config'. -func runProcess(container libcontainer.Container, config *specs.Process, listenFDs []*os.File, console string, pidFile string, detach bool) (int, error) { - process := newProcess(*config) - - // Add extra file descriptors if needed - if len(listenFDs) > 0 { - process.Env = append(process.Env, fmt.Sprintf("LISTEN_FDS=%d", len(listenFDs)), "LISTEN_PID=1") - process.ExtraFiles = append(process.ExtraFiles, listenFDs...) - } - - rootuid, err := container.Config().HostUID() - if err != nil { - return -1, err - } - - tty, err := setupIO(process, rootuid, console, config.Terminal, detach) - if err != nil { - return -1, err - } - - if err := container.Start(process); err != nil { - tty.Close() - return -1, err - } - - if pidFile != "" { - if err := createPidFile(pidFile, process); err != nil { - process.Signal(syscall.SIGKILL) - process.Wait() - tty.Close() - return -1, err - } - } - if detach { - return 0, nil - } - handler := newSignalHandler(tty) - defer handler.Close() - - return handler.forward(process) -} diff --git a/vendor/src/github.com/opencontainers/specs/README.md b/vendor/src/github.com/opencontainers/specs/README.md index bfff859..0055252 100644 --- a/vendor/src/github.com/opencontainers/specs/README.md +++ b/vendor/src/github.com/opencontainers/specs/README.md @@ -67,7 +67,7 @@ When in doubt, start on the [mailing-list](#mailing-list). ## Weekly Call The contributors and maintainers of the project have a weekly meeting Wednesdays at 10:00 AM PST. -Everyone is welcome to participate in the [BlueJeans call][BlueJeans]. +Everyone is welcome to participate via [UberConference web][UberConference] or audio-only: 646-494-8704 (no PIN needed.) An initial agenda will be posted to the [mailing list](#mailing-list) earlier in the week, and everyone is welcome to propose additional topics or suggest other agenda alterations there. Minutes are posted to the [mailing list](#mailing-list) and minutes from past calls are archived to the [wiki](https://github.com/opencontainers/specs/wiki) for those who are unable to join the call. @@ -155,3 +155,4 @@ Read more on [How to Write a Git Commit Message](http://chris.beams.io/posts/git 8. When possible, one keyword to scope the change in the subject (i.e. "README: ...", "runtime: ...") [BlueJeans]: https://bluejeans.com/1771332256/ +[UberConference]: https://www.uberconference.com/ssaul diff --git a/vendor/src/github.com/opencontainers/specs/config-linux.md b/vendor/src/github.com/opencontainers/specs/config-linux.md index f7723c7..c226ee8 100644 --- a/vendor/src/github.com/opencontainers/specs/config-linux.md +++ b/vendor/src/github.com/opencontainers/specs/config-linux.md @@ -3,19 +3,6 @@ The Linux container specification uses various kernel features like namespaces, cgroups, capabilities, LSM, and file system jails to fulfill the spec. Additional information is needed for Linux over the [default spec configuration](config.md) in order to configure these various kernel features. -## Capabilities - -Capabilities is an array that specifies Linux capabilities that can be provided to the process inside the container. -Valid values are the strings for capabilities defined in [the man page](http://man7.org/linux/man-pages/man7/capabilities.7.html) - -```json - "capabilities": [ - "CAP_AUDIT_WRITE", - "CAP_KILL", - "CAP_NET_BIND_SERVICE" - ] -``` - ## Default File Systems The Linux ABI includes both syscalls and several special file paths. @@ -112,7 +99,7 @@ The runtime may supply them however it likes (with [mknod][mknod.2], by bind mou The following parameters can be specified: -* **`type`** *(char, required)* - type of device: `c`, `b`, `u` or `p`. +* **`type`** *(string, required)* - type of device: `c`, `b`, `u` or `p`. More info in [mknod(1)][mknod.1]. * **`path`** *(string, required)* - full path to device inside container. * **`major, minor`** *(int64, required unless **`type`** is `p`)* - [major, minor numbers][devices] for the device. @@ -130,7 +117,7 @@ The following parameters can be specified: "type": "c", "major": 10, "minor": 229, - "fileMode": 0666, + "fileMode": 438, "uid": 0, "gid": 0 }, @@ -139,7 +126,7 @@ The following parameters can be specified: "type": "b", "major": 8, "minor": 0, - "fileMode": 0660, + "fileMode": 432, "uid": 0, "gid": 0 } @@ -194,7 +181,7 @@ The runtime MUST apply entries in the listed order. The following parameters can be specified: * **`allow`** *(boolean, required)* - whether the entry is allowed or denied. -* **`type`** *(char, optional)* - type of device: `a` (all), `c` (char), or `b` (block). +* **`type`** *(string, optional)* - type of device: `a` (all), `c` (char), or `b` (block). `null` or unset values mean "all", mapping to `a`. * **`major, minor`** *(int64, optional)* - [major, minor numbers][devices] for the device. `null` or unset values mean "all", mapping to [`*` in the filesystem API][cgroup-v1-devices]. @@ -486,28 +473,6 @@ The kernel enforces the `soft` limit for a resource while the `hard` limit acts ] ``` -## SELinux process label - -SELinux process label specifies the label with which the processes in a container are run. -For more information about SELinux, see [Selinux documentation](http://selinuxproject.org/page/Main_Page) - -###### Example - -```json - "selinuxProcessLabel": "system_u:system_r:svirt_lxc_net_t:s0:c124,c675" -``` - -## Apparmor profile - -Apparmor profile specifies the name of the apparmor profile that will be used for the container. -For more information about Apparmor, see [Apparmor documentation](https://wiki.ubuntu.com/AppArmor) - -###### Example - -```json - "apparmorProfile": "acme_secure_profile" -``` - ## seccomp Seccomp provides application sandboxing mechanism in the Linux kernel. @@ -574,17 +539,6 @@ Its value is either slave, private, or shared. "rootfsPropagation": "slave", ``` -## No new privileges - -Setting `noNewPrivileges` to true prevents the processes in the container from gaining additional privileges. -[The kernel doc](https://www.kernel.org/doc/Documentation/prctl/no_new_privs.txt) has more information on how this is achieved using a prctl system call. - -###### Example - -```json - "noNewPrivileges": true, -``` - [cgroup-v1]: https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt [cgroup-v1-blkio]: https://www.kernel.org/doc/Documentation/cgroup-v1/blkio-controller.txt [cgroup-v1-cpusets]: https://www.kernel.org/doc/Documentation/cgroup-v1/cpusets.txt diff --git a/vendor/src/github.com/opencontainers/specs/config.go b/vendor/src/github.com/opencontainers/specs/config.go index 7861c56..8fd6b4d 100644 --- a/vendor/src/github.com/opencontainers/specs/config.go +++ b/vendor/src/github.com/opencontainers/specs/config.go @@ -33,6 +33,14 @@ type Process struct { // Cwd is the current working directory for the process and must be // relative to the container's root. Cwd string `json:"cwd"` + // Capabilities are linux capabilities that are kept for the container. + Capabilities []string `json:"capabilities,omitempty"` + // ApparmorProfile specified the apparmor profile for the container. + ApparmorProfile string `json:"apparmorProfile,omitempty"` + // SelinuxProcessLabel specifies the selinux context that the container process is run as. + SelinuxLabel string `json:"selinuxLabel,omitempty"` + // NoNewPrivileges controls whether additional privileges could be gained by processes in the container. + NoNewPrivileges bool `json:"noNewPrivileges,omitempty"` } // Root contains information about the container's root filesystem on the host. diff --git a/vendor/src/github.com/opencontainers/specs/config.md b/vendor/src/github.com/opencontainers/specs/config.md index 884fe32..d0a1388 100644 --- a/vendor/src/github.com/opencontainers/specs/config.md +++ b/vendor/src/github.com/opencontainers/specs/config.md @@ -90,6 +90,17 @@ See links for details about [mountvol](http://ss64.com/nt/mountvol.html) and [Se * **`env`** (array of strings, optional) contains a list of variables that will be set in the process's environment prior to execution. Elements in the array are specified as Strings in the form "KEY=value". The left hand side must consist solely of letters, digits, and underscores `_` as outlined in [IEEE Std 1003.1-2001](http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html). * **`args`** (string, required) executable to launch and any flags as an array. The executable is the first element and must be available at the given path inside of the rootfs. If the executable path is not an absolute path then the search $PATH is interpreted to find the executable. +For Linux-based systemd the process structure supports the following process specific fields: + +* **`capabilities`** (array of strings, optional) capabilities is an array that specifies Linux capabilities that can be provided to the process inside the container. +Valid values are the strings for capabilities defined in [the man page](http://man7.org/linux/man-pages/man7/capabilities.7.html) +* **`apparmorProfile`** (string, optional) apparmor profile specifies the name of the apparmor profile that will be used for the container. +For more information about Apparmor, see [Apparmor documentation](https://wiki.ubuntu.com/AppArmor) +* **`selinuxLabel`** (string, optional) SELinux process label specifies the label with which the processes in a container are run. +For more information about SELinux, see [Selinux documentation](http://selinuxproject.org/page/Main_Page) +* **`noNewPrivileges`** (bool, optional) setting `noNewPrivileges` to true prevents the processes in the container from gaining additional privileges. +[The kernel doc](https://www.kernel.org/doc/Documentation/prctl/no_new_privs.txt) has more information on how this is achieved using a prctl system call. + The user for the process is a platform-specific structure that allows specific control over which user the process runs as. For Linux-based systems the user structure has the following fields: @@ -114,6 +125,14 @@ For Linux-based systems the user structure has the following fields: "cwd": "/root", "args": [ "sh" + ], + "apparmorProfile": "acme_secure_profile", + "selinuxLabel": "system_u:system_r:svirt_lxc_net_t:s0:c124,c675", + "noNewPrivileges": true, + "capabilities": [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" ] } ``` diff --git a/vendor/src/github.com/opencontainers/specs/config_linux.go b/vendor/src/github.com/opencontainers/specs/config_linux.go index 7202711..f798a44 100644 --- a/vendor/src/github.com/opencontainers/specs/config_linux.go +++ b/vendor/src/github.com/opencontainers/specs/config_linux.go @@ -14,8 +14,6 @@ type LinuxSpec struct { // Linux contains platform specific configuration for linux based containers. type Linux struct { - // Capabilities are linux capabilities that are kept for the container. - Capabilities []string `json:"capabilities"` // UIDMapping specifies user mappings for supporting user namespaces on linux. UIDMappings []IDMapping `json:"uidMappings,omitempty"` // GIDMapping specifies group mappings for supporting user namespaces on linux. @@ -35,16 +33,10 @@ type Linux struct { Namespaces []Namespace `json:"namespaces"` // Devices are a list of device nodes that are created for the container Devices []Device `json:"devices"` - // ApparmorProfile specified the apparmor profile for the container. - ApparmorProfile string `json:"apparmorProfile"` - // SelinuxProcessLabel specifies the selinux context that the container process is run as. - SelinuxProcessLabel string `json:"selinuxProcessLabel"` // Seccomp specifies the seccomp security settings for the container. Seccomp Seccomp `json:"seccomp"` // RootfsPropagation is the rootfs mount propagation mode for the container. RootfsPropagation string `json:"rootfsPropagation,omitempty"` - // NoNewPrivileges controls whether additional privileges could be gained by processes in the container. - NoNewPrivileges bool `json:"noNewPrivileges,omitempty"` } // User specifies linux specific user and group information for the container's @@ -238,7 +230,7 @@ type Device struct { // Path to the device. Path string `json:"path"` // Device type, block, char, etc. - Type rune `json:"type"` + Type string `json:"type"` // Major is the device's major number. Major int64 `json:"major"` // Minor is the device's minor number. @@ -256,7 +248,7 @@ type DeviceCgroup struct { // Allow or deny Allow bool `json:"allow"` // Device type, block, char, etc. - Type *rune `json:"type,omitempty"` + Type *string `json:"type,omitempty"` // Major is the device's major number. Major *int64 `json:"major,omitempty"` // Minor is the device's minor number. diff --git a/vendor/src/github.com/opencontainers/specs/runtime.md b/vendor/src/github.com/opencontainers/specs/runtime.md index 12d6c94..47d4add 100644 --- a/vendor/src/github.com/opencontainers/specs/runtime.md +++ b/vendor/src/github.com/opencontainers/specs/runtime.md @@ -1,19 +1,15 @@ # Runtime and Lifecycle +## Scope of a Container + +Barring access control concerns, the entity using a runtime to create a container MUST be able to use the operations defined in this specification against that same container. +Whether other entities using the same, or other, instance of the runtime can see that container is out of scope of this specification. + ## State -Runtime MUST store container metadata on disk so that external tools can consume and act on this information. -It is recommended that this data be stored in a temporary filesystem so that it can be removed on a system reboot. -On Linux/Unix based systems the metadata MUST be stored under `/run/opencontainer/containers`. -For non-Linux/Unix based systems the location of the root metadata directory is currently undefined. -Within that directory there MUST be one directory for each container created, where the name of the directory MUST be the ID of the container. -For example: for a Linux container with an ID of `173975398351`, there will be a corresponding directory: `/run/opencontainer/containers/173975398351`. -Within each container's directory, there MUST be a JSON encoded file called `state.json` that contains the runtime state of the container. -For example: `/run/opencontainer/containers/173975398351/state.json`. +The state of a container MUST include, at least, the following propeties: -The `state.json` file MUST contain all of the following properties: - -* **`version`**: (string) is the OCF specification version used when creating the container. +* **`ociVersion`**: (string) is the OCI specification version used when creating the container. * **`id`**: (string) is the container's ID. This MUST be unique across all containers on this host. There is no requirement that it be unique across hosts. @@ -23,37 +19,111 @@ This allows the hooks to perform cleanup and teardown logic after the runtime de * **`bundlePath`**: (string) is the absolute path to the container's bundle directory. This is provided so that consumers can find the container's configuration and root filesystem on the host. -*Example* - +When serialized in JSON, the format MUST adhere to the following pattern: ```json { - "version": "0.2.0", - "id": "oc-container", + "ociVersion": "0.2.0", + "id": "oci-container1", "pid": 4422, "bundlePath": "/containers/redis" } ``` +See [Query State](#query-state) for information on retrieving the state of a container. + ## Lifecycle The lifecycle describes the timeline of events that happen from when a container is created to when it ceases to exist. -1. OCI compliant runtime is invoked by passing the bundle path as argument. -2. The container's runtime environment is created according to the configuration in [`config.json`](config.md). - Any updates to `config.json` after container is running do not affect the container. -3. The container's state.json file is written to the filesystem. -4. The prestart hooks are invoked by the runtime. - If any prestart hook fails, then the container is stopped and the lifecycle continues at step 8. -5. The user specified process is executed in the container. -6. The poststart hooks are invoked by the runtime. - If any poststart hook fails, then the container is stopped and the lifecycle continues at step 8. -7. Additional actions such as pausing the container, resuming the container or signaling the container may be performed using the runtime interface. - The container could also error out or crash. -8. The container is destroyed by undoing the steps performed during create phase (step 2). -9. The poststop hooks are invoked by the runtime and errors, if any, are logged. -10. The state.json file associated with the container is removed and the return code of the container's user specified process is returned or logged. +1. OCI compliant runtime is invoked with a reference to the location of the bundle. + How this reference is passed to the runtime is an implementation detail. +2. The container's runtime environment MUST be created according to the configuration in [`config.json`](config.md). + Any updates to `config.json` after container is running MUST not affect the container. +3. The prestart hooks MUST be invoked by the runtime. + If any prestart hook fails, then the container MUST be stopped and the lifecycle continues at step 8. +4. The user specified process MUST be executed in the container. +5. The poststart hooks MUST be invoked by the runtime. + If any poststart hook fails, then the container MUST be stopped and the lifecycle continues at step 8. +6. Additional actions such as pausing the container, resuming the container or signaling the container MAY be performed using the runtime interface. + The container MAY also error out, exit or crash. +7. The container MUST be destroyed by undoing the steps performed during create phase (step 2). +8. The poststop hooks MUST be invoked by the runtime and errors, if any, MAY be logged. Note: The lifecycle is a WIP and it will evolve as we have more use cases and more information on the viability of a separate create phase. +## Operations + +OCI compliant runtimes MUST support the following operations, unless the operation is not supported by the base operating system. + +### Errors +In cases where the specified operation generates an error, this specification does not mandate how, or even if, that error is returned or exposed to the user of an implementation. +Unless otherwise stated, generating an error MUST leave the state of the environment as if the operation were never attempted - modulo any possible trivial ancillary changes such as logging. + +### Query State + +`state ` + +This operation MUST generate an error if it is not provided the ID of a container. +This operation MUST return the state of a container as specified in the [State](#state) section. +In particular, the state MUST be serialized as JSON. + + +### Start + +`start ` + +This operation MUST generate an error if it is not provided a path to the bundle and the container ID to associate with the container. +If the ID provided is not unique across all containers within the scope of the runtime, or is not valid in any other way, the implementation MUST generate an error. +Using the data in `config.json`, that are in the bundle's directory, this operation MUST create a new container. +This includes creating the relevant namespaces, resource limits, etc and configuring the appropriate capabilities for the container. +A new process within the scope of the container MUST be created as specified by the `config.json` file otherwise an error MUST be generated. + +Attempting to start an already running container MUST have no effect on the container and MUST generate an error. + +### Stop + +`stop ` + +This operation MUST generate an error if it is not provided the container ID. +This operation MUST stop and delete a running container. +Stopping a container MUST stop all of the processes running within the scope of the container. +Deleting a container MUST delete the associated namespaces and resources associated with the container. +Once a container is deleted, its `id` MAY be used by subsequent containers. +Attempting to stop a container that is not running MUST have no effect on the container and MUST generate an error. + +### Exec + +`exec ` + +This operation MUST generate an error if it is not provided the container ID and a path to the JSON describing the process to start. +The JSON describing the new process MUST adhere to the [Process configuration](config.md#process-configuration) definition. +This operation MUST create a new process within the scope of the container. +If the container is not running then this operation MUST have no effect on the container and MUST generate an error. +Executing this operation multiple times MUST result in a new process each time. +Example: +``` +{ + "terminal": true, + "user": { + "uid": 0, + "gid": 0, + "additionalGids": null + }, + "args": [ + "/bin/sleep", + "60" + ], + "env": [ + "version=1.0" + ], + "cwd": "...", +} +``` +This specification does not manadate the name of this JSON file. +See the specification of the `config.json` file for the definition of these fields. +The stopping, or exiting, of these secondary process MUST have no effect on the state of the container. +In other words, a container (and its PID 1 process) MUST NOT be stopped due to the exiting of a secondary process. + ## Hooks -See [runtime configuration for hooks](./config.md#hooks) +Many of the operations specified in this specification have "hooks" that allow for additional actions to be taken before or after each operation. +See [runtime configuration for hooks](./config.md#hooks) for more information. diff --git a/vendor/src/github.com/opencontainers/specs/style.md b/vendor/src/github.com/opencontainers/specs/style.md index e9e86d0..a04b6ba 100644 --- a/vendor/src/github.com/opencontainers/specs/style.md +++ b/vendor/src/github.com/opencontainers/specs/style.md @@ -13,9 +13,14 @@ The redundancy reduction from removing the namespacing prefix is not useful enou ## Optional settings should have pointer Go types So we have a consistent way to identify unset values ([source][optional-pointer]). +The exceptions are entries where the Go default for the type is a no-op in the spec, in which case `omitempty` is sufficient and no pointer is needed (sources [here][no-pointer-for-slices], [here][no-pointer-for-boolean], and [here][pointer-when-updates-require-changes]). + [capabilities]: config-linux.md#capabilities [class-id]: config-linux.md#network [integer-over-hex]: https://github.com/opencontainers/specs/pull/267#discussion_r48360013 [keep-prefix]: https://github.com/opencontainers/specs/pull/159#issuecomment-138728337 +[no-pointer-for-boolean]: https://github.com/opencontainers/specs/pull/290#discussion_r50296396 +[no-pointer-for-slices]: https://github.com/opencontainers/specs/pull/316/files#r50782982 [optional-pointer]: https://github.com/opencontainers/specs/pull/233#discussion_r47829711 +[pointer-when-updates-require-changes]: https://github.com/opencontainers/specs/pull/317/files#r50932706 diff --git a/vendor/src/github.com/opencontainers/specs/version.go b/vendor/src/github.com/opencontainers/specs/version.go index f236a69..35785d7 100644 --- a/vendor/src/github.com/opencontainers/specs/version.go +++ b/vendor/src/github.com/opencontainers/specs/version.go @@ -6,12 +6,12 @@ const ( // VersionMajor is for an API incompatible changes VersionMajor = 0 // VersionMinor is for functionality in a backwards-compatible manner - VersionMinor = 3 + VersionMinor = 4 // VersionPatch is for backwards-compatible bug fixes VersionPatch = 0 // VersionDev indicates development branch. Releases will be empty string. - VersionDev = "" + VersionDev = "-dev" ) // Version is the specification version that the package types support.