diff --git a/api/exec.go b/api/exec.go new file mode 100644 index 00000000..b0d7441e --- /dev/null +++ b/api/exec.go @@ -0,0 +1,49 @@ +package api + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io/ioutil" + + docker "github.com/docker/docker/api/types" +) + +type ExecCreateConfig struct { + docker.ExecConfig +} + +type ExecCreateResponse struct { + docker.IDResponse +} + +type ExecStartConfig struct { + Detach bool `json:"Detach"` + Tty bool `json:"Tty"` +} + +func (c *API) CreateExec(ctx context.Context, container string, opts ExecCreateConfig) (*ExecCreateResponse, error) { + payload, err := json.Marshal(opts) + if err != nil { + return nil, err + } + + res, err := c.Post(ctx, fmt.Sprintf("/v1.0.0/libpod/containers/%s/exec", container), bytes.NewBuffer(payload)) + if err != nil { + return nil, err + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err + } + + response := &ExecCreateResponse{} + if err = json.Unmarshal(body, &response); err != nil { + return nil, err + } + + return response, nil +} diff --git a/driver.go b/driver.go index 8f82fc07..df6e26f6 100644 --- a/driver.go +++ b/driver.go @@ -701,7 +701,19 @@ func (d *Driver) SignalTask(taskID string, signal string) error { // ExecTask function is used by the Nomad client to execute commands inside the task execution context. func (d *Driver) ExecTask(taskID string, cmd []string, timeout time.Duration) (*drivers.ExecTaskResult, error) { - return nil, fmt.Errorf("Podman driver does not support exec") + task, ok := d.tasks.Get(taskID) + if !ok { + return nil, drivers.ErrTaskNotFound + } + + if len(cmd) == 0 { + return nil, fmt.Errorf("cmd is required, but was empty") + } + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + return task.Exec(ctx, cmd[0], cmd[1:]) } func (d *Driver) containerMounts(task *drivers.TaskConfig, driverConfig *TaskConfig) ([]spec.Mount, error) { diff --git a/examples/payload.json b/examples/payload.json new file mode 100644 index 00000000..841caddc --- /dev/null +++ b/examples/payload.json @@ -0,0 +1,8 @@ +{ + "AttachStdin": false, + "AttachStdout": true, + "AttachStderr": true, + "Cmd": ["sh"], + "Privileged": true, + "Tty": true +} diff --git a/examples/payload2.json b/examples/payload2.json new file mode 100644 index 00000000..0bac47b4 --- /dev/null +++ b/examples/payload2.json @@ -0,0 +1,4 @@ +{ + "Detach": false, + "Tty": true +} diff --git a/go.mod b/go.mod index aa7a0c74..021ab27d 100644 --- a/go.mod +++ b/go.mod @@ -12,8 +12,10 @@ replace ( require ( github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect + github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e github.com/container-storage-interface/spec v1.2.0 // indirect github.com/containernetworking/plugins v0.8.5 // indirect + github.com/docker/docker v17.12.0-ce-rc1.0.20200330121334-7f8b4b621b5d+incompatible github.com/docker/go-metrics v0.0.1 // indirect github.com/go-ole/go-ole v1.2.4 // indirect github.com/google/go-cmp v0.5.0 // indirect diff --git a/handle.go b/handle.go index b793005e..e97e7bf3 100644 --- a/handle.go +++ b/handle.go @@ -141,7 +141,6 @@ func (h *TaskHandle) runStatsEmitter(ctx context.Context, statsChannel chan *dri } func (h *TaskHandle) runContainerMonitor() { - timer := time.NewTimer(0) interval := time.Second * 1 h.logger.Debug("Monitoring container", "container", h.containerID) @@ -209,3 +208,46 @@ func (h *TaskHandle) runContainerMonitor() { h.stateLock.Unlock() } } + +func (h *TaskHandle) Exec(ctx context.Context, cmd string, args []string) (*drivers.ExecTaskResult, error) { + fullCmd := make([]string, len(args)+1) + fullCmd[0] = cmd + copy(fullCmd[1:], args) + + createExecOpts := api.ExecCreateConfig{} + createExecOpts.AttachStderr = true + createExecOpts.AttachStdout = true + createExecOpts.AttachStdin = false + createExecOpts.Tty = false + createExecOpts.Cmd = fullCmd + + createResp, err := h.driver.podman.CreateExec(ctx, h.containerID, createExecOpts) + if err != nil { + return nil, err + } + + return &drivers.ExecTaskResult{Stdout: []byte(createResp.ID)}, nil +} + +// execResult := &drivers.ExecTaskResult{ExitResult: &drivers.ExitResult{}} +// stdout, _ := circbuf.NewBuffer(int64(drivers.CheckBufSize)) +// stderr, _ := circbuf.NewBuffer(int64(drivers.CheckBufSize)) +// startOpts := docker.StartExecOptions{ +// Detach: false, +// Tty: false, +// OutputStream: stdout, +// ErrorStream: stderr, +// Context: ctx, +// } +// if err := client.StartExec(exec.ID, startOpts); err != nil { +// return nil, err +// } +// execResult.Stdout = stdout.Bytes() +// execResult.Stderr = stderr.Bytes() +// res, err := client.InspectExec(exec.ID) +// if err != nil { +// return execResult, err +// } + +// execResult.ExitResult.ExitCode = res.ExitCode +// return execResult, nil