Add exec functionality to shim
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
parent
d5d2e586cd
commit
e09b0b0c35
7 changed files with 1351 additions and 93 deletions
1264
api/shim/shim.pb.go
1264
api/shim/shim.pb.go
File diff suppressed because it is too large
Load diff
|
@ -5,7 +5,7 @@ package containerd.v1;
|
||||||
import "google/protobuf/empty.proto";
|
import "google/protobuf/empty.proto";
|
||||||
import "gogoproto/gogo.proto";
|
import "gogoproto/gogo.proto";
|
||||||
|
|
||||||
service ShimService {
|
service Shim {
|
||||||
rpc Create(CreateRequest) returns (CreateResponse);
|
rpc Create(CreateRequest) returns (CreateResponse);
|
||||||
rpc Start(StartRequest) returns (google.protobuf.Empty);
|
rpc Start(StartRequest) returns (google.protobuf.Empty);
|
||||||
rpc Delete(DeleteRequest) returns (DeleteResponse);
|
rpc Delete(DeleteRequest) returns (DeleteResponse);
|
||||||
|
@ -14,7 +14,7 @@ service ShimService {
|
||||||
}
|
}
|
||||||
|
|
||||||
message CreateRequest {
|
message CreateRequest {
|
||||||
string id = 1 [(gogoproto.customname) = "ID"];
|
string id = 1 [(gogoproto.customname) = "ID"];
|
||||||
string bundle = 2;
|
string bundle = 2;
|
||||||
string runtime = 3;
|
string runtime = 3;
|
||||||
bool no_pivot = 4;
|
bool no_pivot = 4;
|
||||||
|
@ -40,7 +40,32 @@ message DeleteResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
message ExecRequest {
|
message ExecRequest {
|
||||||
|
string id = 1 [(gogoproto.customname) = "ID"];
|
||||||
|
bool terminal = 2;
|
||||||
|
string stdin = 3;
|
||||||
|
string stdout = 4;
|
||||||
|
string stderr = 5;
|
||||||
|
User user = 6;
|
||||||
|
repeated string args = 7;
|
||||||
|
repeated string env = 8;
|
||||||
|
string cwd = 9;
|
||||||
|
repeated string capabilities = 10;
|
||||||
|
repeated Rlimit rlimits = 11;
|
||||||
|
bool no_new_privileges = 12;
|
||||||
|
string apparmor_profile = 13;
|
||||||
|
string selinux_label = 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
message User {
|
||||||
|
uint32 uid = 1;
|
||||||
|
uint32 gid = 2;
|
||||||
|
repeated uint32 additional_gids = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Rlimit {
|
||||||
|
string type = 1;
|
||||||
|
uint64 hard = 2;
|
||||||
|
uint64 soft = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ExecResponse {
|
message ExecResponse {
|
||||||
|
@ -49,6 +74,6 @@ message ExecResponse {
|
||||||
|
|
||||||
message PtyRequest {
|
message PtyRequest {
|
||||||
uint32 pid = 1;
|
uint32 pid = 1;
|
||||||
uint32 width = 2;
|
uint32 width = 2;
|
||||||
uint32 height = 3;
|
uint32 height = 3;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,127 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
func newExecProcess(id, bundle, runtimeName string) (process, error) {
|
import (
|
||||||
return nil, nil
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
runc "github.com/crosbymichael/go-runc"
|
||||||
|
"github.com/docker/containerd/api/shim"
|
||||||
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
type execProcess struct {
|
||||||
|
sync.WaitGroup
|
||||||
|
|
||||||
|
id string
|
||||||
|
console *runc.Console
|
||||||
|
io runc.IO
|
||||||
|
status int
|
||||||
|
pid int
|
||||||
|
|
||||||
|
parent *initProcess
|
||||||
|
}
|
||||||
|
|
||||||
|
func newExecProcess(context context.Context, r *shim.ExecRequest, parent *initProcess) (process, error) {
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
e := &execProcess{
|
||||||
|
id: r.ID,
|
||||||
|
parent: parent,
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
socket *runc.ConsoleSocket
|
||||||
|
io runc.IO
|
||||||
|
pidfile = filepath.Join(cwd, fmt.Sprintf("%s.pid", r.ID))
|
||||||
|
)
|
||||||
|
if r.Terminal {
|
||||||
|
if socket, err = runc.NewConsoleSocket(filepath.Join(cwd, "pty.sock")); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO: get uid/gid
|
||||||
|
if io, err = runc.NewPipeIO(0, 0); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
e.io = io
|
||||||
|
}
|
||||||
|
opts := &runc.ExecOpts{
|
||||||
|
PidFile: pidfile,
|
||||||
|
ConsoleSocket: socket,
|
||||||
|
IO: io,
|
||||||
|
Detach: true,
|
||||||
|
Tty: socket != nil,
|
||||||
|
}
|
||||||
|
if err := parent.runc.Exec(context, r.ID, processFromRequest(r), opts); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pid, err := runc.ReadPidFile(opts.PidFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
e.pid = pid
|
||||||
|
return e, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processFromRequest(r *shim.ExecRequest) specs.Process {
|
||||||
|
return specs.Process{
|
||||||
|
Terminal: r.Terminal,
|
||||||
|
User: specs.User{
|
||||||
|
UID: r.User.Uid,
|
||||||
|
GID: r.User.Gid,
|
||||||
|
AdditionalGids: r.User.AdditionalGids,
|
||||||
|
},
|
||||||
|
Rlimits: rlimits(r.Rlimits),
|
||||||
|
Args: r.Args,
|
||||||
|
Env: r.Env,
|
||||||
|
Cwd: r.Cwd,
|
||||||
|
Capabilities: r.Capabilities,
|
||||||
|
NoNewPrivileges: r.NoNewPrivileges,
|
||||||
|
ApparmorProfile: r.ApparmorProfile,
|
||||||
|
SelinuxLabel: r.SelinuxLabel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func rlimits(rr []*shim.Rlimit) (o []specs.LinuxRlimit) {
|
||||||
|
for _, r := range rr {
|
||||||
|
o = append(o, specs.LinuxRlimit{
|
||||||
|
Type: r.Type,
|
||||||
|
Hard: r.Hard,
|
||||||
|
Soft: r.Soft,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *execProcess) Pid() int {
|
||||||
|
return e.pid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *execProcess) Status() int {
|
||||||
|
return e.status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *execProcess) Exited(status int) {
|
||||||
|
e.status = status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *execProcess) Start(_ context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *execProcess) Delete(context context.Context) error {
|
||||||
|
e.Wait()
|
||||||
|
e.io.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *execProcess) Resize(ws runc.WinSize) error {
|
||||||
|
if e.console == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return e.console.Resize(ws)
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,9 +52,10 @@ func newInitProcess(context context.Context, r *shim.CreateRequest) (process, er
|
||||||
if io, err = runc.NewPipeIO(0, 0); err != nil {
|
if io, err = runc.NewPipeIO(0, 0); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
p.io = io
|
||||||
}
|
}
|
||||||
opts := &runc.CreateOpts{
|
opts := &runc.CreateOpts{
|
||||||
PidFile: filepath.Join(cwd, "pid"),
|
PidFile: filepath.Join(cwd, "init.pid"),
|
||||||
ConsoleSocket: socket,
|
ConsoleSocket: socket,
|
||||||
IO: io,
|
IO: io,
|
||||||
NoPivot: r.NoPivot,
|
NoPivot: r.NoPivot,
|
||||||
|
|
|
@ -56,7 +56,7 @@ func main() {
|
||||||
processes: make(map[int]process),
|
processes: make(map[int]process),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
shim.RegisterShimServiceServer(server, sv)
|
shim.RegisterShimServer(server, sv)
|
||||||
l, err := utils.CreateUnixSocket("shim.sock")
|
l, err := utils.CreateUnixSocket("shim.sock")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -62,7 +62,17 @@ func (s *service) Delete(ctx context.Context, r *shim.DeleteRequest) (*shim.Dele
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Exec(ctx context.Context, r *shim.ExecRequest) (*shim.ExecResponse, error) {
|
func (s *service) Exec(ctx context.Context, r *shim.ExecRequest) (*shim.ExecResponse, error) {
|
||||||
return nil, nil
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
process, err := newExecProcess(ctx, r, s.processes[s.initPid].(*initProcess))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pid := process.Pid()
|
||||||
|
s.processes[pid] = process
|
||||||
|
return &shim.ExecResponse{
|
||||||
|
Pid: uint32(pid),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Pty(ctx context.Context, r *shim.PtyRequest) (*google_protobuf.Empty, error) {
|
func (s *service) Pty(ctx context.Context, r *shim.PtyRequest) (*google_protobuf.Empty, error) {
|
||||||
|
|
|
@ -104,7 +104,7 @@ var shimDeleteCommand = cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func getShimService() (shim.ShimServiceClient, error) {
|
func getShimService() (shim.ShimClient, error) {
|
||||||
bindSocket := "shim.sock"
|
bindSocket := "shim.sock"
|
||||||
|
|
||||||
// reset the logger for grpc to log to dev/null so that it does not mess with our stdio
|
// reset the logger for grpc to log to dev/null so that it does not mess with our stdio
|
||||||
|
@ -119,6 +119,6 @@ func getShimService() (shim.ShimServiceClient, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return shim.NewShimServiceClient(conn), nil
|
return shim.NewShimClient(conn), nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue