Merge pull request #326 from docker/run_follow_logs

Run containers and attach to logs by default, detach with -d option
This commit is contained in:
Guillaume Tardif 2020-07-02 17:02:33 +02:00 committed by GitHub
commit 4a1b50a9cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 76 additions and 12 deletions

View File

@ -57,9 +57,7 @@ func runLogs(ctx context.Context, containerName string, opts logsOpts) error {
if err != nil { if err != nil {
return errors.Wrap(err, "cannot connect to backend") return errors.Wrap(err, "cannot connect to backend")
} }
var con io.Writer var con io.Writer = os.Stdout
con = os.Stdout
if c, err := console.ConsoleFromFile(os.Stdout); err == nil { if c, err := console.ConsoleFromFile(os.Stdout); err == nil {
con = c con = c
} }

View File

@ -19,9 +19,14 @@ package run
import ( import (
"context" "context"
"fmt" "fmt"
"io"
"os"
"github.com/containerd/console"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/docker/api/containers"
"github.com/docker/api/cli/options/run" "github.com/docker/api/cli/options/run"
"github.com/docker/api/client" "github.com/docker/api/client"
"github.com/docker/api/progress" "github.com/docker/api/progress"
@ -43,7 +48,7 @@ func Command() *cobra.Command {
cmd.Flags().StringVar(&opts.Name, "name", "", "Assign a name to the container") cmd.Flags().StringVar(&opts.Name, "name", "", "Assign a name to the container")
cmd.Flags().StringArrayVarP(&opts.Labels, "label", "l", []string{}, "Set meta data on a container") cmd.Flags().StringArrayVarP(&opts.Labels, "label", "l", []string{}, "Set meta data on a container")
cmd.Flags().StringArrayVarP(&opts.Volumes, "volume", "v", []string{}, "Volume. Ex: user:key@my_share:/absolute/path/to/target") cmd.Flags().StringArrayVarP(&opts.Volumes, "volume", "v", []string{}, "Volume. Ex: user:key@my_share:/absolute/path/to/target")
cmd.Flags().BoolP("detach", "d", true, "Run container in background and print container ID") cmd.Flags().BoolVarP(&opts.Detach, "detach", "d", false, "Run container in background and print container ID")
cmd.Flags().Float64Var(&opts.Cpus, "cpus", 1., "Number of CPUs") cmd.Flags().Float64Var(&opts.Cpus, "cpus", 1., "Number of CPUs")
cmd.Flags().VarP(&opts.Memory, "memory", "m", "Memory limit") cmd.Flags().VarP(&opts.Memory, "memory", "m", "Memory limit")
@ -64,8 +69,22 @@ func runRun(ctx context.Context, image string, opts run.Opts) error {
err = progress.Run(ctx, func(ctx context.Context) error { err = progress.Run(ctx, func(ctx context.Context) error {
return c.ContainerService().Run(ctx, containerConfig) return c.ContainerService().Run(ctx, containerConfig)
}) })
if err == nil { if err != nil {
fmt.Println(opts.Name) return err
} }
return err if !opts.Detach {
var con io.Writer = os.Stdout
if c, err := console.ConsoleFromFile(os.Stdout); err == nil {
con = c
}
req := containers.LogsRequest{
Follow: true,
Writer: con,
}
return c.ContainerService().Logs(ctx, opts.Name, req)
}
fmt.Println(opts.Name)
return nil
} }

View File

@ -5,7 +5,7 @@ Usage:
Flags: Flags:
--cpus float Number of CPUs (default 1) --cpus float Number of CPUs (default 1)
-d, --detach Run container in background and print container ID (default true) -d, --detach Run container in background and print container ID
-l, --label stringArray Set meta data on a container -l, --label stringArray Set meta data on a container
-m, --memory bytes Memory limit -m, --memory bytes Memory limit
--name string Assign a name to the container --name string Assign a name to the container

View File

@ -36,6 +36,7 @@ type Opts struct {
Volumes []string Volumes []string
Cpus float64 Cpus float64
Memory formatter.MemBytes Memory formatter.MemBytes
Detach bool
} }
// ToContainerConfig convert run options to a container configuration // ToContainerConfig convert run options to a container configuration

View File

@ -45,7 +45,7 @@ func (m *LocalBackendTestSuite) TestPs() {
} }
func (m *LocalBackendTestSuite) TestRun() { func (m *LocalBackendTestSuite) TestRun() {
_, err := m.NewDockerCommand("run", "--name", "nginx", "nginx").Exec() _, err := m.NewDockerCommand("run", "-d", "--name", "nginx", "nginx").Exec()
require.Nil(m.T(), err) require.Nil(m.T(), err)
out := m.NewDockerCommand("ps").ExecOrDie() out := m.NewDockerCommand("ps").ExecOrDie()
defer func() { defer func() {
@ -55,7 +55,7 @@ func (m *LocalBackendTestSuite) TestRun() {
} }
func (m *LocalBackendTestSuite) TestRunWithPorts() { func (m *LocalBackendTestSuite) TestRunWithPorts() {
_, err := m.NewDockerCommand("run", "--name", "nginx", "-p", "8080:80", "nginx").Exec() _, err := m.NewDockerCommand("run", "-d", "--name", "nginx", "-p", "8080:80", "nginx").Exec()
require.Nil(m.T(), err) require.Nil(m.T(), err)
out := m.NewDockerCommand("ps").ExecOrDie() out := m.NewDockerCommand("ps").ExecOrDie()
defer func() { defer func() {

View File

@ -125,7 +125,7 @@ func (s *E2eACISuite) TestACIBackend() {
uploadFile(credential, u.String(), testFileName, testFileContent) uploadFile(credential, u.String(), testFileName, testFileContent)
mountTarget := "/usr/share/nginx/html" mountTarget := "/usr/share/nginx/html"
output := s.NewDockerCommand("run", "nginx", output := s.NewDockerCommand("run", "-d", "nginx",
"-v", fmt.Sprintf("%s:%s@%s:%s", "-v", fmt.Sprintf("%s:%s@%s:%s",
testStorageAccountName, firstKey, testShareName, mountTarget), testStorageAccountName, firstKey, testShareName, mountTarget),
"-p", "80:80", "-p", "80:80",
@ -177,6 +177,52 @@ func (s *E2eACISuite) TestACIBackend() {
Expect(Lines(output)[0]).To(Equal(testContainerName)) Expect(Lines(output)[0]).To(Equal(testContainerName))
}) })
s.T().Run("re-run nginx with modified cpu/mem, and without --detach and follow logs", func(t *testing.T) {
shutdown := make(chan time.Time)
errs := make(chan error)
outChan := make(chan string)
cmd := s.NewDockerCommand("run", "nginx", "--memory", "0.1G", "--cpus", "0.1", "-p", "80:80", "--name", testContainerName).WithTimeout(shutdown)
go func() {
output, err := cmd.Exec()
outChan <- output
errs <- err
}()
var containerID string
err := WaitFor(time.Second, 100*time.Second, errs, func() bool {
output := s.NewDockerCommand("ps").ExecOrDie()
lines := Lines(output)
if len(lines) != 2 {
return false
}
containerFields := Columns(lines[1])
if containerFields[2] != "Running" {
return false
}
containerID = containerFields[0]
nginxExposedURL = strings.ReplaceAll(containerFields[3], "->80/tcp", "")
return true
})
Expect(err).NotTo(HaveOccurred())
s.NewCommand("curl", nginxExposedURL+"/test").ExecOrDie()
inspect := s.NewDockerCommand("inspect", containerID).ExecOrDie()
Expect(inspect).To(ContainSubstring("\"CPULimit\": 0.1"))
Expect(inspect).To(ContainSubstring("\"MemoryLimit\": 107374182"))
// Give a little time to get logs of the curl call
time.Sleep(5 * time.Second)
// Kill
close(shutdown)
output := <-outChan
Expect(output).To(ContainSubstring("/test"))
})
s.T().Run("removes container nginx", func(t *testing.T) {
output := s.NewDockerCommand("rm", testContainerName).ExecOrDie()
Expect(Lines(output)[0]).To(Equal(testContainerName))
})
var exposedURL string var exposedURL string
const composeFile = "../composefiles/aci-demo/aci_demo_port.yaml" const composeFile = "../composefiles/aci-demo/aci_demo_port.yaml"
const composeFileMultiplePorts = "../composefiles/aci-demo/aci_demo_multi_port.yaml" const composeFileMultiplePorts = "../composefiles/aci-demo/aci_demo_multi_port.yaml"

View File

@ -288,7 +288,7 @@ func (s *E2eSuite) TestMockBackend() {
}) })
It("can run 'run' command", func() { It("can run 'run' command", func() {
output := s.NewDockerCommand("run", "nginx", "-p", "80:80").ExecOrDie() output := s.NewDockerCommand("run", "-d", "nginx", "-p", "80:80").ExecOrDie()
Expect(output).To(ContainSubstring("Running container \"nginx\" with name")) Expect(output).To(ContainSubstring("Running container \"nginx\" with name"))
}) })
} }