Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First draft of CLI docker integration #7

Merged
merged 4 commits into from
May 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,8 @@ go 1.14

require (
github.com/AlecAivazis/survey/v2 v2.2.12
github.com/Microsoft/go-winio v0.5.0 // indirect
github.com/containerd/containerd v1.5.2 // indirect
github.com/docker/docker v20.10.6+incompatible
github.com/docker/go-connections v0.4.0 // indirect
github.com/go-test/deep v1.0.7
github.com/mitchellh/go-homedir v1.1.0
github.com/morikuni/aec v1.0.0 // indirect
github.com/spf13/cobra v1.1.3
github.com/stretchr/testify v1.7.0
gopkg.in/yaml.v2 v2.4.0
Expand Down
694 changes: 6 additions & 688 deletions go.sum

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions src/cmd/get/containers/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package containers
import (
"context"
"fmt"
"strings"

"github.com/spf13/cobra"

Expand All @@ -22,9 +23,10 @@ func New() *cobra.Command {
}

func run(ctx context.Context) error {
api, err := docker.NewAPI()
names, err := docker.ListContainers(ctx)
if err != nil {
return fmt.Errorf("failed to connect to docker client: %w", err)
return err
}
return api.ListContainers(ctx)
fmt.Println(strings.Join(names, "\n"))
return nil
}
7 changes: 1 addition & 6 deletions src/cmd/start/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,5 @@ func run(ctx context.Context, name string) error {

containerName := fmt.Sprintf("yey-%s-%s-%s", shortImageName, yeyContext.Name, yeyContext.Hash())

api, err := docker.NewAPI()
if err != nil {
return fmt.Errorf("failed to connect to docker client: %w", err)
}

return api.Start(ctx, yeyContext, containerName)
return docker.Start(ctx, yeyContext, containerName)
}
10 changes: 6 additions & 4 deletions src/internal/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import (

// Context represents execution configuration for some docker container
type Context struct {
Name string `yaml:",omitempty"`
Image string
Env map[string]string
Mounts map[string]string
Name string `yaml:",omitempty"`
Image string
Env map[string]string
Mounts map[string]string
Cmd []string
EntryPoint []string
}

// Clone returns a deep-copy of this context
Expand Down
5 changes: 0 additions & 5 deletions src/internal/docker.go

This file was deleted.

138 changes: 0 additions & 138 deletions src/internal/docker/api.go

This file was deleted.

116 changes: 95 additions & 21 deletions src/internal/docker/cli.go
Original file line number Diff line number Diff line change
@@ -1,38 +1,112 @@
package docker

import (
"context"
"fmt"
"os"
"os/exec"
"strings"

"github.com/mitchellh/go-homedir"
yey "github.com/silphid/yey/src/internal"
)

type CLI struct{}
func Start(ctx context.Context, yeyCtx yey.Context, containerName string) error {
// Determine whether we need to run or exec container
status, err := getContainerStatus(ctx, containerName)
if err != nil {
return err
}

func (c CLI) Start(ct yey.Context, imageTag, containerName string) error {
return fmt.Errorf("not implemented")
switch status {
case "":
return runContainer(ctx, yeyCtx, containerName)
case "exited":
return startContainer(ctx, containerName)
case "running":
return execContainer(ctx, containerName, yeyCtx.Cmd)
default:
return fmt.Errorf("container %q in unexpected state %q", containerName, status)
}
}

func ListContainers(ctx context.Context) ([]string, error) {
cmd := exec.Command("docker", "ps", "--all", "--filter", "name=yey-*", "--format", "{{.Names}}")
output, err := cmd.Output()
if err != nil {
return nil, err
}
return strings.Split(string(output), "\n"), nil
}

// Get running ID and state
// docker ps --all --filter "name=al" --format '{{.ID}}|{{.State}}'
// state="exited"|"running"
func getContainerStatus(ctx context.Context, name string) (string, error) {
cmd := exec.CommandContext(ctx, "docker", "inspect", name, "--format", "{{.State.Status}}")

// Run
// docker run -it --name al alpine
output, err := cmd.CombinedOutput()
if err != nil {
if strings.Contains(string(output), "No such object") {
return "", nil
}
return "", fmt.Errorf("failed to get container status: %s: %w", output, err)
}

// Exec
// run docker exec -it "${DOCKER_EXEC_ARGS[@]}" "${DOCKER_CONTAINER}" zsh
return strings.TrimSpace(string(output)), nil
}

// type containerState string
func runContainer(ctx context.Context, yeyCtx yey.Context, containerName string) error {
cwd, err := os.Getwd()
if err != nil {
return err
}

args := []string{
"run",
"--name", containerName,
"-it",
// "--env LS_COLORS",
// "--env TERM",
// "--env TERM_COLOR",
// "--env TERM_PROGRAM",
"--env", "YEY_WORK_DIR=" + cwd,
"--env", "YEY_CONTEXT=" + yeyCtx.Name,
}

// const (
// stateRunning containerState = "running"
// stateExited = "exited"
// )
// Context env vars
for name, value := range yeyCtx.Env {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the environment only needed to be passed at run? Shouldn't exec into a container that was run with an env keep the env that was set previously?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c'est une question que je me demandais, à tester quand on aura un moment

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

je pense qu'en faisaint un split entre exec et run tu vas ne meme pas avoir besoin de cette fonction apres, car tout c'est args la sont seulement vraiment important quand tu fais run. Et donc tu n'auras pas besoin d'une function a part comme celle ci.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

je viens de vérifier et les env vars sont persistants across docker run, exec et start.

args = append(args, "--env", fmt.Sprintf("%s=%s", name, value))
}

// type container struct {
// state containerState
// }
home, err := homedir.Dir()
if err != nil {
return fmt.Errorf("failed to detect user home directory: %w", err)
}

// func getContainer(name string) (container, error) {
// return container{}, nil
// }
for key, value := range yeyCtx.Mounts {
args = append(
args,
"--volume",
fmt.Sprintf("%s:%s", strings.ReplaceAll(key, "$HOME", home), value),
)
}

args = append(args, yeyCtx.Image)
args = append(args, yeyCtx.Cmd...)

return attachStdPipes(exec.CommandContext(ctx, "docker", args...)).Run()
}

func startContainer(ctx context.Context, containerName string) error {
return attachStdPipes(exec.CommandContext(ctx, "docker", "start", "-i", containerName)).Run()
}

func execContainer(ctx context.Context, containerName string, cmd []string) error {
args := append([]string{"exec", "-ti", containerName}, cmd...)
return attachStdPipes(exec.CommandContext(ctx, "docker", args...)).Run()
}

func attachStdPipes(cmd *exec.Cmd) *exec.Cmd {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
return cmd
}