Compare commits

...

35 Commits

Author SHA1 Message Date
Eric Fan
41b3967cb5 Fix cannot setup IPAM gateway
Signed-off-by: Eric Fan <ericfan@qnap.com>
2022-04-24 17:30:27 +02:00
Nicolas De Loof
00fd1c1530 inspect image ID after pull to se com.docker.compose.image
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2022-04-21 22:42:29 +02:00
Guillaume Lours
14ca112862 Merge pull request #9392 from snehakpersistent/ppc-support
add support for ppc64le for docker compose
2022-04-14 17:43:44 +02:00
Sneha Kanekar1
e0286360a8 add support for ppc64le
Signed-off-by: Sneha Kanekar1 <sneha.kanekar1@ibm.com>
2022-04-14 17:25:01 +05:30
MaxPeal
5d809a2e89 create also a checksums.txt file, add --binary
create also a checksums.txt file
and switch shasum to --binary,
to Fix problems with the verification on different OS systems
fixes https://github.com/docker/compose/issues/9388

Signed-off-by: MaxPeal <30347730+MaxPeal@users.noreply.github.com>
2022-04-14 09:06:35 +02:00
Nicolas De Loof
0dffd5ba9f add support for build.secrets
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2022-04-13 22:45:53 +02:00
Nicolas De Loof
e01687430e when using bind API, use compose-go to (re)build volume string
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2022-04-13 22:45:53 +02:00
Guillaume Lours
a32fdff979 Merge pull request #9385 from ndeloof/lowercase_project_name
project name MUST be lowercase
2022-04-13 10:08:53 +02:00
Nicolas De Loof
9668f600d1 project name MUST be lowercase
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2022-04-13 09:49:01 +02:00
Nicolas De Loof
672e2367fb don't ignore error
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2022-04-12 16:00:36 +02:00
Nicolas De Loof
625a48dcf7 pull to respect pull_policy
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2022-04-12 07:59:58 +02:00
Guillaume Lours
03aadcc85a Merge pull request #9368 from ndeloof/links_dependencies
include services declared by `links` as implicit dependencies
2022-04-11 11:59:25 +02:00
Nicolas De Loof
500555b834 linter
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2022-04-08 11:41:46 +02:00
Nicolas De Loof
e766352d81 include services declared by links as implicit dependencies
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2022-04-08 10:32:36 +02:00
Nicolas De Loof
db698562a9 use project we just created to start services
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2022-04-07 13:38:30 +02:00
Guillaume Lours
7fea9f7e8b use project instead of DownOptions.project to list service images in pkg.compose.down
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2022-04-05 08:24:25 +02:00
Eric Freese
d871cb98e5 Fix search/replace typo in --no-TTY documentation
Commit abbba74b27 looks to have
accidentally replaced `pseudo-tty` with `pseudo-noTty` in several
places. In other places, it looks like it replaced `pseudo-tty` with
`pseudo-TTY`, so I used the uppercased version in these places as well.

For example, running version 2.3.3, I get this output:

```
% docker-compose run --help

...

Options:
  ...
  -T, --no-TTY                Disable pseudo-noTty allocation. By default docker compose run allocates a TTY
  ...
```

Signed-off-by: Eric Freese <ericdfreese@gmail.com>
2022-04-04 19:06:03 +02:00
Guillaume Lours
8d815ff587 Merge pull request #9348 from ndeloof/attach_tty
get Tty from container to know adequate way to attach to
2022-04-04 14:44:07 +02:00
Nicolas De Loof
c9fbb9ba9c inspect container before attachment to use the adequate logic regarding TTY
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2022-04-04 14:39:38 +02:00
Guillaume Lours
f2d9acd3d4 use ssh config when building from compose up
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2022-04-04 10:16:28 +02:00
Guillaume Lours
fcff36fc8a now we use directly the Docker CLI to run autoremove flag should be pass as is
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2022-04-02 08:45:51 +02:00
Guillaume Lours
804ef4af5b Merge pull request #9309 from thaJeztah/vendor_containerd_1.6.2
vendor: github.com/containerd/containerd v1.6.2
2022-03-31 19:02:47 +02:00
Guillaume Lours
0309a735a9 Merge pull request #9336 from ulyssessouza/fix-empty-down
Fix down command without any resource to delete
2022-03-31 18:34:56 +02:00
Ulysses Souza
56e48f8360 Fix down command without any resource to delete
A command down without any resource to delete was
trying to remove a default network that doesn't exist

Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2022-03-31 18:30:29 +02:00
Ulysses Souza
c7473c68ae Merge pull request #9335 from ulyssessouza/remove-deadcode
Remove dead warning code
2022-03-31 17:04:29 +02:00
Ulysses Souza
5e63f12ae8 Merge pull request #9332 from ulyssessouza/fix-project-name
Takes COMPOSE_PROJECT_NAME into consideration on commands
2022-03-31 17:04:12 +02:00
Ulysses Souza
60363c36df Remove dead warning code
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2022-03-31 16:42:04 +02:00
Guillaume Lours
e700f0a5d7 Merge pull request #9334 from mschoettle/ssh-option-fix-typo
fix typo in ssh option description
2022-03-31 16:35:47 +02:00
Matthias Schoettle
6dbd6ffe11 fix typo in ssh option description
Signed-off-by: Matthias Schoettle <git@mattsch.com>
2022-03-31 10:14:13 -04:00
Ulysses Souza
eee0e8bed9 Takes COMPOSE_PROJECT_NAME into consideration on commands
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2022-03-31 14:28:38 +02:00
Guillaume Lours
934b596e00 add e2e tests to check usage of ssh build property
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2022-03-31 12:47:15 +02:00
Guillaume Lours
ff73827a6f Add support of ssh authentications defined in compose file or via cli flags
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2022-03-31 12:47:15 +02:00
Guillaume Lours
3c12b94519 Merge pull request #9331 from glours/e2e-start-stop-race
fix race condition on start-stop e2e tests running in parrallel
2022-03-31 11:47:10 +02:00
Guillaume Lours
9b02add4df fix race condition on start-stop e2e tests running in parrallel
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2022-03-31 11:16:18 +02:00
Sebastiaan van Stijn
5ace5bdeda vendor: github.com/containerd/containerd v1.6.2
includes a fix for CVE-2022-24769 (but doesn't affect the code we use)

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-03-24 04:13:02 +01:00
50 changed files with 510 additions and 188 deletions

View File

@@ -42,6 +42,12 @@ jobs:
name: docker-compose-linux-amd64
path: ${{ github.workspace }}/bin/docker-compose-linux-amd64
- name: Upload linux-ppc64le binary
uses: actions/upload-artifact@v2
with:
name: docker-compose-linux-ppc64le
path: ${{ github.workspace }}/bin/docker-compose-linux-ppc64le
- name: Upload windows-amd64 binary
uses: actions/upload-artifact@v2
with:

View File

@@ -36,7 +36,7 @@ jobs:
run: make GIT_TAG=${{ github.event.inputs.tag }} -f builder.Makefile cross
- name: Compute checksums
run: cd bin; for f in *; do shasum --algorithm 256 $f > $f.sha256; done
run: cd bin; for f in *; do shasum --binary --algorithm 256 $f | tee -a checksums.txt > $f.sha256; done
- name: License
run: cp packaging/* bin/

View File

@@ -47,6 +47,7 @@ compose-plugin:
.PHONY: cross
cross:
GOOS=linux GOARCH=amd64 $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-x86_64 ./cmd
GOOS=linux GOARCH=ppc64le $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-ppc64le ./cmd
GOOS=linux GOARCH=arm64 $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-aarch64 ./cmd
GOOS=linux GOARM=6 GOARCH=arm $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-armv6 ./cmd
GOOS=linux GOARM=7 GOARCH=arm $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-armv7 ./cmd

View File

@@ -23,6 +23,7 @@ import (
"strings"
"github.com/compose-spec/compose-go/cli"
"github.com/compose-spec/compose-go/loader"
"github.com/compose-spec/compose-go/types"
buildx "github.com/docker/buildx/util/progress"
"github.com/docker/compose/v2/pkg/utils"
@@ -40,6 +41,28 @@ type buildOptions struct {
args []string
noCache bool
memory string
ssh string
}
func (opts buildOptions) toAPIBuildOptions(services []string) (api.BuildOptions, error) {
var SSHKeys []types.SSHKey
var err error
if opts.ssh != "" {
SSHKeys, err = loader.ParseShortSSHSyntax(opts.ssh)
if err != nil {
return api.BuildOptions{}, err
}
}
return api.BuildOptions{
Pull: opts.pull,
Progress: opts.progress,
Args: types.NewMappingWithEquals(opts.args),
NoCache: opts.noCache,
Quiet: opts.quiet,
Services: services,
SSHs: SSHKeys,
}, nil
}
var printerModes = []string{
@@ -73,7 +96,10 @@ func buildCommand(p *projectOptions, backend api.Service) *cobra.Command {
}
return nil
}),
RunE: Adapt(func(ctx context.Context, args []string) error {
RunE: AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error {
if cmd.Flags().Changed("ssh") && opts.ssh == "" {
opts.ssh = "default"
}
return runBuild(ctx, backend, opts, args)
}),
ValidArgsFunction: serviceCompletion(p),
@@ -82,6 +108,7 @@ func buildCommand(p *projectOptions, backend api.Service) *cobra.Command {
cmd.Flags().BoolVar(&opts.pull, "pull", false, "Always attempt to pull a newer version of the image.")
cmd.Flags().StringVar(&opts.progress, "progress", buildx.PrinterModeAuto, fmt.Sprintf(`Set type of progress output (%s)`, strings.Join(printerModes, ", ")))
cmd.Flags().StringArrayVar(&opts.args, "build-arg", []string{}, "Set build-time variables for services.")
cmd.Flags().StringVar(&opts.ssh, "ssh", "", "Set SSH authentications used when building service images. (use 'default' for using your default SSH Agent)")
cmd.Flags().Bool("parallel", true, "Build images in parallel. DEPRECATED")
cmd.Flags().MarkHidden("parallel") //nolint:errcheck
cmd.Flags().Bool("compress", true, "Compress the build context using gzip. DEPRECATED")
@@ -103,12 +130,9 @@ func runBuild(ctx context.Context, backend api.Service, opts buildOptions, servi
return err
}
return backend.Build(ctx, project, api.BuildOptions{
Pull: opts.pull,
Progress: opts.progress,
Args: types.NewMappingWithEquals(opts.args),
NoCache: opts.noCache,
Quiet: opts.quiet,
Services: services,
})
apiBuildOptions, err := opts.toAPIBuildOptions(services)
if err != nil {
return err
}
return backend.Build(ctx, project, apiBuildOptions)
}

View File

@@ -89,9 +89,6 @@ func Adapt(fn Command) func(cmd *cobra.Command, args []string) error {
})
}
// Warning is a global warning to be displayed to user on command failure
var Warning string
type projectOptions struct {
ProjectName string
Profiles []string
@@ -143,6 +140,11 @@ func (o *projectOptions) toProjectName() (string, error) {
return o.ProjectName, nil
}
envProjectName := os.Getenv("COMPOSE_PROJECT_NAME")
if envProjectName != "" {
return envProjectName, nil
}
project, err := o.toProject(nil)
if err != nil {
return "", err

View File

@@ -150,7 +150,7 @@ func runCommand(p *projectOptions, dockerCli command.Cli, backend api.Service) *
flags.StringArrayVarP(&opts.environment, "env", "e", []string{}, "Set environment variables")
flags.StringArrayVarP(&opts.labels, "label", "l", []string{}, "Add or override a label")
flags.BoolVar(&opts.Remove, "rm", false, "Automatically remove the container when it exits")
flags.BoolVarP(&opts.noTty, "no-TTY", "T", !dockerCli.Out().IsTerminal(), "Disable pseudo-noTty allocation (default: auto-detected).")
flags.BoolVarP(&opts.noTty, "no-TTY", "T", !dockerCli.Out().IsTerminal(), "Disable pseudo-TTY allocation (default: auto-detected).")
flags.StringVar(&opts.name, "name", "", " Assign a name to the container")
flags.StringVarP(&opts.user, "user", "u", "", "Run as specified username or uid")
flags.StringVarP(&opts.workdir, "workdir", "w", "", "Working directory inside the container")

View File

@@ -204,6 +204,7 @@ func runUp(ctx context.Context, backend api.Service, createOptions createOptions
return backend.Up(ctx, project, api.UpOptions{
Create: create,
Start: api.StartOptions{
Project: project,
Attach: consumer,
AttachTo: attachTo,
ExitCodeFrom: upOptions.exitCodeFrom,

View File

@@ -32,11 +32,6 @@ import (
"github.com/docker/compose/v2/pkg/compose"
)
func init() {
commands.Warning = "The new 'docker compose' command is currently experimental. " +
"To provide feedback or request new features please open issues at https://github.com/docker/compose"
}
func pluginMain() {
plugin.Run(func(dockerCli command.Cli) *cobra.Command {
lazyInit := api.NewServiceProxy()

View File

@@ -12,6 +12,7 @@ Build or rebuild services
| `--progress` | `string` | `auto` | Set type of progress output (auto, tty, plain, quiet) |
| `--pull` | | | Always attempt to pull a newer version of the image. |
| `-q`, `--quiet` | | | Don't print anything to STDOUT |
| `--ssh` | `string` | | Set SSH authentications used when building service images. (use 'default' for using your default SSH Agent) |
<!---MARKER_GEN_END-->

View File

@@ -13,7 +13,7 @@ Run a one-off command on a service.
| `-i`, `--interactive` | | | Keep STDIN open even if not attached. |
| `-l`, `--label` | `stringArray` | | Add or override a label |
| `--name` | `string` | | Assign a name to the container |
| `-T`, `--no-TTY` | | | Disable pseudo-noTty allocation (default: auto-detected). |
| `-T`, `--no-TTY` | | | Disable pseudo-TTY allocation (default: auto-detected). |
| `--no-deps` | | | Don't start linked services. |
| `-p`, `--publish` | `stringArray` | | Publish a container's port(s) to the host. |
| `--quiet-pull` | | | Pull without printing progress information. |

View File

@@ -117,6 +117,16 @@ options:
experimentalcli: false
kubernetes: false
swarm: false
- option: ssh
value_type: string
description: |
Set SSH authentications used when building service images. (use 'default' for using your default SSH Agent)
deprecated: false
hidden: false
experimental: false
experimentalcli: false
kubernetes: false
swarm: false
deprecated: false
experimental: false
experimentalcli: false

View File

@@ -125,7 +125,7 @@ options:
shorthand: T
value_type: bool
default_value: "true"
description: 'Disable pseudo-noTty allocation (default: auto-detected).'
description: 'Disable pseudo-TTY allocation (default: auto-detected).'
deprecated: false
hidden: false
experimental: false

4
go.mod
View File

@@ -6,9 +6,9 @@ require (
github.com/AlecAivazis/survey/v2 v2.3.2
github.com/buger/goterm v1.0.4
github.com/cnabio/cnab-to-oci v0.3.1-beta1
github.com/compose-spec/compose-go v1.2.1
github.com/compose-spec/compose-go v1.2.4
github.com/containerd/console v1.0.3
github.com/containerd/containerd v1.6.1
github.com/containerd/containerd v1.6.2
github.com/distribution/distribution/v3 v3.0.0-20210316161203-a01c71e2477e
github.com/docker/buildx v0.8.1 // when updating, also update the replace rules accordingly
github.com/docker/cli v20.10.12+incompatible

7
go.sum
View File

@@ -302,8 +302,8 @@ github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoC
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/compose-spec/compose-go v1.0.8/go.mod h1:REnCbBugoIdHB7S1sfkN/aJ7AJpNApGNjNiVjA9L8x4=
github.com/compose-spec/compose-go v1.2.1 h1:8+DAP7Mt/Ohl5y6YbZdilLMvIhMxvuSZcNZyywjQmJE=
github.com/compose-spec/compose-go v1.2.1/go.mod h1:pAy7Mikpeft4pxkFU565/DRHEbDfR84G6AQuiL+Hdg8=
github.com/compose-spec/compose-go v1.2.4 h1:nzTFqM8+2J7Veao5Pq5U451thinv3U1wChIvcjX59/A=
github.com/compose-spec/compose-go v1.2.4/go.mod h1:pAy7Mikpeft4pxkFU565/DRHEbDfR84G6AQuiL+Hdg8=
github.com/compose-spec/godotenv v1.1.1/go.mod h1:zF/3BOa18Z24tts5qnO/E9YURQanJTBUf7nlcCTNsyc=
github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
@@ -348,8 +348,9 @@ github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoT
github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s=
github.com/containerd/containerd v1.6.1 h1:oa2uY0/0G+JX4X7hpGCYvkp9FjUancz56kSNnb1sG3o=
github.com/containerd/containerd v1.6.1/go.mod h1:1nJz5xCZPusx6jJU8Frfct988y0NpumIq9ODB0kLtoE=
github.com/containerd/containerd v1.6.2 h1:pcaPUGbYW8kBw6OgIZwIVIeEhdWVrBzsoCfVJ5BjrLU=
github.com/containerd/containerd v1.6.2/go.mod h1:sidY30/InSE1j2vdD1ihtKoJz+lWdaXMdiAeIupaf+s=
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=

View File

@@ -32,9 +32,9 @@ type Service interface {
// Push executes the equivalent ot a `compose push`
Push(ctx context.Context, project *types.Project, options PushOptions) error
// Pull executes the equivalent of a `compose pull`
Pull(ctx context.Context, project *types.Project, opts PullOptions) error
Pull(ctx context.Context, project *types.Project, options PullOptions) error
// Create executes the equivalent to a `compose create`
Create(ctx context.Context, project *types.Project, opts CreateOptions) error
Create(ctx context.Context, project *types.Project, options CreateOptions) error
// Start executes the equivalent to a `compose start`
Start(ctx context.Context, projectName string, options StartOptions) error
// Restart restarts containers
@@ -54,25 +54,25 @@ type Service interface {
// Convert translate compose model into backend's native format
Convert(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error)
// Kill executes the equivalent to a `compose kill`
Kill(ctx context.Context, project string, options KillOptions) error
Kill(ctx context.Context, projectName string, options KillOptions) error
// RunOneOffContainer creates a service oneoff container and starts its dependencies
RunOneOffContainer(ctx context.Context, project *types.Project, opts RunOptions) (int, error)
// Remove executes the equivalent to a `compose rm`
Remove(ctx context.Context, project string, options RemoveOptions) error
Remove(ctx context.Context, projectName string, options RemoveOptions) error
// Exec executes a command in a running service container
Exec(ctx context.Context, project string, opts RunOptions) (int, error)
Exec(ctx context.Context, projectName string, options RunOptions) (int, error)
// Copy copies a file/folder between a service container and the local filesystem
Copy(ctx context.Context, project string, options CopyOptions) error
Copy(ctx context.Context, projectName string, options CopyOptions) error
// Pause executes the equivalent to a `compose pause`
Pause(ctx context.Context, project string, options PauseOptions) error
Pause(ctx context.Context, projectName string, options PauseOptions) error
// UnPause executes the equivalent to a `compose unpause`
UnPause(ctx context.Context, project string, options PauseOptions) error
UnPause(ctx context.Context, projectName string, options PauseOptions) error
// Top executes the equivalent to a `compose top`
Top(ctx context.Context, projectName string, services []string) ([]ContainerProcSummary, error)
// Events executes the equivalent to a `compose events`
Events(ctx context.Context, project string, options EventsOptions) error
Events(ctx context.Context, projectName string, options EventsOptions) error
// Port executes the equivalent to a `compose port`
Port(ctx context.Context, project string, service string, port int, options PortOptions) (string, int, error)
Port(ctx context.Context, projectName string, service string, port int, options PortOptions) (string, int, error)
// Images executes the equivalent of a `compose images`
Images(ctx context.Context, projectName string, options ImagesOptions) ([]ImageSummary, error)
}
@@ -91,6 +91,8 @@ type BuildOptions struct {
Quiet bool
// Services passed in the command line to be built
Services []string
// Ssh authentications passed in the command line
SSHs []types.SSHKey
}
// CreateOptions group options of the Create API
@@ -115,6 +117,8 @@ type CreateOptions struct {
// StartOptions group options of the Start API
type StartOptions struct {
// Project is the compose project used to define this app. Might be nil if user ran `start` just with project name
Project *types.Project
// Attach to container and forward logs if not nil
Attach LogConsumer
// AttachTo set the services to attach to

View File

@@ -219,11 +219,11 @@ func (s *ServiceProxy) Convert(ctx context.Context, project *types.Project, opti
}
// Kill implements Service interface
func (s *ServiceProxy) Kill(ctx context.Context, project string, options KillOptions) error {
func (s *ServiceProxy) Kill(ctx context.Context, projectName string, options KillOptions) error {
if s.KillFn == nil {
return ErrNotImplemented
}
return s.KillFn(ctx, project, options)
return s.KillFn(ctx, projectName, options)
}
// RunOneOffContainer implements Service interface
@@ -238,43 +238,43 @@ func (s *ServiceProxy) RunOneOffContainer(ctx context.Context, project *types.Pr
}
// Remove implements Service interface
func (s *ServiceProxy) Remove(ctx context.Context, project string, options RemoveOptions) error {
func (s *ServiceProxy) Remove(ctx context.Context, projectName string, options RemoveOptions) error {
if s.RemoveFn == nil {
return ErrNotImplemented
}
return s.RemoveFn(ctx, project, options)
return s.RemoveFn(ctx, projectName, options)
}
// Exec implements Service interface
func (s *ServiceProxy) Exec(ctx context.Context, project string, options RunOptions) (int, error) {
func (s *ServiceProxy) Exec(ctx context.Context, projectName string, options RunOptions) (int, error) {
if s.ExecFn == nil {
return 0, ErrNotImplemented
}
return s.ExecFn(ctx, project, options)
return s.ExecFn(ctx, projectName, options)
}
// Copy implements Service interface
func (s *ServiceProxy) Copy(ctx context.Context, project string, options CopyOptions) error {
func (s *ServiceProxy) Copy(ctx context.Context, projectName string, options CopyOptions) error {
if s.CopyFn == nil {
return ErrNotImplemented
}
return s.CopyFn(ctx, project, options)
return s.CopyFn(ctx, projectName, options)
}
// Pause implements Service interface
func (s *ServiceProxy) Pause(ctx context.Context, project string, options PauseOptions) error {
func (s *ServiceProxy) Pause(ctx context.Context, projectName string, options PauseOptions) error {
if s.PauseFn == nil {
return ErrNotImplemented
}
return s.PauseFn(ctx, project, options)
return s.PauseFn(ctx, projectName, options)
}
// UnPause implements Service interface
func (s *ServiceProxy) UnPause(ctx context.Context, project string, options PauseOptions) error {
func (s *ServiceProxy) UnPause(ctx context.Context, projectName string, options PauseOptions) error {
if s.UnPauseFn == nil {
return ErrNotImplemented
}
return s.UnPauseFn(ctx, project, options)
return s.UnPauseFn(ctx, projectName, options)
}
// Top implements Service interface
@@ -286,19 +286,19 @@ func (s *ServiceProxy) Top(ctx context.Context, project string, services []strin
}
// Events implements Service interface
func (s *ServiceProxy) Events(ctx context.Context, project string, options EventsOptions) error {
func (s *ServiceProxy) Events(ctx context.Context, projectName string, options EventsOptions) error {
if s.EventsFn == nil {
return ErrNotImplemented
}
return s.EventsFn(ctx, project, options)
return s.EventsFn(ctx, projectName, options)
}
// Port implements Service interface
func (s *ServiceProxy) Port(ctx context.Context, project string, service string, port int, options PortOptions) (string, int, error) {
func (s *ServiceProxy) Port(ctx context.Context, projectName string, service string, port int, options PortOptions) (string, int, error) {
if s.PortFn == nil {
return "", 0, ErrNotImplemented
}
return s.PortFn(ctx, project, service, port, options)
return s.PortFn(ctx, projectName, service, port, options)
}
// Images implements Service interface

View File

@@ -48,7 +48,7 @@ func (s *composeService) attach(ctx context.Context, project *types.Project, lis
fmt.Printf("Attaching to %s\n", strings.Join(names, ", "))
for _, container := range containers {
err := s.attachContainer(ctx, container, listener, project)
err := s.attachContainer(ctx, container, listener)
if err != nil {
return nil, err
}
@@ -56,13 +56,9 @@ func (s *composeService) attach(ctx context.Context, project *types.Project, lis
return containers, err
}
func (s *composeService) attachContainer(ctx context.Context, container moby.Container, listener api.ContainerEventListener, project *types.Project) error {
func (s *composeService) attachContainer(ctx context.Context, container moby.Container, listener api.ContainerEventListener) error {
serviceName := container.Labels[api.ServiceLabel]
containerName := getContainerNameWithoutProject(container)
service, err := project.GetService(serviceName)
if err != nil {
return err
}
listener(api.ContainerEvent{
Type: api.ContainerEventAttach,
@@ -78,7 +74,13 @@ func (s *composeService) attachContainer(ctx context.Context, container moby.Con
Line: line,
})
})
_, _, err = s.attachContainerStreams(ctx, container.ID, service.Tty, nil, w, w)
inspect, err := s.dockerCli.Client().ContainerInspect(ctx, container.ID)
if err != nil {
return err
}
_, _, err = s.attachContainerStreams(ctx, container.ID, inspect.Config.Tty, nil, w, w)
return err
}

View File

@@ -31,6 +31,8 @@ import (
bclient "github.com/moby/buildkit/client"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/auth/authprovider"
"github.com/moby/buildkit/session/secrets/secretsprovider"
"github.com/moby/buildkit/session/sshforward/sshprovider"
specs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/docker/compose/v2/pkg/api"
@@ -62,7 +64,7 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
if service.Build != nil {
imageName := getImageName(service, project.Name)
imagesToBuild = append(imagesToBuild, imageName)
buildOptions, err := s.toBuildOptions(project, service, imageName)
buildOptions, err := s.toBuildOptions(project, service, imageName, options.SSHs)
if err != nil {
return err
}
@@ -80,7 +82,6 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
Attrs: map[string]string{"ref": image},
})
}
opts[imageName] = buildOptions
}
}
@@ -159,7 +160,7 @@ func (s *composeService) getBuildOptions(project *types.Project, images map[stri
if localImagePresent && service.PullPolicy != types.PullPolicyBuild {
continue
}
opt, err := s.toBuildOptions(project, service, imageName)
opt, err := s.toBuildOptions(project, service, imageName, []types.SSHKey{})
if err != nil {
return nil, err
}
@@ -209,7 +210,7 @@ func (s *composeService) doBuild(ctx context.Context, project *types.Project, op
return s.doBuildBuildkit(ctx, project, opts, mode)
}
func (s *composeService) toBuildOptions(project *types.Project, service types.ServiceConfig, imageTag string) (build.Options, error) {
func (s *composeService) toBuildOptions(project *types.Project, service types.ServiceConfig, imageTag string, sshKeys []types.SSHKey) (build.Options, error) {
var tags []string
tags = append(tags, imageTag)
@@ -243,6 +244,37 @@ func (s *composeService) toBuildOptions(project *types.Project, service types.Se
return build.Options{}, err
}
sessionConfig := []session.Attachable{
authprovider.NewDockerAuthProvider(s.stderr()),
}
if len(sshKeys) > 0 || len(service.Build.SSH) > 0 {
sshAgentProvider, err := sshAgentProvider(append(service.Build.SSH, sshKeys...))
if err != nil {
return build.Options{}, err
}
sessionConfig = append(sessionConfig, sshAgentProvider)
}
if len(service.Build.Secrets) > 0 {
var sources []secretsprovider.Source
for _, secret := range service.Build.Secrets {
config := project.Secrets[secret.Source]
if config.File == "" {
return build.Options{}, fmt.Errorf("build.secrets only supports file-based secrets: %q", secret.Source)
}
sources = append(sources, secretsprovider.Source{
ID: secret.Source,
FilePath: config.File,
})
}
store, err := secretsprovider.NewStore(sources)
if err != nil {
return build.Options{}, err
}
p := secretsprovider.NewSecretProvider(store)
sessionConfig = append(sessionConfig, p)
}
return build.Options{
Inputs: build.Inputs{
ContextPath: service.Build.Context,
@@ -260,9 +292,7 @@ func (s *composeService) toBuildOptions(project *types.Project, service types.Se
Labels: service.Build.Labels,
NetworkMode: service.Build.Network,
ExtraHosts: service.Build.ExtraHosts,
Session: []session.Attachable{
authprovider.NewDockerAuthProvider(s.stderr()),
},
Session: sessionConfig,
}, nil
}
@@ -296,3 +326,14 @@ func dockerFilePath(context string, dockerfile string) string {
}
return filepath.Join(context, dockerfile)
}
func sshAgentProvider(sshKeys types.SSHConfig) (session.Attachable, error) {
sshConfig := make([]sshprovider.AgentConfig, 0, len(sshKeys))
for _, sshKey := range sshKeys {
sshConfig = append(sshConfig, sshprovider.AgentConfig{
ID: sshKey.ID,
Paths: []string{sshKey.Path},
})
}
return sshprovider.NewSSHAgentProvider(sshConfig)
}

View File

@@ -143,17 +143,8 @@ func (s *composeService) doBuildClassicSimpleImage(ctx context.Context, options
return "", err
}
// if up to this point nothing has set the context then we must have another
// way for sending it(streaming) and set the context to the Dockerfile
if dockerfileCtx != nil && buildCtx == nil {
buildCtx = dockerfileCtx
}
progressOutput := streamformatter.NewProgressOutput(progBuff)
var body io.Reader
if buildCtx != nil {
body = progress.NewProgressReader(buildCtx, progressOutput, 0, "", "Sending build context to Docker daemon")
}
body := progress.NewProgressReader(buildCtx, progressOutput, 0, "", "Sending build context to Docker daemon")
configFile := s.configFile()
creds, err := configFile.GetAllCredentials()

View File

@@ -42,9 +42,10 @@ const (
acrossServices = fromService | toService
)
func (s *composeService) Copy(ctx context.Context, project string, opts api.CopyOptions) error {
srcService, srcPath := splitCpArg(opts.Source)
destService, dstPath := splitCpArg(opts.Destination)
func (s *composeService) Copy(ctx context.Context, projectName string, options api.CopyOptions) error {
projectName = strings.ToLower(projectName)
srcService, srcPath := splitCpArg(options.Source)
destService, dstPath := splitCpArg(options.Destination)
var direction copyDirection
var serviceName string
@@ -53,7 +54,7 @@ func (s *composeService) Copy(ctx context.Context, project string, opts api.Copy
serviceName = srcService
// copying from multiple containers of a services doesn't make sense.
if opts.All {
if options.All {
return errors.New("cannot use the --all flag when copying from a service")
}
}
@@ -62,7 +63,7 @@ func (s *composeService) Copy(ctx context.Context, project string, opts api.Copy
serviceName = destService
}
containers, err := s.getContainers(ctx, project, oneOffExclude, true, serviceName)
containers, err := s.getContainers(ctx, projectName, oneOffExclude, true, serviceName)
if err != nil {
return err
}
@@ -71,8 +72,8 @@ func (s *composeService) Copy(ctx context.Context, project string, opts api.Copy
return fmt.Errorf("no container found for service %q", serviceName)
}
if !opts.All {
containers = containers.filter(indexed(opts.Index))
if !options.All {
containers = containers.filter(indexed(options.Index))
}
g := errgroup.Group{}
@@ -81,9 +82,9 @@ func (s *composeService) Copy(ctx context.Context, project string, opts api.Copy
g.Go(func() error {
switch direction {
case fromService:
return s.copyFromContainer(ctx, containerID, srcPath, dstPath, opts)
return s.copyFromContainer(ctx, containerID, srcPath, dstPath, options)
case toService:
return s.copyToContainer(ctx, containerID, srcPath, dstPath, opts)
return s.copyToContainer(ctx, containerID, srcPath, dstPath, options)
case acrossServices:
return errors.New("copying between services is not supported")
default:

View File

@@ -173,6 +173,10 @@ func prepareServicesDependsOn(p *types.Project) error {
dependencies = append(dependencies, spec[0])
}
for _, link := range service.Links {
dependencies = append(dependencies, strings.Split(link, ":")[0])
}
if len(dependencies) == 0 {
continue
}
@@ -709,11 +713,13 @@ func (s *composeService) buildContainerVolumes(ctx context.Context, p types.Proj
MOUNTS:
for _, m := range mountOptions {
volumeMounts[m.Target] = struct{}{}
// `Bind` API is used when host path need to be created if missing, `Mount` is preferred otherwise
if m.Type == mount.TypeBind || m.Type == mount.TypeNamedPipe {
// `Mount` is preferred but does not offer option to created host path if missing
// so `Bind` API is used here with raw volume string
// see https://github.com/moby/moby/issues/43483
for _, v := range service.Volumes {
if v.Target == m.Target && v.Bind != nil && v.Bind.CreateHostPath {
binds = append(binds, fmt.Sprintf("%s:%s:%s", m.Source, m.Target, getBindMode(v.Bind, m.ReadOnly)))
binds = append(binds, v.String())
continue MOUNTS
}
}
@@ -723,23 +729,6 @@ MOUNTS:
return volumeMounts, binds, mounts, nil
}
func getBindMode(bind *types.ServiceVolumeBind, readOnly bool) string {
mode := "rw"
if readOnly {
mode = "ro"
}
switch bind.SELinux {
case types.SELinuxShared:
mode += ",z"
case types.SELinuxPrivate:
mode += ",Z"
}
return mode
}
func buildContainerMountOptions(p types.Project, s types.ServiceConfig, img moby.ImageInspect, inherit *moby.Container) ([]mount.Mount, error) {
var mounts = map[string]mount.Mount{}
if inherit != nil {
@@ -1059,7 +1048,10 @@ func (s *composeService) ensureNetwork(ctx context.Context, n types.NetworkConfi
for _, ipamConfig := range n.Ipam.Config {
config := network.IPAMConfig{
Subnet: ipamConfig.Subnet,
Subnet: ipamConfig.Subnet,
IPRange: ipamConfig.IPRange,
Gateway: ipamConfig.Gateway,
AuxAddress: ipamConfig.AuxiliaryAddresses,
}
createOpts.IPAM.Config = append(createOpts.IPAM.Config, config)
}

View File

@@ -143,15 +143,6 @@ func TestBuildContainerMountOptions(t *testing.T) {
assert.Equal(t, mounts[1].Target, "/var/myvolume2")
}
func TestGetBindMode(t *testing.T) {
assert.Equal(t, getBindMode(&composetypes.ServiceVolumeBind{}, false), "rw")
assert.Equal(t, getBindMode(&composetypes.ServiceVolumeBind{}, true), "ro")
assert.Equal(t, getBindMode(&composetypes.ServiceVolumeBind{SELinux: composetypes.SELinuxShared}, false), "rw,z")
assert.Equal(t, getBindMode(&composetypes.ServiceVolumeBind{SELinux: composetypes.SELinuxPrivate}, false), "rw,Z")
assert.Equal(t, getBindMode(&composetypes.ServiceVolumeBind{SELinux: composetypes.SELinuxShared}, true), "ro,z")
assert.Equal(t, getBindMode(&composetypes.ServiceVolumeBind{SELinux: composetypes.SELinuxPrivate}, true), "ro,Z")
}
func TestGetDefaultNetworkMode(t *testing.T) {
t.Run("returns the network with the highest priority when service has multiple networks", func(t *testing.T) {
service := composetypes.ServiceConfig{

View File

@@ -23,6 +23,7 @@ import (
"time"
"github.com/compose-spec/compose-go/types"
"github.com/docker/cli/cli/registry/client"
moby "github.com/docker/docker/api/types"
"github.com/docker/docker/errdefs"
"golang.org/x/sync/errgroup"
@@ -81,7 +82,7 @@ func (s *composeService) down(ctx context.Context, projectName string, options a
ops := s.ensureNetworksDown(ctx, project, w)
if options.Images != "" {
ops = append(ops, s.ensureImagesDown(ctx, projectName, options, w)...)
ops = append(ops, s.ensureImagesDown(ctx, project, options, w)...)
}
if options.Volumes {
@@ -113,9 +114,9 @@ func (s *composeService) ensureVolumesDown(ctx context.Context, project *types.P
return ops
}
func (s *composeService) ensureImagesDown(ctx context.Context, projectName string, options api.DownOptions, w progress.Writer) []downOp {
func (s *composeService) ensureImagesDown(ctx context.Context, project *types.Project, options api.DownOptions, w progress.Writer) []downOp {
var ops []downOp
for image := range s.getServiceImages(options, projectName) {
for image := range s.getServiceImages(options, project) {
image := image
ops = append(ops, func() error {
return s.removeImage(ctx, image, w)
@@ -131,6 +132,11 @@ func (s *composeService) ensureNetworksDown(ctx context.Context, project *types.
continue
}
networkName := n.Name
_, err := s.apiClient().NetworkInspect(ctx, networkName, moby.NetworkInspectOptions{})
if client.IsNotFound(err) {
return nil
}
ops = append(ops, func() error {
return s.removeNetwork(ctx, networkName, w)
})
@@ -138,15 +144,15 @@ func (s *composeService) ensureNetworksDown(ctx context.Context, project *types.
return ops
}
func (s *composeService) getServiceImages(options api.DownOptions, projectName string) map[string]struct{} {
func (s *composeService) getServiceImages(options api.DownOptions, project *types.Project) map[string]struct{} {
images := map[string]struct{}{}
for _, service := range options.Project.Services {
for _, service := range project.Services {
image := service.Image
if options.Images == "local" && image != "" {
continue
}
if image == "" {
image = getImageName(service, projectName)
image = getImageName(service, project.Name)
}
images[image] = struct{}{}
}
@@ -232,7 +238,10 @@ func (s *composeService) removeContainers(ctx context.Context, w progress.Writer
func (s *composeService) getProjectWithResources(ctx context.Context, containers Containers, projectName string) (*types.Project, error) {
containers = containers.filter(isNotOneOff)
project, _ := s.projectFromName(containers, projectName)
project, err := s.projectFromName(containers, projectName)
if err != nil {
return nil, err
}
volumes, err := s.actualVolumes(ctx, projectName)
if err != nil {

View File

@@ -23,7 +23,6 @@ import (
compose "github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/mocks"
moby "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/volume"
@@ -60,6 +59,7 @@ func TestDown(t *testing.T) {
api.EXPECT().ContainerRemove(gomock.Any(), "456", moby.ContainerRemoveOptions{Force: true}).Return(nil)
api.EXPECT().ContainerRemove(gomock.Any(), "789", moby.ContainerRemoveOptions{Force: true}).Return(nil)
api.EXPECT().NetworkInspect(gomock.Any(), "myProject_default", moby.NetworkInspectOptions{}).Return(moby.NetworkResource{Name: "myProject_default"}, nil)
api.EXPECT().NetworkRemove(gomock.Any(), "myProject_default").Return(nil)
err := tested.Down(context.Background(), strings.ToLower(testProject), compose.DownOptions{})
@@ -94,6 +94,7 @@ func TestDownRemoveOrphans(t *testing.T) {
api.EXPECT().ContainerRemove(gomock.Any(), "789", moby.ContainerRemoveOptions{Force: true}).Return(nil)
api.EXPECT().ContainerRemove(gomock.Any(), "321", moby.ContainerRemoveOptions{Force: true}).Return(nil)
api.EXPECT().NetworkInspect(gomock.Any(), "myProject_default", moby.NetworkInspectOptions{}).Return(moby.NetworkResource{Name: "myProject_default"}, nil)
api.EXPECT().NetworkRemove(gomock.Any(), "myProject_default").Return(nil)
err := tested.Down(context.Background(), strings.ToLower(testProject), compose.DownOptions{RemoveOrphans: true})

View File

@@ -29,9 +29,10 @@ import (
"github.com/docker/compose/v2/pkg/utils"
)
func (s *composeService) Events(ctx context.Context, project string, options api.EventsOptions) error {
func (s *composeService) Events(ctx context.Context, projectName string, options api.EventsOptions) error {
projectName = strings.ToLower(projectName)
events, errors := s.apiClient().Events(ctx, moby.EventsOptions{
Filters: filters.NewArgs(projectFilter(project)),
Filters: filters.NewArgs(projectFilter(projectName)),
})
for {
select {

View File

@@ -19,6 +19,7 @@ package compose
import (
"context"
"fmt"
"strings"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command/container"
@@ -27,22 +28,23 @@ import (
"github.com/docker/docker/api/types/filters"
)
func (s *composeService) Exec(ctx context.Context, project string, opts api.RunOptions) (int, error) {
target, err := s.getExecTarget(ctx, project, opts)
func (s *composeService) Exec(ctx context.Context, projectName string, options api.RunOptions) (int, error) {
projectName = strings.ToLower(projectName)
target, err := s.getExecTarget(ctx, projectName, options)
if err != nil {
return 0, err
}
exec := container.NewExecOptions()
exec.Interactive = opts.Interactive
exec.TTY = opts.Tty
exec.Detach = opts.Detach
exec.User = opts.User
exec.Privileged = opts.Privileged
exec.Workdir = opts.WorkingDir
exec.Interactive = options.Interactive
exec.TTY = options.Tty
exec.Detach = options.Detach
exec.User = options.User
exec.Privileged = options.Privileged
exec.Workdir = options.WorkingDir
exec.Container = target.ID
exec.Command = opts.Command
for _, v := range opts.Environment {
exec.Command = options.Command
for _, v := range options.Environment {
err := exec.Env.Set(v)
if err != nil {
return 0, err

View File

@@ -32,6 +32,7 @@ import (
)
func (s *composeService) Images(ctx context.Context, projectName string, options api.ImagesOptions) ([]api.ImageSummary, error) {
projectName = strings.ToLower(projectName)
allContainers, err := s.apiClient().ContainerList(ctx, moby.ContainerListOptions{
All: true,
Filters: filters.NewArgs(projectFilter(projectName)),

View File

@@ -19,6 +19,7 @@ package compose
import (
"context"
"fmt"
"strings"
moby "github.com/docker/docker/api/types"
"golang.org/x/sync/errgroup"
@@ -27,19 +28,19 @@ import (
"github.com/docker/compose/v2/pkg/progress"
)
func (s *composeService) Kill(ctx context.Context, project string, options api.KillOptions) error {
func (s *composeService) Kill(ctx context.Context, projectName string, options api.KillOptions) error {
return progress.Run(ctx, func(ctx context.Context) error {
return s.kill(ctx, project, options)
return s.kill(ctx, strings.ToLower(projectName), options)
})
}
func (s *composeService) kill(ctx context.Context, project string, options api.KillOptions) error {
func (s *composeService) kill(ctx context.Context, projectName string, options api.KillOptions) error {
w := progress.ContextWriter(ctx)
services := options.Services
var containers Containers
containers, err := s.getContainers(ctx, project, oneOffInclude, false, services...)
containers, err := s.getContainers(ctx, projectName, oneOffInclude, false, services...)
if err != nil {
return err
}

View File

@@ -19,6 +19,7 @@ package compose
import (
"context"
"io"
"strings"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/utils"
@@ -28,6 +29,7 @@ import (
)
func (s *composeService) Logs(ctx context.Context, projectName string, consumer api.LogConsumer, options api.LogOptions) error {
projectName = strings.ToLower(projectName)
containers, err := s.getContainers(ctx, projectName, oneOffExclude, true, options.Services...)
if err != nil {
return err

View File

@@ -18,6 +18,7 @@ package compose
import (
"context"
"strings"
moby "github.com/docker/docker/api/types"
"golang.org/x/sync/errgroup"
@@ -26,9 +27,9 @@ import (
"github.com/docker/compose/v2/pkg/progress"
)
func (s *composeService) Pause(ctx context.Context, project string, options api.PauseOptions) error {
func (s *composeService) Pause(ctx context.Context, projectName string, options api.PauseOptions) error {
return progress.Run(ctx, func(ctx context.Context) error {
return s.pause(ctx, project, options)
return s.pause(ctx, strings.ToLower(projectName), options)
})
}
@@ -54,14 +55,14 @@ func (s *composeService) pause(ctx context.Context, project string, options api.
return eg.Wait()
}
func (s *composeService) UnPause(ctx context.Context, project string, options api.PauseOptions) error {
func (s *composeService) UnPause(ctx context.Context, projectName string, options api.PauseOptions) error {
return progress.Run(ctx, func(ctx context.Context) error {
return s.unPause(ctx, project, options)
return s.unPause(ctx, strings.ToLower(projectName), options)
})
}
func (s *composeService) unPause(ctx context.Context, project string, options api.PauseOptions) error {
containers, err := s.getContainers(ctx, project, oneOffExclude, false, options.Services...)
func (s *composeService) unPause(ctx context.Context, projectName string, options api.PauseOptions) error {
containers, err := s.getContainers(ctx, projectName, oneOffExclude, false, options.Services...)
if err != nil {
return err
}

View File

@@ -19,6 +19,7 @@ package compose
import (
"context"
"fmt"
"strings"
"github.com/docker/compose/v2/pkg/api"
@@ -26,10 +27,11 @@ import (
"github.com/docker/docker/api/types/filters"
)
func (s *composeService) Port(ctx context.Context, project string, service string, port int, options api.PortOptions) (string, int, error) {
func (s *composeService) Port(ctx context.Context, projectName string, service string, port int, options api.PortOptions) (string, int, error) {
projectName = strings.ToLower(projectName)
list, err := s.apiClient().ContainerList(ctx, moby.ContainerListOptions{
Filters: filters.NewArgs(
projectFilter(project),
projectFilter(projectName),
serviceFilter(service),
containerNumberFilter(options.Index),
),

View File

@@ -19,6 +19,7 @@ package compose
import (
"context"
"sort"
"strings"
"golang.org/x/sync/errgroup"
@@ -26,6 +27,7 @@ import (
)
func (s *composeService) Ps(ctx context.Context, projectName string, options api.PsOptions) ([]api.ContainerSummary, error) {
projectName = strings.ToLower(projectName)
oneOff := oneOffExclude
if options.All {
oneOff = oneOffInclude

View File

@@ -36,12 +36,12 @@ import (
"github.com/docker/compose/v2/pkg/progress"
)
func (s *composeService) Pull(ctx context.Context, project *types.Project, opts api.PullOptions) error {
if opts.Quiet {
return s.pull(ctx, project, opts)
func (s *composeService) Pull(ctx context.Context, project *types.Project, options api.PullOptions) error {
if options.Quiet {
return s.pull(ctx, project, options)
}
return progress.Run(ctx, func(ctx context.Context) error {
return s.pull(ctx, project, opts)
return s.pull(ctx, project, options)
})
}
@@ -55,6 +55,11 @@ func (s *composeService) pull(ctx context.Context, project *types.Project, opts
info.IndexServerAddress = registry.IndexServer
}
images, err := s.getLocalImagesDigests(ctx, project)
if err != nil {
return err
}
w := progress.ContextWriter(ctx)
eg, ctx := errgroup.WithContext(ctx)
@@ -69,8 +74,28 @@ func (s *composeService) pull(ctx context.Context, project *types.Project, opts
})
continue
}
switch service.PullPolicy {
case types.PullPolicyNever, types.PullPolicyBuild:
w.Event(progress.Event{
ID: service.Name,
Status: progress.Done,
Text: "Skipped",
})
continue
case types.PullPolicyMissing, types.PullPolicyIfNotPresent:
if _, ok := images[service.Image]; ok {
w.Event(progress.Event{
ID: service.Name,
Status: progress.Done,
Text: "Exists",
})
continue
}
}
eg.Go(func() error {
err := s.pullServiceImage(ctx, service, info, s.configFile(), w, false)
_, err := s.pullServiceImage(ctx, service, info, s.configFile(), w, false)
if err != nil {
if !opts.IgnoreFailures {
if service.Build != nil {
@@ -93,7 +118,7 @@ func (s *composeService) pull(ctx context.Context, project *types.Project, opts
return err
}
func (s *composeService) pullServiceImage(ctx context.Context, service types.ServiceConfig, info moby.Info, configFile driver.Auth, w progress.Writer, quietPull bool) error {
func (s *composeService) pullServiceImage(ctx context.Context, service types.ServiceConfig, info moby.Info, configFile driver.Auth, w progress.Writer, quietPull bool) (string, error) {
w.Event(progress.Event{
ID: service.Name,
Status: progress.Working,
@@ -101,12 +126,12 @@ func (s *composeService) pullServiceImage(ctx context.Context, service types.Ser
})
ref, err := reference.ParseNormalizedNamed(service.Image)
if err != nil {
return err
return "", err
}
repoInfo, err := registry.ParseRepositoryInfo(ref)
if err != nil {
return err
return "", err
}
key := repoInfo.Index.Name
@@ -116,12 +141,12 @@ func (s *composeService) pullServiceImage(ctx context.Context, service types.Ser
authConfig, err := configFile.GetAuthConfig(key)
if err != nil {
return err
return "", err
}
buf, err := json.Marshal(authConfig)
if err != nil {
return err
return "", err
}
stream, err := s.apiClient().ImagePull(ctx, service.Image, moby.ImagePullOptions{
@@ -134,7 +159,7 @@ func (s *composeService) pullServiceImage(ctx context.Context, service types.Ser
Status: progress.Error,
Text: "Error",
})
return WrapCategorisedComposeError(err, PullFailure)
return "", WrapCategorisedComposeError(err, PullFailure)
}
dec := json.NewDecoder(stream)
@@ -144,10 +169,10 @@ func (s *composeService) pullServiceImage(ctx context.Context, service types.Ser
if err == io.EOF {
break
}
return WrapCategorisedComposeError(err, PullFailure)
return "", WrapCategorisedComposeError(err, PullFailure)
}
if jm.Error != nil {
return WrapCategorisedComposeError(errors.New(jm.Error.Message), PullFailure)
return "", WrapCategorisedComposeError(errors.New(jm.Error.Message), PullFailure)
}
if !quietPull {
toPullProgressEvent(service.Name, jm, w)
@@ -158,7 +183,12 @@ func (s *composeService) pullServiceImage(ctx context.Context, service types.Ser
Status: progress.Done,
Text: "Pulled",
})
return nil
inspected, _, err := s.dockerCli.Client().ImageInspectWithRaw(ctx, service.Image)
if err != nil {
return "", err
}
return inspected.ID, nil
}
func (s *composeService) pullRequiredImages(ctx context.Context, project *types.Project, images map[string]string, quietPull bool) error {
@@ -195,10 +225,12 @@ func (s *composeService) pullRequiredImages(ctx context.Context, project *types.
return progress.Run(ctx, func(ctx context.Context) error {
w := progress.ContextWriter(ctx)
eg, ctx := errgroup.WithContext(ctx)
for _, service := range needPull {
service := service
pulledImages := make([]string, len(needPull))
for i, service := range needPull {
i, service := i, service
eg.Go(func() error {
err := s.pullServiceImage(ctx, service, info, s.configFile(), w, quietPull)
id, err := s.pullServiceImage(ctx, service, info, s.configFile(), w, quietPull)
pulledImages[i] = id
if err != nil && service.Build != nil {
// image can be built, so we can ignore pull failure
return nil
@@ -206,7 +238,16 @@ func (s *composeService) pullRequiredImages(ctx context.Context, project *types.
return err
})
}
return eg.Wait()
for i, service := range needPull {
if pulledImages[i] != "" {
images[service.Image] = pulledImages[i]
}
}
err := eg.Wait()
if err != nil {
return err
}
return err
})
}

View File

@@ -30,6 +30,7 @@ import (
)
func (s *composeService) Remove(ctx context.Context, projectName string, options api.RemoveOptions) error {
projectName = strings.ToLower(projectName)
containers, _, err := s.actualState(ctx, projectName, options.Services)
if err != nil {
if api.IsNotFoundError(err) {

View File

@@ -18,6 +18,7 @@ package compose
import (
"context"
"strings"
"github.com/docker/compose/v2/pkg/api"
"golang.org/x/sync/errgroup"
@@ -28,7 +29,7 @@ import (
func (s *composeService) Restart(ctx context.Context, projectName string, options api.RestartOptions) error {
return progress.Run(ctx, func(ctx context.Context) error {
return s.restart(ctx, projectName, options)
return s.restart(ctx, strings.ToLower(projectName), options)
})
}

View File

@@ -89,7 +89,7 @@ func (s *composeService) prepareRun(ctx context.Context, project *types.Project,
updateServices(&service, observedState)
created, err := s.createContainer(ctx, project, service, service.ContainerName, 1,
opts.Detach && opts.AutoRemove, opts.UseNetworkAliases, opts.Interactive)
opts.AutoRemove, opts.UseNetworkAliases, opts.Interactive)
if err != nil {
return "", err
}

View File

@@ -18,6 +18,7 @@ package compose
import (
"context"
"strings"
"github.com/compose-spec/compose-go/types"
moby "github.com/docker/docker/api/types"
@@ -30,20 +31,23 @@ import (
func (s *composeService) Start(ctx context.Context, projectName string, options api.StartOptions) error {
return progress.Run(ctx, func(ctx context.Context) error {
return s.start(ctx, projectName, options, nil)
return s.start(ctx, strings.ToLower(projectName), options, nil)
})
}
func (s *composeService) start(ctx context.Context, projectName string, options api.StartOptions, listener api.ContainerEventListener) error {
var containers Containers
containers, err := s.getContainers(ctx, projectName, oneOffExclude, true)
if err != nil {
return err
}
project := options.Project
if project == nil {
var containers Containers
containers, err := s.getContainers(ctx, projectName, oneOffExclude, true)
if err != nil {
return err
}
project, err := s.projectFromName(containers, projectName, options.AttachTo...)
if err != nil {
return err
project, err = s.projectFromName(containers, projectName, options.AttachTo...)
if err != nil {
return err
}
}
eg, ctx := errgroup.WithContext(ctx)
@@ -55,12 +59,12 @@ func (s *composeService) start(ctx context.Context, projectName string, options
eg.Go(func() error {
return s.watchContainers(context.Background(), project.Name, options.AttachTo, listener, attached, func(container moby.Container) error {
return s.attachContainer(ctx, container, listener, project)
return s.attachContainer(ctx, container, listener)
})
})
}
err = InDependencyOrder(ctx, project, func(c context.Context, name string) error {
err := InDependencyOrder(ctx, project, func(c context.Context, name string) error {
service, err := project.GetService(name)
if err != nil {
return err

View File

@@ -18,6 +18,7 @@ package compose
import (
"context"
"strings"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/progress"
@@ -25,7 +26,7 @@ import (
func (s *composeService) Stop(ctx context.Context, projectName string, options api.StopOptions) error {
return progress.Run(ctx, func(ctx context.Context) error {
return s.stop(ctx, projectName, options)
return s.stop(ctx, strings.ToLower(projectName), options)
})
}

View File

@@ -18,12 +18,14 @@ package compose
import (
"context"
"strings"
"github.com/docker/compose/v2/pkg/api"
"golang.org/x/sync/errgroup"
)
func (s *composeService) Top(ctx context.Context, projectName string, services []string) ([]api.ContainerProcSummary, error) {
projectName = strings.ToLower(projectName)
var containers Containers
containers, err := s.getContainers(ctx, projectName, oneOffInclude, false)
if err != nil {

View File

@@ -18,6 +18,7 @@ package e2e
import (
"net/http"
"os"
"strings"
"testing"
"time"
@@ -79,6 +80,57 @@ func TestLocalComposeBuild(t *testing.T) {
res.Assert(t, icmd.Expected{Out: `"RESULT": "SUCCESS"`})
})
t.Run("build failed with ssh default value", func(t *testing.T) {
//unset SSH_AUTH_SOCK to be sure we don't have a default value for the SSH Agent
defaultSSHAUTHSOCK := os.Getenv("SSH_AUTH_SOCK")
os.Unsetenv("SSH_AUTH_SOCK") //nolint:errcheck
defer os.Setenv("SSH_AUTH_SOCK", defaultSSHAUTHSOCK) //nolint:errcheck
res := c.RunDockerComposeCmdNoCheck("--project-directory", "fixtures/build-test", "build", "--ssh", "")
res.Assert(t, icmd.Expected{
ExitCode: 1,
Err: "invalid empty ssh agent socket: make sure SSH_AUTH_SOCK is set",
})
})
t.Run("build succeed with ssh from Compose file", func(t *testing.T) {
c.RunDockerOrExitError("rmi", "build-test-ssh")
c.RunDockerComposeCmd("--project-directory", "fixtures/build-test/ssh", "build")
c.RunDockerCmd("image", "inspect", "build-test-ssh")
})
t.Run("build succeed with ssh from CLI", func(t *testing.T) {
c.RunDockerOrExitError("rmi", "build-test-ssh")
c.RunDockerComposeCmd("-f", "fixtures/build-test/ssh/compose-without-ssh.yaml", "--project-directory",
"fixtures/build-test/ssh", "build", "--no-cache", "--ssh", "fake-ssh=./fixtures/build-test/ssh/fake_rsa")
c.RunDockerCmd("image", "inspect", "build-test-ssh")
})
t.Run("build failed with wrong ssh key id from CLI", func(t *testing.T) {
c.RunDockerOrExitError("rmi", "build-test-ssh")
res := c.RunDockerComposeCmdNoCheck("-f", "fixtures/build-test/ssh/compose-without-ssh.yaml",
"--project-directory", "fixtures/build-test/ssh", "build", "--no-cache", "--ssh",
"wrong-ssh=./fixtures/build-test/ssh/fake_rsa")
res.Assert(t, icmd.Expected{
ExitCode: 17,
Err: "failed to solve: rpc error: code = Unknown desc = unset ssh forward key fake-ssh",
})
})
t.Run("build succeed as part of up with ssh from Compose file", func(t *testing.T) {
c.RunDockerOrExitError("rmi", "build-test-ssh")
c.RunDockerComposeCmd("--project-directory", "fixtures/build-test/ssh", "up", "-d", "--build")
t.Cleanup(func() {
c.RunDockerComposeCmd("--project-directory", "fixtures/build-test/ssh", "down")
})
c.RunDockerCmd("image", "inspect", "build-test-ssh")
})
t.Run("build as part of up", func(t *testing.T) {
c.RunDockerOrExitError("rmi", "build-test_nginx")
c.RunDockerOrExitError("rmi", "custom-nginx")
@@ -117,3 +169,15 @@ func TestLocalComposeBuild(t *testing.T) {
c.RunDockerCmd("rmi", "custom-nginx")
})
}
func TestBuildSecrets(t *testing.T) {
c := NewParallelE2eCLI(t, binDir)
t.Run("build with secrets", func(t *testing.T) {
// ensure local test run does not reuse previously build image
c.RunDockerOrExitError("rmi", "build-test-secret")
res := c.RunDockerComposeCmd("--project-directory", "fixtures/build-test/secrets", "build")
res.Assert(t, icmd.Success)
})
}

View File

@@ -0,0 +1,22 @@
# syntax=docker/dockerfile:1.2
# 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.
FROM alpine
RUN echo "foo" > /tmp/expected
RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret > /tmp/actual
RUN diff /tmp/expected /tmp/actual

View File

@@ -0,0 +1,11 @@
services:
ssh:
image: build-test-secret
build:
context: .
secrets:
- mysecret
secrets:
mysecret:
file: ./secret.txt

View File

@@ -0,0 +1 @@
foo

View File

@@ -0,0 +1,24 @@
# syntax=docker/dockerfile:1.2
# 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.
FROM alpine
RUN apk add --no-cache openssh-client
WORKDIR /compose
COPY fake_rsa.pub /compose/
RUN --mount=type=ssh,id=fake-ssh,required=true diff <(ssh-add -L) <(cat /compose/fake_rsa.pub)

View File

@@ -0,0 +1,5 @@
services:
ssh:
image: build-test-ssh
build:
context: .

View File

@@ -0,0 +1,7 @@
services:
ssh:
image: build-test-ssh
build:
context: .
ssh:
- fake-ssh=./fixtures/build-test/ssh/fake_rsa

View File

@@ -0,0 +1,49 @@
-----BEGIN OPENSSH PRIVATE KEY-----
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
Xsd/RqSc66MAAAAAAQID
-----END OPENSSH PRIVATE KEY-----

View File

@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDucnjECEntXAjre25rLcMIdpNd4Rj3Yfpg1nym0AgFjSZSfoZz2az3ge9wAp6YImQ7R/LpTYk6hJP6rVg8Al/zo2shTjWFl3OvDZB2ob8DeNrhVMBo4lsf3Bp8oelYuzqTKKAa2LcpIFpubgcBFTyWC1EToC4ILX6bDzbUXNOwxYzFGn+spXGCyIxSx13ntZEo52fxNGbo0dwSzLtfvMAnv4KH+a4YYIKTdn35hTOhVW1j/AZiZZdeP81TPGcSrRcvI7wcL5BT/11aWHU4uagy7E3WVi0dEVZay0Jugo2w5wiImwsp9DW3jPiNerk/slMsTk+eB6auvjErbVEWNVoZCk6PJCBmfWjTAC/Lvwo5HCA3QSXBxv9cgol6nPN7MIjJeVJp95e4c/6gyMzazYxc0eUwq/onCHhBjBRDrX5sBw+RyYh2W2IAw0tzFiKoS53zkRBCX1yK6EwprRtmXU4QgvBVIhqwS70EQpWvPnZllUsYxyGo5X/h/U+o8RqCd+dFgS20noC5phRole9JA/pmPgAVvpas/AQEgU64Af2Lha0bnZAArq5zXCw9mUebwn5WdMQEoW4YRG7+4kFY+jjcuO7xWse5lTxB440REp8ltzUQj1empaL7dVxZPRAm3EQZbZiYPnTn5wo1zfXHA61yrCiC3BPTCe6PQEB/fcdjfw==

View File

@@ -204,17 +204,20 @@ func (c *E2eCLI) RunDockerCmd(args ...string) *icmd.Result {
// RunDockerComposeCmd runs a docker compose command, expects no error and returns a result
func (c *E2eCLI) RunDockerComposeCmd(args ...string) *icmd.Result {
res := c.RunDockerComposeCmdNoCheck(args...)
res.Assert(c.test, icmd.Success)
return res
}
// RunDockerComposeCmdNoCheck runs a docker compose command, don't presume of any expectation and returns a result
func (c *E2eCLI) RunDockerComposeCmdNoCheck(args ...string) *icmd.Result {
if composeStandaloneMode {
composeBinary, err := findExecutable(DockerComposeExecutableName, []string{"../../bin", "../../../bin"})
assert.NilError(c.test, err)
res := icmd.RunCmd(c.NewCmd(composeBinary, args...))
res.Assert(c.test, icmd.Success)
return res
return icmd.RunCmd(c.NewCmd(composeBinary, args...))
}
args = append([]string{"compose"}, args...)
res := icmd.RunCmd(c.NewCmd(DockerExecutableName, args...))
res.Assert(c.test, icmd.Success)
return res
return icmd.RunCmd(c.NewCmd(DockerExecutableName, args...))
}
// StdoutContains returns a predicate on command result expecting a string in stdout

View File

@@ -27,7 +27,7 @@ import (
func TestStartStop(t *testing.T) {
c := NewParallelE2eCLI(t, binDir)
const projectName = "e2e-start-stop"
const projectName = "e2e-start-stop-no-dependencies"
getProjectRegx := func(status string) string {
// match output with random spaces like:
@@ -43,7 +43,7 @@ func TestStartStop(t *testing.T) {
t.Run("Up a project", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "up", "-d")
assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-simple-1 Started"), res.Combined())
assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-no-dependencies-simple-1 Started"), res.Combined())
res = c.RunDockerComposeCmd("ls", "--all")
testify.Regexp(t, getProjectRegx("running"), res.Stdout())
@@ -57,13 +57,13 @@ func TestStartStop(t *testing.T) {
c.RunDockerComposeCmd("-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "stop")
res := c.RunDockerComposeCmd("ls")
assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop"), res.Combined())
assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-no-dependencies"), res.Combined())
res = c.RunDockerComposeCmd("ls", "--all")
testify.Regexp(t, getProjectRegx("exited"), res.Stdout())
res = c.RunDockerComposeCmd("--project-name", projectName, "ps")
assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-words-1"), res.Combined())
assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-no-dependencies-words-1"), res.Combined())
res = c.RunDockerComposeCmd("--project-name", projectName, "ps", "--all")
testify.Regexp(t, getServiceRegx("simple", "exited"), res.Stdout())