mirror of
https://github.com/docker/compose.git
synced 2025-04-07 19:55:07 +02:00
No need to filter services again in backend, filter is done by cli command. Added e2e test, labels one-off and slug
Signed-off-by: Guillaume Tardif <guillaume.tardif@gmail.com>
This commit is contained in:
parent
370781e95e
commit
b289138ca9
@ -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.ensureProjectNetworks(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,10 +88,7 @@ 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) {
|
||||
@ -88,11 +102,15 @@ 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] = s.Labels[oneoffLabel]
|
||||
labels[slugLabel] = s.Labels[slugLabel]
|
||||
} else {
|
||||
labels[oneoffLabel] = "False"
|
||||
}
|
||||
labels[configHashLabel] = hash
|
||||
labels[workingDirLabel] = p.WorkingDir
|
||||
labels[configFilesLabel] = strings.Join(p.ComposeFiles, ",")
|
||||
|
@ -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"
|
||||
|
@ -21,7 +21,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/compose-cli/api/compose"
|
||||
@ -37,12 +36,11 @@ func (s *composeService) CreateOneOffContainer(ctx context.Context, project *typ
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = s.ensureRequiredNetworks(ctx, project, service)
|
||||
if err != nil {
|
||||
if err := s.ensureProjectNetworks(ctx, project); err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = s.ensureRequiredVolumes(ctx, project, service)
|
||||
if err != nil {
|
||||
|
||||
if err := s.ensureProjectVolumes(ctx, project); err != nil {
|
||||
return "", err
|
||||
}
|
||||
// ensure required services are up and running before creating the oneoff container
|
||||
@ -128,123 +126,27 @@ func updateOneOffServiceConfig(service *types.ServiceConfig, projectName string,
|
||||
service.Scale = 1
|
||||
service.ContainerName = fmt.Sprintf("%s_%s_run_%s", projectName, service.Name, moby.TruncateID(slug))
|
||||
service.Labels = types.Labels{
|
||||
"com.docker.compose.slug": slug,
|
||||
"com.docker.compose.oneoff": "True",
|
||||
slugLabel: slug,
|
||||
oneoffLabel: "True",
|
||||
}
|
||||
service.Tty = true
|
||||
service.StdinOpen = true
|
||||
}
|
||||
|
||||
func (s *composeService) ensureRequiredServices(ctx context.Context, project *types.Project, service types.ServiceConfig) error {
|
||||
requiredServices := getDependencyNames(project, service, func() []string {
|
||||
return service.GetDependencies()
|
||||
})
|
||||
if len(requiredServices) > 0 {
|
||||
// dependencies here
|
||||
services, err := project.GetServices(requiredServices)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
project.Services = services
|
||||
err = s.ensureImagesExists(ctx, project)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err := s.ensureImagesExists(ctx, project)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = InDependencyOrder(ctx, project, func(c context.Context, svc types.ServiceConfig) error {
|
||||
err = InDependencyOrder(ctx, project, func(c context.Context, svc types.ServiceConfig) error {
|
||||
if svc.Name != service.Name { // only start dependencies, not service to run one-off
|
||||
return s.ensureService(c, project, svc)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.Start(ctx, project, nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *composeService) ensureRequiredNetworks(ctx context.Context, project *types.Project, service types.ServiceConfig) error {
|
||||
networks := getDependentNetworkNames(project, service)
|
||||
for k, network := range project.Networks {
|
||||
if !contains(networks, network.Name) {
|
||||
continue
|
||||
}
|
||||
if !network.External.External && network.Name != "" {
|
||||
network.Name = fmt.Sprintf("%s_%s", project.Name, k)
|
||||
project.Networks[k] = network
|
||||
}
|
||||
network.Labels = network.Labels.Add(networkLabel, k)
|
||||
network.Labels = network.Labels.Add(projectLabel, project.Name)
|
||||
network.Labels = network.Labels.Add(versionLabel, ComposeVersion)
|
||||
|
||||
err := s.ensureNetwork(ctx, network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *composeService) ensureRequiredVolumes(ctx context.Context, project *types.Project, service types.ServiceConfig) error {
|
||||
volumes := getDependentVolumeNames(project, service)
|
||||
|
||||
for k, volume := range project.Volumes {
|
||||
if !contains(volumes, volume.Name) {
|
||||
continue
|
||||
}
|
||||
if !volume.External.External && volume.Name != "" {
|
||||
volume.Name = fmt.Sprintf("%s_%s", project.Name, k)
|
||||
project.Volumes[k] = volume
|
||||
}
|
||||
volume.Labels = volume.Labels.Add(volumeLabel, k)
|
||||
volume.Labels = volume.Labels.Add(projectLabel, project.Name)
|
||||
volume.Labels = volume.Labels.Add(versionLabel, ComposeVersion)
|
||||
err := s.ensureVolume(ctx, volume)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type filterDependency func() []string
|
||||
|
||||
func getDependencyNames(project *types.Project, service types.ServiceConfig, f filterDependency) []string {
|
||||
names := f()
|
||||
serviceNames := service.GetDependencies()
|
||||
if len(serviceNames) == 0 {
|
||||
return names
|
||||
}
|
||||
if len(serviceNames) > 0 {
|
||||
services, _ := project.GetServices(serviceNames)
|
||||
for _, s := range services {
|
||||
svc := getDependencyNames(project, s, f)
|
||||
names = append(names, svc...)
|
||||
}
|
||||
}
|
||||
sort.Strings(names)
|
||||
return unique(names)
|
||||
}
|
||||
|
||||
func getDependentNetworkNames(project *types.Project, service types.ServiceConfig) []string {
|
||||
return getDependencyNames(project, service, func() []string {
|
||||
names := []string{}
|
||||
for n := range service.Networks {
|
||||
if contains(project.NetworkNames(), n) {
|
||||
names = append(names, n)
|
||||
}
|
||||
}
|
||||
return names
|
||||
})
|
||||
}
|
||||
|
||||
func getDependentVolumeNames(project *types.Project, service types.ServiceConfig) []string {
|
||||
return getDependencyNames(project, service, func() []string {
|
||||
names := []string{}
|
||||
for _, v := range service.Volumes {
|
||||
if contains(project.VolumeNames(), v.Source) {
|
||||
names = append(names, v.Source)
|
||||
}
|
||||
}
|
||||
return names
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.Start(ctx, project, nil)
|
||||
}
|
||||
|
@ -38,14 +38,3 @@ func contains(slice []string, item string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func unique(s []string) []string {
|
||||
items := []string{}
|
||||
for _, item := range s {
|
||||
if contains(items, item) {
|
||||
continue
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
@ -103,6 +103,57 @@ 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")
|
||||
res.Assert(t, icmd.Expected{Out: "Hello there!!"})
|
||||
})
|
||||
|
||||
t.Run("check run container exited", func(t *testing.T) {
|
||||
res := c.RunDockerCmd("ps", "--all")
|
||||
lines := Lines(res.Stdout())
|
||||
var runContainerID 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)
|
||||
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": "`})
|
||||
})
|
||||
|
||||
t.Run("compose run --rm", func(t *testing.T) {
|
||||
res := c.RunDockerCmd("compose", "run", "-f", "./fixtures/run-test/docker-compose.yml", "--rm", "back")
|
||||
res.Assert(t, icmd.Expected{Out: "Hello there!!"})
|
||||
})
|
||||
|
||||
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)
|
||||
|
||||
|
24
tests/compose-e2e/fixtures/run-test/docker-compose.yml
Normal file
24
tests/compose-e2e/fixtures/run-test/docker-compose.yml
Normal file
@ -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…
x
Reference in New Issue
Block a user