mirror of
https://github.com/docker/compose.git
synced 2025-07-23 13:45:00 +02:00
commit
ed0b123b75
@ -285,8 +285,7 @@ func (kc KubeClient) MapPortsToLocalhost(ctx context.Context, opts PortMappingOp
|
|||||||
|
|
||||||
eg, ctx := errgroup.WithContext(ctx)
|
eg, ctx := errgroup.WithContext(ctx)
|
||||||
for serviceName, servicePorts := range opts.Services {
|
for serviceName, servicePorts := range opts.Services {
|
||||||
serviceName := serviceName
|
serviceName, servicePorts := serviceName, servicePorts
|
||||||
servicePorts := servicePorts
|
|
||||||
pod, err := kc.GetPod(ctx, opts.ProjectName, serviceName)
|
pod, err := kc.GetPod(ctx, opts.ProjectName, serviceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -55,6 +55,19 @@ const (
|
|||||||
type convergence struct {
|
type convergence struct {
|
||||||
service *composeService
|
service *composeService
|
||||||
observedState map[string]Containers
|
observedState map[string]Containers
|
||||||
|
stateMutex sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *convergence) getObservedState(serviceName string) Containers {
|
||||||
|
c.stateMutex.Lock()
|
||||||
|
defer c.stateMutex.Unlock()
|
||||||
|
return c.observedState[serviceName]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *convergence) setObservedState(serviceName string, containers Containers) {
|
||||||
|
c.stateMutex.Lock()
|
||||||
|
defer c.stateMutex.Unlock()
|
||||||
|
c.observedState[serviceName] = containers
|
||||||
}
|
}
|
||||||
|
|
||||||
func newConvergence(services []string, state Containers, s *composeService) *convergence {
|
func newConvergence(services []string, state Containers, s *composeService) *convergence {
|
||||||
@ -97,7 +110,7 @@ var mu sync.Mutex
|
|||||||
|
|
||||||
// updateProject updates project after service converged, so dependent services relying on `service:xx` can refer to actual containers.
|
// updateProject updates project after service converged, so dependent services relying on `service:xx` can refer to actual containers.
|
||||||
func (c *convergence) updateProject(project *types.Project, service string) {
|
func (c *convergence) updateProject(project *types.Project, service string) {
|
||||||
containers := c.observedState[service]
|
containers := c.getObservedState(service)
|
||||||
container := containers[0]
|
container := containers[0]
|
||||||
|
|
||||||
// operation is protected by a Mutex so that we can safely update project.Services while running concurrent convergence on services
|
// operation is protected by a Mutex so that we can safely update project.Services while running concurrent convergence on services
|
||||||
@ -148,7 +161,7 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
containers := c.observedState[service.Name]
|
containers := c.getObservedState(service.Name)
|
||||||
actual := len(containers)
|
actual := len(containers)
|
||||||
updated := make(Containers, expected)
|
updated := make(Containers, expected)
|
||||||
|
|
||||||
@ -157,6 +170,7 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
|
|||||||
for i, container := range containers {
|
for i, container := range containers {
|
||||||
if i > expected {
|
if i > expected {
|
||||||
// Scale Down
|
// Scale Down
|
||||||
|
container := container
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
err := c.service.apiClient.ContainerStop(ctx, container.ID, timeout)
|
err := c.service.apiClient.ContainerStop(ctx, container.ID, timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -178,7 +192,7 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
|
|||||||
name := getContainerProgressName(container)
|
name := getContainerProgressName(container)
|
||||||
diverged := container.Labels[api.ConfigHashLabel] != configHash
|
diverged := container.Labels[api.ConfigHashLabel] != configHash
|
||||||
if diverged || recreate == api.RecreateForce || service.Extensions[extLifecycle] == forceRecreate {
|
if diverged || recreate == api.RecreateForce || service.Extensions[extLifecycle] == forceRecreate {
|
||||||
i := i
|
i, container := i, container
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
recreated, err := c.service.recreateContainer(ctx, project, service, container, inherit, timeout)
|
recreated, err := c.service.recreateContainer(ctx, project, service, container, inherit, timeout)
|
||||||
updated[i] = recreated
|
updated[i] = recreated
|
||||||
@ -197,6 +211,7 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
|
|||||||
case ContainerExited:
|
case ContainerExited:
|
||||||
w.Event(progress.CreatedEvent(name))
|
w.Event(progress.CreatedEvent(name))
|
||||||
default:
|
default:
|
||||||
|
container := container
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
return c.service.startContainer(ctx, container)
|
return c.service.startContainer(ctx, container)
|
||||||
})
|
})
|
||||||
@ -212,16 +227,17 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
|
|||||||
// Scale UP
|
// Scale UP
|
||||||
number := next + i
|
number := next + i
|
||||||
name := getContainerName(project.Name, service, number)
|
name := getContainerName(project.Name, service, number)
|
||||||
|
i := i
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
container, err := c.service.createContainer(ctx, project, service, name, number, false, true)
|
container, err := c.service.createContainer(ctx, project, service, name, number, false, true)
|
||||||
updated[actual+i-1] = container
|
updated[actual+i] = container
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = eg.Wait()
|
err = eg.Wait()
|
||||||
c.observedState[service.Name] = updated
|
c.setObservedState(service.Name, updated)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,11 +558,11 @@ func (s *composeService) startService(ctx context.Context, project *types.Projec
|
|||||||
|
|
||||||
w := progress.ContextWriter(ctx)
|
w := progress.ContextWriter(ctx)
|
||||||
eg, ctx := errgroup.WithContext(ctx)
|
eg, ctx := errgroup.WithContext(ctx)
|
||||||
for _, c := range containers {
|
for _, container := range containers {
|
||||||
container := c
|
|
||||||
if container.State == ContainerRunning {
|
if container.State == ContainerRunning {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
container := container
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
eventName := getContainerProgressName(container)
|
eventName := getContainerProgressName(container)
|
||||||
w.Event(progress.StartingEvent(eventName))
|
w.Event(progress.StartingEvent(eventName))
|
||||||
|
@ -81,9 +81,8 @@ func (s *composeService) Copy(ctx context.Context, project *types.Project, opts
|
|||||||
}
|
}
|
||||||
|
|
||||||
g := errgroup.Group{}
|
g := errgroup.Group{}
|
||||||
for i := range containers {
|
for _, container := range containers {
|
||||||
containerID := containers[i].ID
|
containerID := container.ID
|
||||||
|
|
||||||
g.Go(func() error {
|
g.Go(func() error {
|
||||||
switch direction {
|
switch direction {
|
||||||
case fromService:
|
case fromService:
|
||||||
|
@ -91,22 +91,22 @@ func visit(ctx context.Context, project *types.Project, traversalConfig graphTra
|
|||||||
// Note: this could be `graph.walk` or whatever
|
// Note: this could be `graph.walk` or whatever
|
||||||
func run(ctx context.Context, graph *Graph, eg *errgroup.Group, nodes []*Vertex, traversalConfig graphTraversalConfig, fn func(context.Context, string) error) error {
|
func run(ctx context.Context, graph *Graph, eg *errgroup.Group, nodes []*Vertex, traversalConfig graphTraversalConfig, fn func(context.Context, string) error) error {
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
n := node
|
|
||||||
// Don't start this service yet if all of its children have
|
// Don't start this service yet if all of its children have
|
||||||
// not been started yet.
|
// not been started yet.
|
||||||
if len(traversalConfig.filterAdjacentByStatusFn(graph, n.Service, traversalConfig.adjacentServiceStatusToSkip)) != 0 {
|
if len(traversalConfig.filterAdjacentByStatusFn(graph, node.Service, traversalConfig.adjacentServiceStatusToSkip)) != 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node := node
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
err := fn(ctx, n.Service)
|
err := fn(ctx, node.Service)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
graph.UpdateStatus(n.Service, traversalConfig.targetServiceStatus)
|
graph.UpdateStatus(node.Service, traversalConfig.targetServiceStatus)
|
||||||
|
|
||||||
return run(ctx, graph, eg, traversalConfig.adjacentNodesFn(n), traversalConfig, fn)
|
return run(ctx, graph, eg, traversalConfig.adjacentNodesFn(node), traversalConfig, fn)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,17 +217,17 @@ func (s *composeService) stopContainers(ctx context.Context, w progress.Writer,
|
|||||||
func (s *composeService) removeContainers(ctx context.Context, w progress.Writer, containers []moby.Container, timeout *time.Duration, volumes bool) error {
|
func (s *composeService) removeContainers(ctx context.Context, w progress.Writer, containers []moby.Container, timeout *time.Duration, volumes bool) error {
|
||||||
eg, _ := errgroup.WithContext(ctx)
|
eg, _ := errgroup.WithContext(ctx)
|
||||||
for _, container := range containers {
|
for _, container := range containers {
|
||||||
toDelete := container
|
container := container
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
eventName := getContainerProgressName(toDelete)
|
eventName := getContainerProgressName(container)
|
||||||
w.Event(progress.StoppingEvent(eventName))
|
w.Event(progress.StoppingEvent(eventName))
|
||||||
err := s.stopContainers(ctx, w, []moby.Container{toDelete}, timeout)
|
err := s.stopContainers(ctx, w, []moby.Container{container}, timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.Event(progress.ErrorMessageEvent(eventName, "Error while Stopping"))
|
w.Event(progress.ErrorMessageEvent(eventName, "Error while Stopping"))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
w.Event(progress.RemovingEvent(eventName))
|
w.Event(progress.RemovingEvent(eventName))
|
||||||
err = s.apiClient.ContainerRemove(ctx, toDelete.ID, moby.ContainerRemoveOptions{
|
err = s.apiClient.ContainerRemove(ctx, container.ID, moby.ContainerRemoveOptions{
|
||||||
Force: true,
|
Force: true,
|
||||||
RemoveVolumes: volumes,
|
RemoveVolumes: volumes,
|
||||||
})
|
})
|
||||||
|
@ -29,20 +29,20 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (s *composeService) Logs(ctx context.Context, projectName string, consumer api.LogConsumer, options api.LogOptions) error {
|
func (s *composeService) Logs(ctx context.Context, projectName string, consumer api.LogConsumer, options api.LogOptions) error {
|
||||||
list, err := s.getContainers(ctx, projectName, oneOffExclude, true, options.Services...)
|
containers, err := s.getContainers(ctx, projectName, oneOffExclude, true, options.Services...)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
eg, ctx := errgroup.WithContext(ctx)
|
eg, ctx := errgroup.WithContext(ctx)
|
||||||
for _, c := range list {
|
for _, c := range containers {
|
||||||
c := c
|
|
||||||
service := c.Labels[api.ServiceLabel]
|
service := c.Labels[api.ServiceLabel]
|
||||||
container, err := s.apiClient.ContainerInspect(ctx, c.ID)
|
container, err := s.apiClient.ContainerInspect(ctx, c.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name := getContainerNameWithoutProject(c)
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
r, err := s.apiClient.ContainerLogs(ctx, container.ID, types.ContainerLogsOptions{
|
r, err := s.apiClient.ContainerLogs(ctx, container.ID, types.ContainerLogsOptions{
|
||||||
ShowStdout: true,
|
ShowStdout: true,
|
||||||
@ -58,7 +58,6 @@ func (s *composeService) Logs(ctx context.Context, projectName string, consumer
|
|||||||
}
|
}
|
||||||
defer r.Close() // nolint errcheck
|
defer r.Close() // nolint errcheck
|
||||||
|
|
||||||
name := getContainerNameWithoutProject(c)
|
|
||||||
w := utils.GetWriter(func(line string) {
|
w := utils.GetWriter(func(line string) {
|
||||||
consumer.Log(name, service, line)
|
consumer.Log(name, service, line)
|
||||||
})
|
})
|
||||||
|
@ -38,9 +38,8 @@ func (s *composeService) Ps(ctx context.Context, projectName string, options api
|
|||||||
|
|
||||||
summary := make([]api.ContainerSummary, len(containers))
|
summary := make([]api.ContainerSummary, len(containers))
|
||||||
eg, ctx := errgroup.WithContext(ctx)
|
eg, ctx := errgroup.WithContext(ctx)
|
||||||
for i, c := range containers {
|
for i, container := range containers {
|
||||||
container := c
|
i, container := i, container
|
||||||
i := i
|
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
var publishers []api.PortPublisher
|
var publishers []api.PortPublisher
|
||||||
sort.Slice(container.Ports, func(i, j int) bool {
|
sort.Slice(container.Ports, func(i, j int) bool {
|
||||||
|
@ -58,8 +58,8 @@ func (s *composeService) pull(ctx context.Context, project *types.Project, opts
|
|||||||
w := progress.ContextWriter(ctx)
|
w := progress.ContextWriter(ctx)
|
||||||
eg, ctx := errgroup.WithContext(ctx)
|
eg, ctx := errgroup.WithContext(ctx)
|
||||||
|
|
||||||
for _, srv := range project.Services {
|
for _, service := range project.Services {
|
||||||
service := srv
|
service := service
|
||||||
if service.Image == "" {
|
if service.Image == "" {
|
||||||
w.Event(progress.Event{
|
w.Event(progress.Event{
|
||||||
ID: service.Name,
|
ID: service.Name,
|
||||||
|
@ -74,12 +74,12 @@ func (s *composeService) Remove(ctx context.Context, project *types.Project, opt
|
|||||||
func (s *composeService) remove(ctx context.Context, containers Containers, options api.RemoveOptions) error {
|
func (s *composeService) remove(ctx context.Context, containers Containers, options api.RemoveOptions) error {
|
||||||
w := progress.ContextWriter(ctx)
|
w := progress.ContextWriter(ctx)
|
||||||
eg, ctx := errgroup.WithContext(ctx)
|
eg, ctx := errgroup.WithContext(ctx)
|
||||||
for _, c := range containers {
|
for _, container := range containers {
|
||||||
c := c
|
container := container
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
eventName := getContainerProgressName(c)
|
eventName := getContainerProgressName(container)
|
||||||
w.Event(progress.RemovingEvent(eventName))
|
w.Event(progress.RemovingEvent(eventName))
|
||||||
err := s.apiClient.ContainerRemove(ctx, c.ID, moby.ContainerRemoveOptions{
|
err := s.apiClient.ContainerRemove(ctx, container.ID, moby.ContainerRemoveOptions{
|
||||||
RemoveVolumes: options.Volumes,
|
RemoveVolumes: options.Volumes,
|
||||||
Force: options.Force,
|
Force: options.Force,
|
||||||
})
|
})
|
||||||
|
@ -49,8 +49,8 @@ func (s *composeService) restart(ctx context.Context, project *types.Project, op
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
eg, ctx := errgroup.WithContext(ctx)
|
eg, ctx := errgroup.WithContext(ctx)
|
||||||
for _, c := range observedState.filter(isService(service)) {
|
for _, container := range observedState.filter(isService(service)) {
|
||||||
container := c
|
container := container
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
eventName := getContainerProgressName(container)
|
eventName := getContainerProgressName(container)
|
||||||
w.Event(progress.RestartingEvent(eventName))
|
w.Event(progress.RestartingEvent(eventName))
|
||||||
|
@ -34,9 +34,8 @@ func (s *composeService) Top(ctx context.Context, projectName string, services [
|
|||||||
}
|
}
|
||||||
summary := make([]api.ContainerProcSummary, len(containers))
|
summary := make([]api.ContainerProcSummary, len(containers))
|
||||||
eg, ctx := errgroup.WithContext(ctx)
|
eg, ctx := errgroup.WithContext(ctx)
|
||||||
for i, c := range containers {
|
for i, container := range containers {
|
||||||
container := c
|
i, container := i, container
|
||||||
i := i
|
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
topContent, err := s.apiClient.ContainerTop(ctx, container.ID, []string{})
|
topContent, err := s.apiClient.ContainerTop(ctx, container.ID, []string{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user