mirror of https://github.com/docker/compose.git
Merge pull request #1003 from aiordache/compose_run_cmd
Add local `compose run` command
This commit is contained in:
commit
b2b9ce0a53
|
@ -201,3 +201,7 @@ func (cs *aciComposeService) Logs(ctx context.Context, projectName string, consu
|
|||
func (cs *aciComposeService) Convert(ctx context.Context, project *types.Project, options compose.ConvertOptions) ([]byte, error) {
|
||||
return nil, errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (cs *aciComposeService) RunOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
|
|
@ -71,3 +71,7 @@ func (c *composeService) List(context.Context, string) ([]compose.Stack, error)
|
|||
func (c *composeService) Convert(context.Context, *types.Project, compose.ConvertOptions) ([]byte, error) {
|
||||
return nil, errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (c *composeService) RunOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package compose
|
|||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
)
|
||||
|
@ -46,6 +47,8 @@ type Service interface {
|
|||
List(ctx context.Context, projectName string) ([]Stack, error)
|
||||
// Convert translate compose model into backend's native format
|
||||
Convert(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error)
|
||||
// RunOneOffContainer creates a service oneoff container and starts its dependencies
|
||||
RunOneOffContainer(ctx context.Context, project *types.Project, opts RunOptions) error
|
||||
}
|
||||
|
||||
// UpOptions group options of the Up API
|
||||
|
@ -66,6 +69,16 @@ type ConvertOptions struct {
|
|||
Format string
|
||||
}
|
||||
|
||||
// RunOptions options to execute compose run
|
||||
type RunOptions struct {
|
||||
Name string
|
||||
Command []string
|
||||
Detach bool
|
||||
AutoRemove bool
|
||||
Writer io.Writer
|
||||
Reader io.Reader
|
||||
}
|
||||
|
||||
// PortPublisher hold status about published port
|
||||
type PortPublisher struct {
|
||||
URL string
|
||||
|
|
|
@ -90,6 +90,7 @@ func Command(contextType string) *cobra.Command {
|
|||
listCommand(),
|
||||
logsCommand(),
|
||||
convertCommand(),
|
||||
runCommand(),
|
||||
)
|
||||
|
||||
if contextType == store.LocalContextType || contextType == store.DefaultContextType {
|
||||
|
@ -99,7 +100,7 @@ func Command(contextType string) *cobra.Command {
|
|||
pullCommand(),
|
||||
)
|
||||
}
|
||||
|
||||
command.Flags().SetInterspersed(false)
|
||||
return command
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
Copyright 2020 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/api/client"
|
||||
"github.com/docker/compose-cli/api/compose"
|
||||
"github.com/docker/compose-cli/progress"
|
||||
)
|
||||
|
||||
type runOptions struct {
|
||||
Name string
|
||||
Command []string
|
||||
WorkingDir string
|
||||
ConfigPaths []string
|
||||
Environment []string
|
||||
Detach bool
|
||||
Remove bool
|
||||
}
|
||||
|
||||
func runCommand() *cobra.Command {
|
||||
opts := runOptions{}
|
||||
runCmd := &cobra.Command{
|
||||
Use: "run [options] [-v VOLUME...] [-p PORT...] [-e KEY=VAL...] [-l KEY=VALUE...] SERVICE [COMMAND] [ARGS...]",
|
||||
Short: "Run a one-off command on a service.",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) > 1 {
|
||||
opts.Command = args[1:]
|
||||
}
|
||||
opts.Name = args[0]
|
||||
return runRun(cmd.Context(), opts)
|
||||
},
|
||||
}
|
||||
runCmd.Flags().StringVar(&opts.WorkingDir, "workdir", "", "Work dir")
|
||||
runCmd.Flags().StringArrayVarP(&opts.ConfigPaths, "file", "f", []string{}, "Compose configuration files")
|
||||
runCmd.Flags().BoolVarP(&opts.Detach, "detach", "d", false, "Run container in background and print container ID")
|
||||
runCmd.Flags().StringArrayVarP(&opts.Environment, "env", "e", []string{}, "Set environment variables")
|
||||
runCmd.Flags().BoolVar(&opts.Remove, "rm", false, "Automatically remove the container when it exits")
|
||||
|
||||
runCmd.Flags().SetInterspersed(false)
|
||||
return runCmd
|
||||
}
|
||||
|
||||
func runRun(ctx context.Context, opts runOptions) error {
|
||||
projectOpts := composeOptions{
|
||||
ConfigPaths: opts.ConfigPaths,
|
||||
WorkingDir: opts.WorkingDir,
|
||||
Environment: opts.Environment,
|
||||
}
|
||||
c, project, err := setup(ctx, projectOpts, []string{opts.Name})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
originalServices := project.Services
|
||||
_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
|
||||
return "", startDependencies(ctx, c, project, opts.Name)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
project.Services = originalServices
|
||||
// start container and attach to container streams
|
||||
runOpts := compose.RunOptions{
|
||||
Name: opts.Name,
|
||||
Command: opts.Command,
|
||||
Detach: opts.Detach,
|
||||
AutoRemove: opts.Remove,
|
||||
Writer: os.Stdout,
|
||||
Reader: os.Stdin,
|
||||
}
|
||||
return c.ComposeService().RunOneOffContainer(ctx, project, runOpts)
|
||||
}
|
||||
|
||||
func startDependencies(ctx context.Context, c *client.Client, project *types.Project, requestedService string) error {
|
||||
originalServices := project.Services
|
||||
dependencies := types.Services{}
|
||||
for _, service := range originalServices {
|
||||
if service.Name != requestedService {
|
||||
dependencies = append(dependencies, service)
|
||||
}
|
||||
}
|
||||
project.Services = dependencies
|
||||
if err := c.ComposeService().Create(ctx, project); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.ComposeService().Start(ctx, project, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
|
@ -27,6 +27,7 @@ import (
|
|||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/compose-cli/api/compose"
|
||||
"github.com/docker/compose-cli/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sanathkr/go-yaml"
|
||||
)
|
||||
|
||||
|
@ -162,3 +163,6 @@ func (e ecsLocalSimulation) Ps(ctx context.Context, projectName string) ([]compo
|
|||
func (e ecsLocalSimulation) List(ctx context.Context, projectName string) ([]compose.Stack, error) {
|
||||
return e.compose.List(ctx, projectName)
|
||||
}
|
||||
func (e ecsLocalSimulation) RunOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) error {
|
||||
return errors.Wrap(errdefs.ErrNotImplemented, "use docker-compose run")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
Copyright 2020 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ecs
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/compose-cli/api/compose"
|
||||
"github.com/docker/compose-cli/errdefs"
|
||||
)
|
||||
|
||||
func (b *ecsAPIService) RunOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
|
@ -182,3 +182,6 @@ func (cs *composeService) Logs(ctx context.Context, projectName string, consumer
|
|||
func (cs *composeService) Convert(ctx context.Context, project *types.Project, options compose.ConvertOptions) ([]byte, error) {
|
||||
return nil, errdefs.ErrNotImplemented
|
||||
}
|
||||
func (cs *composeService) RunOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
|
|
@ -120,6 +120,7 @@ func (s *composeService) getContainerStreams(ctx context.Context, container moby
|
|||
Stdin: true,
|
||||
Stdout: true,
|
||||
Stderr: true,
|
||||
Logs: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
|
|
@ -62,7 +62,7 @@ func (s *composeService) ensureService(ctx context.Context, project *types.Proje
|
|||
number := next + i
|
||||
name := fmt.Sprintf("%s_%s_%d", project.Name, service.Name, number)
|
||||
eg.Go(func() error {
|
||||
return s.createContainer(ctx, project, service, name, number)
|
||||
return s.createContainer(ctx, project, service, name, number, false)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -163,10 +163,10 @@ func getScale(config types.ServiceConfig) int {
|
|||
return 1
|
||||
}
|
||||
|
||||
func (s *composeService) createContainer(ctx context.Context, project *types.Project, service types.ServiceConfig, name string, number int) error {
|
||||
func (s *composeService) createContainer(ctx context.Context, project *types.Project, service types.ServiceConfig, name string, number int, autoRemove bool) error {
|
||||
w := progress.ContextWriter(ctx)
|
||||
w.Event(progress.CreatingEvent(name))
|
||||
err := s.runContainer(ctx, project, service, name, number, nil)
|
||||
err := s.createMobyContainer(ctx, project, service, name, number, nil, autoRemove)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ func (s *composeService) recreateContainer(ctx context.Context, project *types.P
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = s.runContainer(ctx, project, service, name, number, &container)
|
||||
err = s.createMobyContainer(ctx, project, service, name, number, &container, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -228,8 +228,8 @@ func (s *composeService) restartContainer(ctx context.Context, container moby.Co
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *composeService) runContainer(ctx context.Context, project *types.Project, service types.ServiceConfig, name string, number int, container *moby.Container) error {
|
||||
containerConfig, hostConfig, networkingConfig, err := getContainerCreateOptions(project, service, number, container)
|
||||
func (s *composeService) createMobyContainer(ctx context.Context, project *types.Project, service types.ServiceConfig, name string, number int, container *moby.Container, autoRemove bool) error {
|
||||
containerConfig, hostConfig, networkingConfig, err := getCreateOptions(project, service, number, container, autoRemove)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -44,6 +44,20 @@ func (s *composeService) Create(ctx context.Context, project *types.Project) err
|
|||
return err
|
||||
}
|
||||
|
||||
if err := s.ensureProjectNetworks(ctx, project); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.ensureProjectVolumes(ctx, project); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return InDependencyOrder(ctx, project, func(c context.Context, service types.ServiceConfig) error {
|
||||
return s.ensureService(c, project, service)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *composeService) ensureProjectNetworks(ctx context.Context, project *types.Project) error {
|
||||
for k, network := range project.Networks {
|
||||
if !network.External.External && network.Name != "" {
|
||||
network.Name = fmt.Sprintf("%s_%s", project.Name, k)
|
||||
|
@ -57,7 +71,10 @@ func (s *composeService) Create(ctx context.Context, project *types.Project) err
|
|||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *composeService) ensureProjectVolumes(ctx context.Context, project *types.Project) error {
|
||||
for k, volume := range project.Volumes {
|
||||
if !volume.External.External && volume.Name != "" {
|
||||
volume.Name = fmt.Sprintf("%s_%s", project.Name, k)
|
||||
|
@ -71,13 +88,10 @@ func (s *composeService) Create(ctx context.Context, project *types.Project) err
|
|||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return InDependencyOrder(ctx, project, func(c context.Context, service types.ServiceConfig) error {
|
||||
return s.ensureService(c, project, service)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func getContainerCreateOptions(p *types.Project, s types.ServiceConfig, number int, inherit *moby.Container) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error) {
|
||||
func getCreateOptions(p *types.Project, s types.ServiceConfig, number int, inherit *moby.Container, autoRemove bool) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error) {
|
||||
hash, err := jsonHash(s)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
|
@ -88,11 +102,12 @@ func getContainerCreateOptions(p *types.Project, s types.ServiceConfig, number i
|
|||
labels[k] = v
|
||||
}
|
||||
|
||||
// TODO: change oneoffLabel value for containers started with `docker compose run`
|
||||
labels[projectLabel] = p.Name
|
||||
labels[serviceLabel] = s.Name
|
||||
labels[versionLabel] = ComposeVersion
|
||||
labels[oneoffLabel] = "False"
|
||||
if _, ok := s.Labels[oneoffLabel]; !ok {
|
||||
labels[oneoffLabel] = "False"
|
||||
}
|
||||
labels[configHashLabel] = hash
|
||||
labels[workingDirLabel] = p.WorkingDir
|
||||
labels[configFilesLabel] = strings.Join(p.ComposeFiles, ",")
|
||||
|
@ -152,6 +167,7 @@ func getContainerCreateOptions(p *types.Project, s types.ServiceConfig, number i
|
|||
|
||||
networkMode := getNetworkMode(p, s)
|
||||
hostConfig := container.HostConfig{
|
||||
AutoRemove: autoRemove,
|
||||
Mounts: mountOptions,
|
||||
CapAdd: strslice.StrSlice(s.CapAdd),
|
||||
CapDrop: strslice.StrSlice(s.CapDrop),
|
||||
|
|
|
@ -91,16 +91,17 @@ func (s *composeService) Down(ctx context.Context, projectName string, options c
|
|||
|
||||
func (s *composeService) removeContainers(ctx context.Context, w progress.Writer, eg *errgroup.Group, containers []moby.Container) error {
|
||||
for _, container := range containers {
|
||||
toDelete := container
|
||||
eg.Go(func() error {
|
||||
eventName := "Container " + getContainerName(container)
|
||||
eventName := "Container " + getContainerName(toDelete)
|
||||
w.Event(progress.StoppingEvent(eventName))
|
||||
err := s.apiClient.ContainerStop(ctx, container.ID, nil)
|
||||
err := s.apiClient.ContainerStop(ctx, toDelete.ID, nil)
|
||||
if err != nil {
|
||||
w.Event(progress.ErrorMessageEvent(eventName, "Error while Stopping"))
|
||||
return err
|
||||
}
|
||||
w.Event(progress.RemovingEvent(eventName))
|
||||
err = s.apiClient.ContainerRemove(ctx, container.ID, moby.ContainerRemoveOptions{})
|
||||
err = s.apiClient.ContainerRemove(ctx, toDelete.ID, moby.ContainerRemoveOptions{})
|
||||
if err != nil {
|
||||
w.Event(progress.ErrorMessageEvent(eventName, "Error while Removing"))
|
||||
return err
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
const (
|
||||
containerNumberLabel = "com.docker.compose.container-number"
|
||||
oneoffLabel = "com.docker.compose.oneoff"
|
||||
slugLabel = "com.docker.compose.slug"
|
||||
projectLabel = "com.docker.compose.project"
|
||||
volumeLabel = "com.docker.compose.volume"
|
||||
workingDirLabel = "com.docker.compose.project.working_dir"
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
Copyright 2020 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/compose-cli/api/compose"
|
||||
apitypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
moby "github.com/docker/docker/pkg/stringid"
|
||||
)
|
||||
|
||||
func (s *composeService) RunOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) error {
|
||||
originalServices := project.Services
|
||||
var requestedService types.ServiceConfig
|
||||
for _, service := range originalServices {
|
||||
if service.Name == opts.Name {
|
||||
requestedService = service
|
||||
}
|
||||
}
|
||||
|
||||
project.Services = originalServices
|
||||
if len(opts.Command) > 0 {
|
||||
requestedService.Command = opts.Command
|
||||
}
|
||||
requestedService.Scale = 1
|
||||
requestedService.Tty = true
|
||||
requestedService.StdinOpen = true
|
||||
|
||||
slug := moby.GenerateRandomID()
|
||||
requestedService.ContainerName = fmt.Sprintf("%s_%s_run_%s", project.Name, requestedService.Name, moby.TruncateID(slug))
|
||||
requestedService.Labels = requestedService.Labels.Add(slugLabel, slug)
|
||||
requestedService.Labels = requestedService.Labels.Add(oneoffLabel, "True")
|
||||
|
||||
if err := s.ensureImagesExists(ctx, project); err != nil { // all dependencies already checked, but might miss requestedService img
|
||||
return err
|
||||
}
|
||||
if err := s.waitDependencies(ctx, project, requestedService); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.createContainer(ctx, project, requestedService, requestedService.ContainerName, 1, opts.AutoRemove); err != nil {
|
||||
return err
|
||||
}
|
||||
containerID := requestedService.ContainerName
|
||||
|
||||
if opts.Detach {
|
||||
err := s.apiClient.ContainerStart(ctx, containerID, apitypes.ContainerStartOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(opts.Writer, containerID)
|
||||
return nil
|
||||
}
|
||||
|
||||
containers, err := s.apiClient.ContainerList(ctx, apitypes.ContainerListOptions{
|
||||
Filters: filters.NewArgs(
|
||||
filters.Arg("label", fmt.Sprintf("%s=%s", slugLabel, slug)),
|
||||
),
|
||||
All: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oneoffContainer := containers[0]
|
||||
eg := errgroup.Group{}
|
||||
eg.Go(func() error {
|
||||
return s.attachContainerStreams(ctx, oneoffContainer, true, opts.Reader, opts.Writer)
|
||||
})
|
||||
|
||||
if err = s.apiClient.ContainerStart(ctx, containerID, apitypes.ContainerStartOptions{}); err != nil {
|
||||
return err
|
||||
}
|
||||
return eg.Wait()
|
||||
}
|
|
@ -103,6 +103,61 @@ func TestLocalComposeUp(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestLocalComposeRun(t *testing.T) {
|
||||
c := NewParallelE2eCLI(t, binDir)
|
||||
|
||||
t.Run("compose run", func(t *testing.T) {
|
||||
res := c.RunDockerCmd("compose", "run", "-f", "./fixtures/run-test/docker-compose.yml", "back")
|
||||
lines := Lines(res.Stdout())
|
||||
assert.Equal(t, lines[len(lines)-1], "Hello there!!", res.Stdout())
|
||||
})
|
||||
|
||||
t.Run("check run container exited", func(t *testing.T) {
|
||||
res := c.RunDockerCmd("ps", "--all")
|
||||
lines := Lines(res.Stdout())
|
||||
var runContainerID string
|
||||
var truncatedSlug string
|
||||
for _, line := range lines {
|
||||
fields := strings.Fields(line)
|
||||
containerID := fields[len(fields)-1]
|
||||
assert.Assert(t, !strings.HasPrefix(containerID, "run-test_front"))
|
||||
if strings.HasPrefix(containerID, "run-test_back") {
|
||||
//only the one-off container for back service
|
||||
assert.Assert(t, strings.HasPrefix(containerID, "run-test_back_run_"), containerID)
|
||||
truncatedSlug = strings.Replace(containerID, "run-test_back_run_", "", 1)
|
||||
runContainerID = containerID
|
||||
assert.Assert(t, strings.Contains(line, "Exited"), line)
|
||||
}
|
||||
if strings.HasPrefix(containerID, "run-test_db_1") {
|
||||
assert.Assert(t, strings.Contains(line, "Up"), line)
|
||||
}
|
||||
}
|
||||
assert.Assert(t, runContainerID != "")
|
||||
res = c.RunDockerCmd("inspect", runContainerID)
|
||||
res.Assert(t, icmd.Expected{Out: `"com.docker.compose.container-number": "1"`})
|
||||
res.Assert(t, icmd.Expected{Out: `"com.docker.compose.project": "run-test"`})
|
||||
res.Assert(t, icmd.Expected{Out: `"com.docker.compose.oneoff": "True",`})
|
||||
res.Assert(t, icmd.Expected{Out: `"com.docker.compose.slug": "` + truncatedSlug})
|
||||
})
|
||||
|
||||
t.Run("compose run --rm", func(t *testing.T) {
|
||||
res := c.RunDockerCmd("compose", "run", "-f", "./fixtures/run-test/docker-compose.yml", "--rm", "back", "/bin/sh", "-c", "echo Hello again")
|
||||
lines := Lines(res.Stdout())
|
||||
assert.Equal(t, lines[len(lines)-1], "Hello again", res.Stdout())
|
||||
})
|
||||
|
||||
t.Run("check run container removed", func(t *testing.T) {
|
||||
res := c.RunDockerCmd("ps", "--all")
|
||||
assert.Assert(t, strings.Contains(res.Stdout(), "run-test_back"), res.Stdout())
|
||||
})
|
||||
|
||||
t.Run("down", func(t *testing.T) {
|
||||
c.RunDockerCmd("compose", "down", "-f", "./fixtures/run-test/docker-compose.yml")
|
||||
res := c.RunDockerCmd("ps", "--all")
|
||||
assert.Assert(t, !strings.Contains(res.Stdout(), "run-test"), res.Stdout())
|
||||
})
|
||||
}
|
||||
|
||||
func TestLocalComposeBuild(t *testing.T) {
|
||||
c := NewParallelE2eCLI(t, binDir)
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
version: '3.8'
|
||||
services:
|
||||
back:
|
||||
image: alpine
|
||||
command: echo "Hello there!!"
|
||||
depends_on:
|
||||
- db
|
||||
networks:
|
||||
- backnet
|
||||
db:
|
||||
image: nginx
|
||||
networks:
|
||||
- backnet
|
||||
volumes:
|
||||
- data:/test
|
||||
front:
|
||||
image: nginx
|
||||
networks:
|
||||
- frontnet
|
||||
networks:
|
||||
frontnet:
|
||||
backnet:
|
||||
volumes:
|
||||
data:
|
Loading…
Reference in New Issue