Merge pull request #1454 from mlaventure/per-container-runtime-binary

Per container runtime binary
This commit is contained in:
Phil Estes 2017-09-01 13:25:17 -04:00 committed by GitHub
commit 4291fb4803
13 changed files with 461 additions and 249 deletions

View File

@ -66,6 +66,19 @@ func main() {
Name: "workdir,w", Name: "workdir,w",
Usage: "path used to store large temporary data", Usage: "path used to store large temporary data",
}, },
cli.StringFlag{
Name: "runtime-root",
Usage: "root directory for the runtime",
Value: shim.RuncRoot,
},
cli.StringFlag{
Name: "criu,c",
Usage: "path to criu",
},
cli.BoolFlag{
Name: "systemd-cgroup",
Usage: "set runtime to use systemd-cgroup",
},
} }
app.Before = func(context *cli.Context) error { app.Before = func(context *cli.Context) error {
if context.GlobalBool("debug") { if context.GlobalBool("debug") {
@ -90,9 +103,14 @@ func main() {
return err return err
} }
sv, err := shim.NewService( sv, err := shim.NewService(
path, shim.Config{
context.GlobalString("namespace"), Path: path,
context.GlobalString("workdir"), Namespace: context.GlobalString("namespace"),
WorkDir: context.GlobalString("workdir"),
Criu: context.GlobalString("criu"),
SystemdCgroup: context.GlobalBool("systemd-cgroup"),
RuntimeRoot: context.GlobalString("runtime-root"),
},
&remoteEventsPublisher{client: e}, &remoteEventsPublisher{client: e},
) )
if err != nil { if err != nil {

View File

@ -851,3 +851,48 @@ func TestDaemonRestartWithRunningShim(t *testing.T) {
t.Errorf("pid %d still exists", pid) t.Errorf("pid %d still exists", pid)
} }
} }
func TestContainerRuntimeOptions(t *testing.T) {
t.Parallel()
client, err := newClient(t, address)
if err != nil {
t.Fatal(err)
}
defer client.Close()
var (
image Image
ctx, cancel = testContext()
id = t.Name()
)
defer cancel()
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(
ctx, id,
WithNewSpec(withImageConfig(image), withExitStatus(7)),
withNewSnapshot(id, image),
WithRuntime("io.containerd.runtime.v1.linux", &runcopts.RuncOptions{Runtime: "no-runc"}),
)
if err != nil {
t.Error(err)
return
}
defer container.Delete(ctx, WithSnapshotCleanup)
task, err := container.NewTask(ctx, empty())
if err == nil {
t.Errorf("task creation should have failed")
task.Delete(ctx)
return
}
if !strings.Contains(err.Error(), `"no-runc"`) {
t.Errorf("task creation should have failed because of lack of executable. Instead failed with: %v", err.Error())
}
}

View File

@ -12,23 +12,19 @@ import (
"github.com/containerd/containerd/events" "github.com/containerd/containerd/events"
"github.com/containerd/containerd/linux/runcopts" "github.com/containerd/containerd/linux/runcopts"
client "github.com/containerd/containerd/linux/shim" client "github.com/containerd/containerd/linux/shim"
"github.com/containerd/containerd/runtime"
"github.com/containerd/containerd/typeurl"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
func loadBundle(path, workdir, namespace, id string, events *events.Exchange) *bundle { func loadBundle(id, path, workdir string) *bundle {
return &bundle{ return &bundle{
path: path, id: id,
namespace: namespace, path: path,
id: id, workDir: workdir,
events: events,
workDir: workdir,
} }
} }
// newBundle creates a new bundle on disk at the provided path for the given id // newBundle creates a new bundle on disk at the provided path for the given id
func newBundle(namespace, id, path, workDir string, spec []byte, events *events.Exchange) (b *bundle, err error) { func newBundle(id, path, workDir string, spec []byte) (b *bundle, err error) {
if err := os.MkdirAll(path, 0711); err != nil { if err := os.MkdirAll(path, 0711); err != nil {
return nil, err return nil, err
} }
@ -61,56 +57,43 @@ func newBundle(namespace, id, path, workDir string, spec []byte, events *events.
defer f.Close() defer f.Close()
_, err = io.Copy(f, bytes.NewReader(spec)) _, err = io.Copy(f, bytes.NewReader(spec))
return &bundle{ return &bundle{
id: id, id: id,
path: path, path: path,
workDir: workDir, workDir: workDir,
namespace: namespace,
events: events,
}, err }, err
} }
type bundle struct { type bundle struct {
id string id string
path string path string
workDir string workDir string
namespace string
events *events.Exchange
} }
// NewShim connects to the shim managing the bundle and tasks type shimOpt func(*bundle, string, *runcopts.RuncOptions) (client.Config, client.ClientOpt)
func (b *bundle) NewShim(ctx context.Context, binary, grpcAddress string, remote, debug bool, createOpts runtime.CreateOpts, exitHandler func()) (*client.Client, error) {
opt := client.WithStart(binary, grpcAddress, debug, exitHandler) func ShimRemote(shim, daemonAddress, cgroup string, debug bool, exitHandler func()) shimOpt {
if !remote { return func(b *bundle, ns string, ropts *runcopts.RuncOptions) (client.Config, client.ClientOpt) {
opt = client.WithLocal(b.events) return b.shimConfig(ns, ropts),
client.WithStart(shim, b.shimAddress(ns), daemonAddress, cgroup, debug, exitHandler)
} }
var options runcopts.CreateOptions
if createOpts.Options != nil {
v, err := typeurl.UnmarshalAny(createOpts.Options)
if err != nil {
return nil, err
}
options = *v.(*runcopts.CreateOptions)
}
return client.New(ctx, client.Config{
Address: b.shimAddress(),
Path: b.path,
Namespace: b.namespace,
CgroupPath: options.ShimCgroup,
WorkDir: b.workDir,
}, opt)
} }
// Connect reconnects to an existing shim func ShimLocal(exchange *events.Exchange) shimOpt {
func (b *bundle) Connect(ctx context.Context, remote bool) (*client.Client, error) { return func(b *bundle, ns string, ropts *runcopts.RuncOptions) (client.Config, client.ClientOpt) {
opt := client.WithConnect return b.shimConfig(ns, ropts), client.WithLocal(exchange)
if !remote {
opt = client.WithLocal(b.events)
} }
return client.New(ctx, client.Config{ }
Address: b.shimAddress(),
Path: b.path, func ShimConnect() shimOpt {
Namespace: b.namespace, return func(b *bundle, ns string, ropts *runcopts.RuncOptions) (client.Config, client.ClientOpt) {
}, opt) return b.shimConfig(ns, ropts), client.WithConnect(b.shimAddress(ns))
}
}
// NewShimClient connects to the shim managing the bundle and tasks creating it if needed
func (b *bundle) NewShimClient(ctx context.Context, namespace string, getClientOpts shimOpt, runcOpts *runcopts.RuncOptions) (*client.Client, error) {
cfg, opt := getClientOpts(b, namespace, runcOpts)
return client.New(ctx, cfg, opt)
} }
// Delete deletes the bundle from disk // Delete deletes the bundle from disk
@ -127,7 +110,28 @@ func (b *bundle) Delete() error {
return errors.Wrapf(err, "Failed to remove both bundle and workdir locations: %v", err2) return errors.Wrapf(err, "Failed to remove both bundle and workdir locations: %v", err2)
} }
func (b *bundle) shimAddress() string { func (b *bundle) shimAddress(namespace string) string {
return filepath.Join(string(filepath.Separator), "containerd-shim", b.namespace, b.id, "shim.sock") return filepath.Join(string(filepath.Separator), "containerd-shim", namespace, b.id, "shim.sock")
} }
func (b *bundle) shimConfig(namespace string, runcOptions *runcopts.RuncOptions) client.Config {
var (
criuPath string
runtimeRoot string
systemdCgroup bool
)
if runcOptions != nil {
criuPath = runcOptions.CriuPath
systemdCgroup = runcOptions.SystemdCgroup
runtimeRoot = runcOptions.RuntimeRoot
}
return client.Config{
Path: b.path,
WorkDir: b.workDir,
Namespace: namespace,
Criu: criuPath,
RuntimeRoot: runtimeRoot,
SystemdCgroup: systemdCgroup,
}
}

View File

@ -37,8 +37,10 @@ var _ = math.Inf
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
type RuncOptions struct { type RuncOptions struct {
CriuPath string `protobuf:"bytes,1,opt,name=criu_path,json=criuPath,proto3" json:"criu_path,omitempty"` Runtime string `protobuf:"bytes,1,opt,name=runtime,proto3" json:"runtime,omitempty"`
SystemdCgroup string `protobuf:"bytes,2,opt,name=systemd_cgroup,json=systemdCgroup,proto3" json:"systemd_cgroup,omitempty"` RuntimeRoot string `protobuf:"bytes,2,opt,name=runtime_root,json=runtimeRoot,proto3" json:"runtime_root,omitempty"`
CriuPath string `protobuf:"bytes,3,opt,name=criu_path,json=criuPath,proto3" json:"criu_path,omitempty"`
SystemdCgroup bool `protobuf:"varint,4,opt,name=systemd_cgroup,json=systemdCgroup,proto3" json:"systemd_cgroup,omitempty"`
} }
func (m *RuncOptions) Reset() { *m = RuncOptions{} } func (m *RuncOptions) Reset() { *m = RuncOptions{} }
@ -95,17 +97,33 @@ func (m *RuncOptions) MarshalTo(dAtA []byte) (int, error) {
_ = i _ = i
var l int var l int
_ = l _ = l
if len(m.CriuPath) > 0 { if len(m.Runtime) > 0 {
dAtA[i] = 0xa dAtA[i] = 0xa
i++ i++
i = encodeVarintRunc(dAtA, i, uint64(len(m.Runtime)))
i += copy(dAtA[i:], m.Runtime)
}
if len(m.RuntimeRoot) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintRunc(dAtA, i, uint64(len(m.RuntimeRoot)))
i += copy(dAtA[i:], m.RuntimeRoot)
}
if len(m.CriuPath) > 0 {
dAtA[i] = 0x1a
i++
i = encodeVarintRunc(dAtA, i, uint64(len(m.CriuPath))) i = encodeVarintRunc(dAtA, i, uint64(len(m.CriuPath)))
i += copy(dAtA[i:], m.CriuPath) i += copy(dAtA[i:], m.CriuPath)
} }
if len(m.SystemdCgroup) > 0 { if m.SystemdCgroup {
dAtA[i] = 0x12 dAtA[i] = 0x20
i++
if m.SystemdCgroup {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i++ i++
i = encodeVarintRunc(dAtA, i, uint64(len(m.SystemdCgroup)))
i += copy(dAtA[i:], m.SystemdCgroup)
} }
return i, nil return i, nil
} }
@ -334,13 +352,20 @@ func encodeVarintRunc(dAtA []byte, offset int, v uint64) int {
func (m *RuncOptions) Size() (n int) { func (m *RuncOptions) Size() (n int) {
var l int var l int
_ = l _ = l
l = len(m.Runtime)
if l > 0 {
n += 1 + l + sovRunc(uint64(l))
}
l = len(m.RuntimeRoot)
if l > 0 {
n += 1 + l + sovRunc(uint64(l))
}
l = len(m.CriuPath) l = len(m.CriuPath)
if l > 0 { if l > 0 {
n += 1 + l + sovRunc(uint64(l)) n += 1 + l + sovRunc(uint64(l))
} }
l = len(m.SystemdCgroup) if m.SystemdCgroup {
if l > 0 { n += 2
n += 1 + l + sovRunc(uint64(l))
} }
return n return n
} }
@ -432,6 +457,8 @@ func (this *RuncOptions) String() string {
return "nil" return "nil"
} }
s := strings.Join([]string{`&RuncOptions{`, s := strings.Join([]string{`&RuncOptions{`,
`Runtime:` + fmt.Sprintf("%v", this.Runtime) + `,`,
`RuntimeRoot:` + fmt.Sprintf("%v", this.RuntimeRoot) + `,`,
`CriuPath:` + fmt.Sprintf("%v", this.CriuPath) + `,`, `CriuPath:` + fmt.Sprintf("%v", this.CriuPath) + `,`,
`SystemdCgroup:` + fmt.Sprintf("%v", this.SystemdCgroup) + `,`, `SystemdCgroup:` + fmt.Sprintf("%v", this.SystemdCgroup) + `,`,
`}`, `}`,
@ -510,6 +537,64 @@ func (m *RuncOptions) Unmarshal(dAtA []byte) error {
} }
switch fieldNum { switch fieldNum {
case 1: case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Runtime", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRunc
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthRunc
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Runtime = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field RuntimeRoot", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRunc
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthRunc
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.RuntimeRoot = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 2 { if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field CriuPath", wireType) return fmt.Errorf("proto: wrong wireType = %d for field CriuPath", wireType)
} }
@ -538,11 +623,11 @@ func (m *RuncOptions) Unmarshal(dAtA []byte) error {
} }
m.CriuPath = string(dAtA[iNdEx:postIndex]) m.CriuPath = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex iNdEx = postIndex
case 2: case 4:
if wireType != 2 { if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field SystemdCgroup", wireType) return fmt.Errorf("proto: wrong wireType = %d for field SystemdCgroup", wireType)
} }
var stringLen uint64 var v int
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowRunc return ErrIntOverflowRunc
@ -552,21 +637,12 @@ func (m *RuncOptions) Unmarshal(dAtA []byte) error {
} }
b := dAtA[iNdEx] b := dAtA[iNdEx]
iNdEx++ iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift v |= (int(b) & 0x7F) << shift
if b < 0x80 { if b < 0x80 {
break break
} }
} }
intStringLen := int(stringLen) m.SystemdCgroup = bool(v != 0)
if intStringLen < 0 {
return ErrInvalidLengthRunc
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.SystemdCgroup = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipRunc(dAtA[iNdEx:]) skippy, err := skipRunc(dAtA[iNdEx:])
@ -1163,33 +1239,35 @@ func init() {
} }
var fileDescriptorRunc = []byte{ var fileDescriptorRunc = []byte{
// 438 bytes of a gzipped FileDescriptorProto // 467 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x93, 0xb1, 0x6f, 0xd4, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x93, 0x41, 0x6f, 0xd3, 0x40,
0x18, 0xc5, 0x9b, 0xb6, 0xb4, 0x89, 0xaf, 0x57, 0xc0, 0x50, 0x29, 0x14, 0x11, 0xca, 0x09, 0xa4, 0x10, 0x85, 0xbb, 0x6d, 0x69, 0x9d, 0x4d, 0x53, 0x60, 0xa1, 0x92, 0x29, 0xc2, 0x84, 0x08, 0xa4,
0xb2, 0xdc, 0x49, 0xb0, 0x20, 0xd8, 0xb8, 0x11, 0x28, 0x25, 0xc0, 0xc2, 0x62, 0xa5, 0xbe, 0x8f, 0x70, 0x49, 0x24, 0xb8, 0x20, 0xb8, 0x91, 0x23, 0x50, 0x2a, 0x03, 0x17, 0x2e, 0x2b, 0x77, 0x33,
0xc4, 0xba, 0xe4, 0xfb, 0x2c, 0xdb, 0xa1, 0xb9, 0x8d, 0x3f, 0xaf, 0x23, 0x62, 0x62, 0xa4, 0xf9, 0x24, 0xab, 0xd8, 0x33, 0xab, 0xdd, 0x35, 0x75, 0x6e, 0xfc, 0x02, 0x7e, 0x57, 0x8f, 0x88, 0x13,
0x47, 0x40, 0x71, 0x2e, 0x85, 0x95, 0x95, 0xed, 0xf9, 0xf7, 0x9e, 0x9e, 0xa5, 0x27, 0x7d, 0xec, 0x47, 0x9a, 0x3f, 0x02, 0xf2, 0xda, 0x2e, 0x5c, 0xb9, 0x72, 0x7b, 0xf3, 0xbd, 0xb1, 0xe7, 0xe9,
0x79, 0xae, 0x5c, 0x51, 0x9f, 0x4d, 0x25, 0x55, 0x33, 0x49, 0xe8, 0x32, 0x85, 0x60, 0x16, 0x7f, 0x49, 0xcb, 0x9f, 0x2f, 0xb4, 0x5f, 0x96, 0x67, 0x13, 0x45, 0xc5, 0x54, 0x11, 0xfa, 0x4c, 0x23,
0xcb, 0x52, 0x61, 0xdd, 0xcc, 0x4c, 0x8d, 0x92, 0xb4, 0xb3, 0x5e, 0x4c, 0xb5, 0x21, 0x47, 0xfc, 0xd8, 0xf9, 0xdf, 0x32, 0xd7, 0x58, 0x56, 0x53, 0x5b, 0xa2, 0x22, 0xe3, 0x5d, 0x10, 0x13, 0x63,
0xe0, 0x4f, 0x6a, 0xea, 0x53, 0xd3, 0xce, 0x3c, 0xbc, 0x9d, 0x53, 0x4e, 0x3e, 0x31, 0xeb, 0x54, 0xc9, 0x93, 0x38, 0xfa, 0xb3, 0x35, 0x09, 0x5b, 0x93, 0xda, 0x3c, 0xbe, 0xbd, 0xa0, 0x05, 0x85,
0x1f, 0x9e, 0xbc, 0x63, 0xa3, 0xb4, 0x46, 0xf9, 0x56, 0x3b, 0x45, 0x68, 0xf9, 0x5d, 0x16, 0x49, 0x8d, 0x69, 0xad, 0x9a, 0xe5, 0xd1, 0x57, 0xc6, 0xfb, 0x69, 0x89, 0xea, 0xad, 0xf1, 0x9a, 0xd0,
0xa3, 0x6a, 0xa1, 0x33, 0x57, 0xc4, 0xc1, 0x51, 0x70, 0x1c, 0xa5, 0x61, 0x07, 0x4e, 0x33, 0x57, 0x89, 0x98, 0xef, 0xdb, 0x12, 0xbd, 0x2e, 0x20, 0x66, 0x43, 0x36, 0xee, 0xa5, 0xdd, 0x28, 0x1e,
0xf0, 0x47, 0x6c, 0xdf, 0xae, 0xac, 0x83, 0x6a, 0x21, 0x64, 0x6e, 0xa8, 0xd6, 0xf1, 0xa6, 0x4f, 0xf0, 0x83, 0x56, 0x4a, 0x4b, 0xe4, 0xe3, 0xed, 0x60, 0xf7, 0x5b, 0x96, 0x12, 0x79, 0x71, 0x97,
0x8c, 0xd7, 0x74, 0xee, 0xe1, 0xe4, 0xfb, 0x26, 0x1b, 0xcf, 0x0d, 0x64, 0x0e, 0x86, 0xd6, 0x09, 0xf7, 0x94, 0xd5, 0xa5, 0x34, 0x99, 0x5f, 0xc6, 0x3b, 0xc1, 0x8f, 0x6a, 0x70, 0x9a, 0xf9, 0xa5,
0x1b, 0x23, 0x09, 0xad, 0xbe, 0x90, 0x13, 0x86, 0xc8, 0xf9, 0xe6, 0x30, 0x1d, 0x21, 0x9d, 0x76, 0x78, 0xc4, 0x0f, 0xdd, 0xda, 0x79, 0x28, 0xe6, 0x52, 0x2d, 0x2c, 0x95, 0x26, 0xde, 0x1d, 0xb2,
0x2c, 0x25, 0x72, 0xfc, 0x0e, 0x0b, 0x49, 0x03, 0x0a, 0x27, 0xfb, 0xda, 0x30, 0xdd, 0xed, 0xde, 0x71, 0x94, 0x0e, 0x5a, 0x3a, 0x0b, 0x70, 0xf4, 0x7d, 0x9b, 0x0f, 0x66, 0x16, 0x32, 0x0f, 0x5d,
0x1f, 0xa4, 0xe6, 0x4f, 0xd8, 0x01, 0x34, 0x0e, 0x0c, 0x66, 0xa5, 0xa8, 0x51, 0x35, 0xc2, 0x92, 0xa4, 0x11, 0x1f, 0x20, 0x49, 0xa3, 0x3f, 0x93, 0x6f, 0x2e, 0xb3, 0xf0, 0x5d, 0x1f, 0xe9, 0xb4,
0x5c, 0x82, 0xb3, 0xf1, 0x96, 0xcf, 0xdd, 0x1a, 0xcc, 0x8f, 0xa8, 0x9a, 0xf7, 0xbd, 0xc5, 0x0f, 0x66, 0xe1, 0xf2, 0x1d, 0x1e, 0x91, 0x01, 0x94, 0x5e, 0x99, 0x10, 0x2c, 0x4a, 0xf7, 0xeb, 0xf9,
0x59, 0xe8, 0xc0, 0x54, 0x0a, 0xb3, 0x32, 0xde, 0xf6, 0xb1, 0xab, 0x37, 0xbf, 0xc7, 0xd8, 0x67, 0xbd, 0x32, 0xe2, 0x09, 0x3f, 0x82, 0xca, 0x83, 0xc5, 0x2c, 0x97, 0x25, 0xea, 0x4a, 0x3a, 0x52,
0x55, 0x82, 0x28, 0x49, 0x2e, 0x6d, 0x7c, 0xcd, 0xbb, 0x51, 0x47, 0x5e, 0x77, 0x80, 0x3f, 0x66, 0x2b, 0xf0, 0x2e, 0x04, 0x8c, 0xd2, 0x5b, 0x9d, 0xf9, 0x01, 0x75, 0xf5, 0xae, 0xb1, 0xc4, 0x31,
0x37, 0xa0, 0xd2, 0x6e, 0x25, 0x30, 0xab, 0xc0, 0xea, 0x4c, 0x82, 0x8d, 0x77, 0x8e, 0xb6, 0x8e, 0x8f, 0x3c, 0xd8, 0x42, 0x63, 0x96, 0xb7, 0x29, 0xaf, 0x66, 0x71, 0x8f, 0xf3, 0x4f, 0x3a, 0x07,
0xa3, 0xf4, 0xba, 0xe7, 0x27, 0x57, 0x98, 0x3f, 0x60, 0x7b, 0xfd, 0x12, 0x56, 0x54, 0xb4, 0x80, 0x99, 0x93, 0x5a, 0xb9, 0xf8, 0x5a, 0x70, 0x7b, 0x35, 0x79, 0x5d, 0x03, 0xf1, 0x98, 0xdf, 0x80,
0x78, 0xd7, 0xef, 0x31, 0x5a, 0xb3, 0x37, 0xb4, 0x00, 0xfe, 0x90, 0xed, 0x23, 0x09, 0x84, 0x73, 0xc2, 0xf8, 0xb5, 0xc4, 0xac, 0x00, 0x67, 0x32, 0x05, 0x2e, 0xde, 0x1b, 0xee, 0x8c, 0x7b, 0xe9,
0xb1, 0x84, 0x95, 0x51, 0x98, 0xc7, 0xa1, 0xff, 0x70, 0x0f, 0xe9, 0x04, 0xce, 0x5f, 0xf5, 0x8c, 0xf5, 0xc0, 0x4f, 0xae, 0x70, 0xdd, 0x68, 0xd3, 0x84, 0x93, 0x05, 0xcd, 0x21, 0xde, 0x6f, 0x1a,
0xdf, 0x67, 0x23, 0x5b, 0xa8, 0x6a, 0xd8, 0x35, 0xf2, 0x3d, 0xac, 0x43, 0xeb, 0x51, 0x7f, 0x05, 0x6d, 0xd9, 0x1b, 0x9a, 0x83, 0x78, 0xc8, 0x0f, 0x91, 0x24, 0xc2, 0xb9, 0x5c, 0xc1, 0xda, 0x6a,
0xec, 0xe6, 0xbc, 0x00, 0xb9, 0xd4, 0xa4, 0xd0, 0x0d, 0xc3, 0x72, 0xb6, 0x0d, 0x8d, 0x1a, 0xf6, 0x5c, 0xc4, 0x51, 0x38, 0x78, 0x80, 0x74, 0x02, 0xe7, 0xaf, 0x1a, 0x26, 0xee, 0xf3, 0xbe, 0x5b,
0xf4, 0xfa, 0x7f, 0x1d, 0xf2, 0x65, 0x7a, 0x71, 0x99, 0x6c, 0xfc, 0xb8, 0x4c, 0x36, 0xbe, 0xb6, 0xea, 0xa2, 0xeb, 0xb5, 0x17, 0xfe, 0xc3, 0x6b, 0xd4, 0x96, 0xfa, 0x8b, 0xf1, 0x9b, 0xb3, 0x25,
0x49, 0x70, 0xd1, 0x26, 0xc1, 0xb7, 0x36, 0x09, 0x7e, 0xb6, 0x49, 0xf0, 0xe9, 0xd9, 0x3f, 0x1e, 0xa8, 0x95, 0x21, 0x8d, 0xbe, 0x2b, 0x56, 0xf0, 0x5d, 0xa8, 0x74, 0xd7, 0x67, 0xd0, 0xff, 0x6b,
0xcb, 0x8b, 0x41, 0x9c, 0xed, 0xf8, 0x23, 0x78, 0xfa, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x00, 0x19, 0x91, 0x2f, 0xd3, 0x8b, 0xcb, 0x64, 0xeb, 0xc7, 0x65, 0xb2, 0xf5, 0x65, 0x93, 0xb0, 0x8b, 0x4d,
0xba, 0x8f, 0x6f, 0x03, 0x00, 0x00, 0xc2, 0xbe, 0x6d, 0x12, 0xf6, 0x73, 0x93, 0xb0, 0x8f, 0xcf, 0xfe, 0xf1, 0xa9, 0xbd, 0xe8, 0xc4,
0xd9, 0x5e, 0x78, 0x42, 0x4f, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0xe6, 0x26, 0x29, 0x60, 0xad,
0x03, 0x00, 0x00,
} }

View File

@ -7,8 +7,10 @@ import "gogoproto/gogo.proto";
option go_package = "github.com/containerd/containerd/linux/runcopts;runcopts"; option go_package = "github.com/containerd/containerd/linux/runcopts;runcopts";
message RuncOptions { message RuncOptions {
string criu_path = 1; string runtime = 1;
string systemd_cgroup = 2; string runtime_root = 2;
string criu_path = 3;
bool systemd_cgroup = 4;
} }
message CreateOptions { message CreateOptions {

View File

@ -13,9 +13,11 @@ import (
"github.com/boltdb/bolt" "github.com/boltdb/bolt"
eventsapi "github.com/containerd/containerd/api/services/events/v1" eventsapi "github.com/containerd/containerd/api/services/events/v1"
"github.com/containerd/containerd/api/types" "github.com/containerd/containerd/api/types"
"github.com/containerd/containerd/containers"
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/events" "github.com/containerd/containerd/events"
"github.com/containerd/containerd/identifiers" "github.com/containerd/containerd/identifiers"
"github.com/containerd/containerd/linux/runcopts"
client "github.com/containerd/containerd/linux/shim" client "github.com/containerd/containerd/linux/shim"
shim "github.com/containerd/containerd/linux/shim/v1" shim "github.com/containerd/containerd/linux/shim/v1"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
@ -25,6 +27,7 @@ import (
"github.com/containerd/containerd/reaper" "github.com/containerd/containerd/reaper"
"github.com/containerd/containerd/runtime" "github.com/containerd/containerd/runtime"
"github.com/containerd/containerd/sys" "github.com/containerd/containerd/sys"
"github.com/containerd/containerd/typeurl"
runc "github.com/containerd/go-runc" runc "github.com/containerd/go-runc"
google_protobuf "github.com/golang/protobuf/ptypes/empty" google_protobuf "github.com/golang/protobuf/ptypes/empty"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -67,6 +70,8 @@ type Config struct {
Shim string `toml:"shim,omitempty"` Shim string `toml:"shim,omitempty"`
// Runtime is a path or name of an OCI runtime used by the shim // Runtime is a path or name of an OCI runtime used by the shim
Runtime string `toml:"runtime,omitempty"` Runtime string `toml:"runtime,omitempty"`
// RuntimeRoot is the path that shall be used by the OCI runtime for its data
RuntimeRoot string `toml:"runtime_root,omitempty"`
// NoShim calls runc directly from within the pkg // NoShim calls runc directly from within the pkg
NoShim bool `toml:"no_shim,omitempty"` NoShim bool `toml:"no_shim,omitempty"`
// Debug enable debug on the shim // Debug enable debug on the shim
@ -90,17 +95,14 @@ func New(ic *plugin.InitContext) (interface{}, error) {
} }
cfg := ic.Config.(*Config) cfg := ic.Config.(*Config)
r := &Runtime{ r := &Runtime{
root: ic.Root, root: ic.Root,
state: ic.State, state: ic.State,
remote: !cfg.NoShim, monitor: monitor.(runtime.TaskMonitor),
shim: cfg.Shim, tasks: runtime.NewTaskList(),
shimDebug: cfg.ShimDebug, db: m.(*bolt.DB),
runtime: cfg.Runtime, address: ic.Address,
monitor: monitor.(runtime.TaskMonitor), events: ic.Events,
tasks: runtime.NewTaskList(), config: cfg,
db: m.(*bolt.DB),
address: ic.Address,
events: ic.Events,
} }
tasks, err := r.restoreTasks(ic.Context) tasks, err := r.restoreTasks(ic.Context)
if err != nil { if err != nil {
@ -116,18 +118,16 @@ func New(ic *plugin.InitContext) (interface{}, error) {
} }
type Runtime struct { type Runtime struct {
root string root string
state string state string
shim string address string
shimDebug bool
runtime string
remote bool
address string
monitor runtime.TaskMonitor monitor runtime.TaskMonitor
tasks *runtime.TaskList tasks *runtime.TaskList
db *bolt.DB db *bolt.DB
events *events.Exchange events *events.Exchange
config *Config
} }
func (r *Runtime) ID() string { func (r *Runtime) ID() string {
@ -144,14 +144,18 @@ func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts
return nil, errors.Wrapf(err, "invalid task id") return nil, errors.Wrapf(err, "invalid task id")
} }
ropts, err := r.getRuncOptions(ctx, id)
if err != nil {
return nil, err
}
ec := reaper.Default.Subscribe() ec := reaper.Default.Subscribe()
defer reaper.Default.Unsubscribe(ec) defer reaper.Default.Unsubscribe(ec)
bundle, err := newBundle( bundle, err := newBundle(id,
namespace, id,
filepath.Join(r.state, namespace), filepath.Join(r.state, namespace),
filepath.Join(r.root, namespace), filepath.Join(r.root, namespace),
opts.Spec.Value, r.events) opts.Spec.Value)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -160,36 +164,50 @@ func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts
bundle.Delete() bundle.Delete()
} }
}() }()
s, err := bundle.NewShim(ctx, r.shim, r.address, r.remote, r.shimDebug, opts, func() {
t, err := r.tasks.Get(ctx, id)
if err != nil {
// Task was never started or was already sucessfully deleted
return
}
lc := t.(*Task)
// Stop the monitor shimopt := ShimLocal(r.events)
if err := r.monitor.Stop(lc); err != nil { if !r.config.NoShim {
log.G(ctx).WithError(err).WithFields(logrus.Fields{ var cgroup string
if opts.Options != nil {
v, err := typeurl.UnmarshalAny(opts.Options)
if err != nil {
return nil, err
}
cgroup = v.(*runcopts.CreateOptions).ShimCgroup
}
shimopt = ShimRemote(r.config.Shim, r.address, cgroup, r.config.ShimDebug, func() {
t, err := r.tasks.Get(ctx, id)
if err != nil {
// Task was never started or was already sucessfully deleted
return
}
lc := t.(*Task)
// Stop the monitor
if err := r.monitor.Stop(lc); err != nil {
log.G(ctx).WithError(err).WithFields(logrus.Fields{
"id": id,
"namespace": namespace,
}).Warn("failed to stop monitor")
}
log.G(ctx).WithFields(logrus.Fields{
"id": id, "id": id,
"namespace": namespace, "namespace": namespace,
}).Warn("failed to stop monitor") }).Warn("cleaning up after killed shim")
} err = r.cleanupAfterDeadShim(context.Background(), bundle, namespace, id, lc.pid, ec)
if err == nil {
r.tasks.Delete(ctx, lc)
} else {
log.G(ctx).WithError(err).WithFields(logrus.Fields{
"id": id,
"namespace": namespace,
}).Warn("failed to clen up after killed shim")
}
})
}
log.G(ctx).WithFields(logrus.Fields{ s, err := bundle.NewShimClient(ctx, namespace, shimopt, ropts)
"id": id,
"namespace": namespace,
}).Warn("cleaning up after killed shim")
err = r.cleanupAfterDeadShim(context.Background(), bundle, namespace, id, lc.pid, ec)
if err == nil {
r.tasks.Delete(ctx, lc)
} else {
log.G(ctx).WithError(err).WithFields(logrus.Fields{
"id": id,
"namespace": namespace,
}).Warn("failed to clen up after killed shim")
}
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -200,10 +218,15 @@ func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts
} }
} }
}() }()
runtime := r.config.Runtime
if ropts != nil && ropts.Runtime != "" {
runtime = ropts.Runtime
}
sopts := &shim.CreateTaskRequest{ sopts := &shim.CreateTaskRequest{
ID: id, ID: id,
Bundle: bundle.path, Bundle: bundle.path,
Runtime: r.runtime, Runtime: runtime,
Stdin: opts.IO.Stdin, Stdin: opts.IO.Stdin,
Stdout: opts.IO.Stdout, Stdout: opts.IO.Stdout,
Stderr: opts.IO.Stderr, Stderr: opts.IO.Stderr,
@ -256,11 +279,9 @@ func (r *Runtime) Delete(ctx context.Context, c runtime.Task) (*runtime.Exit, er
} }
bundle := loadBundle( bundle := loadBundle(
lc.id,
filepath.Join(r.state, namespace, lc.id), filepath.Join(r.state, namespace, lc.id),
filepath.Join(r.root, namespace, lc.id), filepath.Join(r.root, namespace, lc.id),
namespace,
lc.id,
r.events,
) )
if err := bundle.Delete(); err != nil { if err := bundle.Delete(); err != nil {
log.G(ctx).WithError(err).Error("failed to delete bundle") log.G(ctx).WithError(err).Error("failed to delete bundle")
@ -313,10 +334,11 @@ func (r *Runtime) loadTasks(ctx context.Context, ns string) ([]*Task, error) {
} }
id := path.Name() id := path.Name()
bundle := loadBundle( bundle := loadBundle(
id,
filepath.Join(r.state, ns, id), filepath.Join(r.state, ns, id),
filepath.Join(r.root, ns, id), filepath.Join(r.root, ns, id),
ns, id, r.events) )
s, err := bundle.Connect(ctx, r.remote) s, err := bundle.NewShimClient(ctx, ns, ShimConnect(), nil)
if err != nil { if err != nil {
log.G(ctx).WithError(err).WithFields(logrus.Fields{ log.G(ctx).WithError(err).WithFields(logrus.Fields{
"id": id, "id": id,
@ -386,6 +408,7 @@ func (r *Runtime) terminate(ctx context.Context, bundle *bundle, ns, id string)
if err != nil { if err != nil {
return err return err
} }
if err := rt.Delete(ctx, id, &runc.DeleteOpts{ if err := rt.Delete(ctx, id, &runc.DeleteOpts{
Force: true, Force: true,
}); err != nil { }); err != nil {
@ -401,18 +424,56 @@ func (r *Runtime) terminate(ctx context.Context, bundle *bundle, ns, id string)
} }
func (r *Runtime) getRuntime(ctx context.Context, ns, id string) (*runc.Runc, error) { func (r *Runtime) getRuntime(ctx context.Context, ns, id string) (*runc.Runc, error) {
ropts, err := r.getRuncOptions(ctx, id)
if err != nil {
return nil, err
}
var (
cmd = r.config.Runtime
root = client.RuncRoot
)
if ropts != nil {
if ropts.Runtime != "" {
cmd = ropts.Runtime
}
if ropts.RuntimeRoot != "" {
root = ropts.RuntimeRoot
}
}
return &runc.Runc{
Command: cmd,
LogFormat: runc.JSON,
PdeathSignal: unix.SIGKILL,
Root: filepath.Join(root, ns),
}, nil
}
func (r *Runtime) getRuncOptions(ctx context.Context, id string) (*runcopts.RuncOptions, error) {
var container containers.Container
if err := r.db.View(func(tx *bolt.Tx) error { if err := r.db.View(func(tx *bolt.Tx) error {
store := metadata.NewContainerStore(tx) store := metadata.NewContainerStore(tx)
var err error var err error
_, err = store.Get(ctx, id) container, err = store.Get(ctx, id)
return err return err
}); err != nil { }); err != nil {
return nil, err return nil, err
} }
return &runc.Runc{
Command: r.runtime, if container.Runtime.Options != nil {
LogFormat: runc.JSON, v, err := typeurl.UnmarshalAny(container.Runtime.Options)
PdeathSignal: unix.SIGKILL, if err != nil {
Root: filepath.Join(client.RuncRoot, ns), return nil, err
}, nil }
ropts, ok := v.(*runcopts.RuncOptions)
if !ok {
return nil, errors.New("invalid runtime options format")
}
return ropts, nil
}
return nil, nil
} }

View File

@ -30,20 +30,20 @@ import (
type ClientOpt func(context.Context, Config) (shim.ShimClient, io.Closer, error) type ClientOpt func(context.Context, Config) (shim.ShimClient, io.Closer, error)
// WithStart executes a new shim process // WithStart executes a new shim process
func WithStart(binary, address string, debug bool, exitHandler func()) ClientOpt { func WithStart(binary, address, daemonAddress, cgroup string, debug bool, exitHandler func()) ClientOpt {
return func(ctx context.Context, config Config) (_ shim.ShimClient, _ io.Closer, err error) { return func(ctx context.Context, config Config) (_ shim.ShimClient, _ io.Closer, err error) {
socket, err := newSocket(config) socket, err := newSocket(address)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
defer socket.Close() defer socket.Close()
f, err := socket.File() f, err := socket.File()
if err != nil { if err != nil {
return nil, nil, errors.Wrapf(err, "failed to get fd for socket %s", config.Address) return nil, nil, errors.Wrapf(err, "failed to get fd for socket %s", address)
} }
defer f.Close() defer f.Close()
cmd := newCommand(binary, address, debug, config, f) cmd := newCommand(binary, daemonAddress, debug, config, f)
ec, err := reaper.Default.Start(cmd) ec, err := reaper.Default.Start(cmd)
if err != nil { if err != nil {
return nil, nil, errors.Wrapf(err, "failed to start shim") return nil, nil, errors.Wrapf(err, "failed to start shim")
@ -59,19 +59,23 @@ func WithStart(binary, address string, debug bool, exitHandler func()) ClientOpt
}() }()
log.G(ctx).WithFields(logrus.Fields{ log.G(ctx).WithFields(logrus.Fields{
"pid": cmd.Process.Pid, "pid": cmd.Process.Pid,
"address": config.Address, "address": address,
"debug": debug, "debug": debug,
}).Infof("shim %s started", binary) }).Infof("shim %s started", binary)
// set shim in cgroup if it is provided // set shim in cgroup if it is provided
if config.CgroupPath != "" { if cgroup != "" {
if err := setCgroup(ctx, config, cmd); err != nil { if err := setCgroup(cgroup, cmd); err != nil {
return nil, nil, err return nil, nil, err
} }
log.G(ctx).WithFields(logrus.Fields{
"pid": cmd.Process.Pid,
"address": address,
}).Infof("shim placed in cgroup %s", cgroup)
} }
if err = sys.SetOOMScore(cmd.Process.Pid, sys.OOMScoreMaxKillable); err != nil { if err = sys.SetOOMScore(cmd.Process.Pid, sys.OOMScoreMaxKillable); err != nil {
return nil, nil, errors.Wrap(err, "failed to set OOM Score on shim") return nil, nil, errors.Wrap(err, "failed to set OOM Score on shim")
} }
c, clo, err := WithConnect(ctx, config) c, clo, err := WithConnect(address)(ctx, config)
if err != nil { if err != nil {
return nil, nil, errors.Wrap(err, "failed to connect") return nil, nil, errors.Wrap(err, "failed to connect")
} }
@ -79,15 +83,26 @@ func WithStart(binary, address string, debug bool, exitHandler func()) ClientOpt
} }
} }
func newCommand(binary, address string, debug bool, config Config, socket *os.File) *exec.Cmd { func newCommand(binary, daemonAddress string, debug bool, config Config, socket *os.File) *exec.Cmd {
args := []string{ args := []string{
"--namespace", config.Namespace, "--namespace", config.Namespace,
"--address", address,
"--workdir", config.WorkDir, "--workdir", config.WorkDir,
"--address", daemonAddress,
}
if config.Criu != "" {
args = append(args, "--criu-path", config.Criu)
}
if config.RuntimeRoot != "" {
args = append(args, "--runtime-root", config.RuntimeRoot)
}
if config.SystemdCgroup {
args = append(args, "--systemd-cgroup")
} }
if debug { if debug {
args = append(args, "--debug") args = append(args, "--debug")
} }
cmd := exec.Command(binary, args...) cmd := exec.Command(binary, args...)
cmd.Dir = config.Path cmd.Dir = config.Path
// make sure the shim can be re-parented to system init // make sure the shim can be re-parented to system init
@ -102,13 +117,13 @@ func newCommand(binary, address string, debug bool, config Config, socket *os.Fi
return cmd return cmd
} }
func newSocket(config Config) (*net.UnixListener, error) { func newSocket(address string) (*net.UnixListener, error) {
if len(config.Address) > 106 { if len(address) > 106 {
return nil, errors.Errorf("%q: unix socket path too long (limit 106)", config.Address) return nil, errors.Errorf("%q: unix socket path too long (limit 106)", address)
} }
l, err := net.Listen("unix", "\x00"+config.Address) l, err := net.Listen("unix", "\x00"+address)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "failed to listen to abstract unix socket %q", config.Address) return nil, errors.Wrapf(err, "failed to listen to abstract unix socket %q", address)
} }
return l.(*net.UnixListener), nil return l.(*net.UnixListener), nil
@ -144,18 +159,20 @@ func dialAddress(address string) string {
} }
// WithConnect connects to an existing shim // WithConnect connects to an existing shim
func WithConnect(ctx context.Context, config Config) (shim.ShimClient, io.Closer, error) { func WithConnect(address string) ClientOpt {
conn, err := connect(config.Address, annonDialer) return func(ctx context.Context, config Config) (shim.ShimClient, io.Closer, error) {
if err != nil { conn, err := connect(address, annonDialer)
return nil, nil, err if err != nil {
return nil, nil, err
}
return shim.NewShimClient(conn), conn, nil
} }
return shim.NewShimClient(conn), conn, nil
} }
// WithLocal uses an in process shim // WithLocal uses an in process shim
func WithLocal(publisher events.Publisher) func(context.Context, Config) (shim.ShimClient, io.Closer, error) { func WithLocal(publisher events.Publisher) func(context.Context, Config) (shim.ShimClient, io.Closer, error) {
return func(ctx context.Context, config Config) (shim.ShimClient, io.Closer, error) { return func(ctx context.Context, config Config) (shim.ShimClient, io.Closer, error) {
service, err := NewService(config.Path, config.Namespace, config.WorkDir, publisher) service, err := NewService(config, publisher)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -164,11 +181,12 @@ func WithLocal(publisher events.Publisher) func(context.Context, Config) (shim.S
} }
type Config struct { type Config struct {
Address string Path string
Path string Namespace string
Namespace string WorkDir string
CgroupPath string Criu string
WorkDir string RuntimeRoot string
SystemdCgroup bool
} }
// New returns a new shim client // New returns a new shim client

View File

@ -3,14 +3,11 @@
package shim package shim
import ( import (
"context"
"os/exec" "os/exec"
"syscall" "syscall"
"github.com/containerd/cgroups" "github.com/containerd/cgroups"
"github.com/containerd/containerd/log"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
) )
var atter = syscall.SysProcAttr{ var atter = syscall.SysProcAttr{
@ -18,19 +15,15 @@ var atter = syscall.SysProcAttr{
Setpgid: true, Setpgid: true,
} }
func setCgroup(ctx context.Context, config Config, cmd *exec.Cmd) error { func setCgroup(cgroupPath string, cmd *exec.Cmd) error {
cg, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(config.CgroupPath)) cg, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(cgroupPath))
if err != nil { if err != nil {
return errors.Wrapf(err, "failed to load cgroup %s", config.CgroupPath) return errors.Wrapf(err, "failed to load cgroup %s", cgroupPath)
} }
if err := cg.Add(cgroups.Process{ if err := cg.Add(cgroups.Process{
Pid: cmd.Process.Pid, Pid: cmd.Process.Pid,
}); err != nil { }); err != nil {
return errors.Wrapf(err, "failed to join cgroup %s", config.CgroupPath) return errors.Wrapf(err, "failed to join cgroup %s", cgroupPath)
} }
log.G(ctx).WithFields(logrus.Fields{
"pid": cmd.Process.Pid,
"address": config.Address,
}).Infof("shim placed in cgroup %s", config.CgroupPath)
return nil return nil
} }

View File

@ -3,7 +3,6 @@
package shim package shim
import ( import (
"context"
"os/exec" "os/exec"
"syscall" "syscall"
) )
@ -12,6 +11,6 @@ var atter = syscall.SysProcAttr{
Setpgid: true, Setpgid: true,
} }
func setCgroup(ctx context.Context, config Config, cmd *exec.Cmd) error { func setCgroup(cgroupPath string, cmd *exec.Cmd) error {
return nil return nil
} }

View File

@ -56,7 +56,7 @@ type initProcess struct {
rootfs string rootfs string
} }
func newInitProcess(context context.Context, plat platform, path, namespace, workDir string, r *shimapi.CreateTaskRequest) (*initProcess, error) { func (s *Service) newInitProcess(context context.Context, r *shimapi.CreateTaskRequest) (*initProcess, error) {
var success bool var success bool
if err := identifiers.Validate(r.ID); err != nil { if err := identifiers.Validate(r.ID); err != nil {
@ -71,7 +71,7 @@ func newInitProcess(context context.Context, plat platform, path, namespace, wor
options = *v.(*runcopts.CreateOptions) options = *v.(*runcopts.CreateOptions)
} }
rootfs := filepath.Join(path, "rootfs") rootfs := filepath.Join(s.config.Path, "rootfs")
// count the number of successful mounts so we can undo // count the number of successful mounts so we can undo
// what was actually done rather than what should have been // what was actually done rather than what should have been
// done. // done.
@ -94,17 +94,19 @@ func newInitProcess(context context.Context, plat platform, path, namespace, wor
} }
} }
runtime := &runc.Runc{ runtime := &runc.Runc{
Command: r.Runtime, Command: r.Runtime,
Log: filepath.Join(path, "log.json"), Log: filepath.Join(s.config.Path, "log.json"),
LogFormat: runc.JSON, LogFormat: runc.JSON,
PdeathSignal: syscall.SIGKILL, PdeathSignal: syscall.SIGKILL,
Root: filepath.Join(RuncRoot, namespace), Root: filepath.Join(s.config.RuntimeRoot, s.config.Namespace),
Criu: s.config.Criu,
SystemdCgroup: s.config.SystemdCgroup,
} }
p := &initProcess{ p := &initProcess{
id: r.ID, id: r.ID,
bundle: r.Bundle, bundle: r.Bundle,
runtime: runtime, runtime: runtime,
platform: plat, platform: s.platform,
stdio: stdio{ stdio: stdio{
stdin: r.Stdin, stdin: r.Stdin,
stdout: r.Stdout, stdout: r.Stdout,
@ -112,7 +114,7 @@ func newInitProcess(context context.Context, plat platform, path, namespace, wor
terminal: r.Terminal, terminal: r.Terminal,
}, },
rootfs: rootfs, rootfs: rootfs,
workDir: workDir, workDir: s.config.WorkDir,
} }
p.initState = &createdState{p: p} p.initState = &createdState{p: p}
var ( var (
@ -133,7 +135,7 @@ func newInitProcess(context context.Context, plat platform, path, namespace, wor
return nil, errors.Wrap(err, "failed to create OCI runtime io pipes") return nil, errors.Wrap(err, "failed to create OCI runtime io pipes")
} }
} }
pidFile := filepath.Join(path, InitPidFile) pidFile := filepath.Join(s.config.Path, InitPidFile)
if r.Checkpoint != "" { if r.Checkpoint != "" {
opts := &runc.RestoreOpts{ opts := &runc.RestoreOpts{
CheckpointOpts: runc.CheckpointOpts{ CheckpointOpts: runc.CheckpointOpts{
@ -178,7 +180,7 @@ func newInitProcess(context context.Context, plat platform, path, namespace, wor
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to retrieve console master") return nil, errors.Wrap(err, "failed to retrieve console master")
} }
console, err = plat.copyConsole(context, console, r.Stdin, r.Stdout, r.Stderr, &p.WaitGroup, &copyWaitGroup) console, err = s.platform.copyConsole(context, console, r.Stdin, r.Stdout, r.Stderr, &p.WaitGroup, &copyWaitGroup)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to start console copy") return nil, errors.Wrap(err, "failed to start console copy")
} }

View File

@ -33,7 +33,7 @@ func (c *local) Start(ctx context.Context, in *shimapi.StartRequest, opts ...grp
func (c *local) Delete(ctx context.Context, in *google_protobuf.Empty, opts ...grpc.CallOption) (*shimapi.DeleteResponse, error) { func (c *local) Delete(ctx context.Context, in *google_protobuf.Empty, opts ...grpc.CallOption) (*shimapi.DeleteResponse, error) {
// make sure we unmount the containers rootfs for this local // make sure we unmount the containers rootfs for this local
if err := unix.Unmount(filepath.Join(c.s.path, "rootfs"), 0); err != nil { if err := unix.Unmount(filepath.Join(c.s.config.Path, "rootfs"), 0); err != nil {
return nil, err return nil, err
} }
return c.s.Delete(ctx, in) return c.s.Delete(ctx, in)

View File

@ -32,23 +32,21 @@ var empty = &google_protobuf.Empty{}
const RuncRoot = "/run/containerd/runc" const RuncRoot = "/run/containerd/runc"
// NewService returns a new shim service that can be used via GRPC // NewService returns a new shim service that can be used via GRPC
func NewService(path, namespace, workDir string, publisher events.Publisher) (*Service, error) { func NewService(config Config, publisher events.Publisher) (*Service, error) {
if namespace == "" { if config.Namespace == "" {
return nil, fmt.Errorf("shim namespace cannot be empty") return nil, fmt.Errorf("shim namespace cannot be empty")
} }
context := namespaces.WithNamespace(context.Background(), namespace) context := namespaces.WithNamespace(context.Background(), config.Namespace)
context = log.WithLogger(context, logrus.WithFields(logrus.Fields{ context = log.WithLogger(context, logrus.WithFields(logrus.Fields{
"namespace": namespace, "namespace": config.Namespace,
"path": config.Path,
"pid": os.Getpid(), "pid": os.Getpid(),
"path": path,
})) }))
s := &Service{ s := &Service{
path: path, config: config,
context: context,
processes: make(map[string]process), processes: make(map[string]process),
events: make(chan interface{}, 4096), events: make(chan interface{}, 4096),
namespace: namespace,
context: context,
workDir: workDir,
ec: reaper.Default.Subscribe(), ec: reaper.Default.Subscribe(),
} }
go s.processExits() go s.processExits()
@ -67,25 +65,24 @@ type platform interface {
} }
type Service struct { type Service struct {
path string mu sync.Mutex
id string
bundle string
mu sync.Mutex
processes map[string]process
events chan interface{}
deferredEvent interface{}
namespace string
context context.Context
ec chan runc.Exit
workDir string config Config
platform platform context context.Context
processes map[string]process
events chan interface{}
platform platform
ec chan runc.Exit
// Filled by Create()
id string
bundle string
} }
func (s *Service) Create(ctx context.Context, r *shimapi.CreateTaskRequest) (*shimapi.CreateTaskResponse, error) { func (s *Service) Create(ctx context.Context, r *shimapi.CreateTaskRequest) (*shimapi.CreateTaskResponse, error) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
process, err := newInitProcess(ctx, s.platform, s.path, s.namespace, s.workDir, r) process, err := s.newInitProcess(ctx, r)
if err != nil { if err != nil {
return nil, errdefs.ToGRPC(err) return nil, errdefs.ToGRPC(err)
} }
@ -194,7 +191,7 @@ func (s *Service) Exec(ctx context.Context, r *shimapi.ExecProcessRequest) (*goo
return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created") return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
} }
process, err := newExecProcess(ctx, s.path, r, p.(*initProcess), r.ID) process, err := newExecProcess(ctx, s.config.Path, r, p.(*initProcess), r.ID)
if err != nil { if err != nil {
return nil, errdefs.ToGRPC(err) return nil, errdefs.ToGRPC(err)
} }

View File

@ -335,18 +335,13 @@ func writeContainer(bkt *bolt.Bucket, container *containers.Container) error {
return err return err
} }
obkt, err := rbkt.CreateBucket(bucketKeyOptions)
if err != nil {
return err
}
if container.Runtime.Options != nil { if container.Runtime.Options != nil {
data, err := proto.Marshal(container.Runtime.Options) data, err := proto.Marshal(container.Runtime.Options)
if err != nil { if err != nil {
return err return err
} }
if err := obkt.Put(bucketKeyOptions, data); err != nil { if err := rbkt.Put(bucketKeyOptions, data); err != nil {
return err return err
} }
} }