|
@@ -63,6 +63,14 @@ func (s *composeService) start(ctx context.Context, projectName string, options
|
|
|
return s.watchContainers(context.Background(), project.Name, options.AttachTo, options.Services, listener, attached,
|
|
|
func(container moby.Container, _ time.Time) error {
|
|
|
return s.attachContainer(ctx, container, listener)
|
|
|
+ }, func(container moby.Container, _ time.Time) error {
|
|
|
+ listener(api.ContainerEvent{
|
|
|
+ Type: api.ContainerEventAttach,
|
|
|
+ Container: "", // actual name will be set by start event
|
|
|
+ ID: container.ID,
|
|
|
+ Service: container.Labels[api.ServiceLabel],
|
|
|
+ })
|
|
|
+ return nil
|
|
|
})
|
|
|
})
|
|
|
}
|
|
@@ -114,7 +122,7 @@ type containerWatchFn func(container moby.Container, t time.Time) error
|
|
|
// watchContainers uses engine events to capture container start/die and notify ContainerEventListener
|
|
|
func (s *composeService) watchContainers(ctx context.Context, //nolint:gocyclo
|
|
|
projectName string, services, required []string,
|
|
|
- listener api.ContainerEventListener, containers Containers, onStart containerWatchFn) error {
|
|
|
+ listener api.ContainerEventListener, containers Containers, onStart, onRecreate containerWatchFn) error {
|
|
|
if len(containers) == 0 {
|
|
|
return nil
|
|
|
}
|
|
@@ -123,12 +131,13 @@ func (s *composeService) watchContainers(ctx context.Context, //nolint:gocyclo
|
|
|
}
|
|
|
|
|
|
var (
|
|
|
- expected Containers
|
|
|
+ expected []string
|
|
|
watched = map[string]int{}
|
|
|
+ replaced []string
|
|
|
)
|
|
|
for _, c := range containers {
|
|
|
if utils.Contains(required, c.Labels[api.ServiceLabel]) {
|
|
|
- expected = append(expected, c)
|
|
|
+ expected = append(expected, c.ID)
|
|
|
}
|
|
|
watched[c.ID] = 0
|
|
|
}
|
|
@@ -157,23 +166,38 @@ func (s *composeService) watchContainers(ctx context.Context, //nolint:gocyclo
|
|
|
service := container.Labels[api.ServiceLabel]
|
|
|
switch event.Status {
|
|
|
case "stop":
|
|
|
- listener(api.ContainerEvent{
|
|
|
- Type: api.ContainerEventStopped,
|
|
|
- Container: name,
|
|
|
- Service: service,
|
|
|
- })
|
|
|
+ if _, ok := watched[container.ID]; ok {
|
|
|
+ eType := api.ContainerEventStopped
|
|
|
+ if utils.Contains(replaced, container.ID) {
|
|
|
+ utils.Remove(replaced, container.ID)
|
|
|
+ eType = api.ContainerEventRecreated
|
|
|
+ }
|
|
|
+ listener(api.ContainerEvent{
|
|
|
+ Type: eType,
|
|
|
+ Container: name,
|
|
|
+ ID: container.ID,
|
|
|
+ Service: service,
|
|
|
+ })
|
|
|
+ }
|
|
|
|
|
|
delete(watched, container.ID)
|
|
|
- expected = expected.remove(container.ID)
|
|
|
+ expected = utils.Remove(expected, container.ID)
|
|
|
case "die":
|
|
|
restarted := watched[container.ID]
|
|
|
watched[container.ID] = restarted + 1
|
|
|
// Container terminated.
|
|
|
willRestart := inspected.State.Restarting
|
|
|
|
|
|
+ eType := api.ContainerEventExit
|
|
|
+ if utils.Contains(replaced, container.ID) {
|
|
|
+ utils.Remove(replaced, container.ID)
|
|
|
+ eType = api.ContainerEventRecreated
|
|
|
+ }
|
|
|
+
|
|
|
listener(api.ContainerEvent{
|
|
|
- Type: api.ContainerEventExit,
|
|
|
+ Type: eType,
|
|
|
Container: name,
|
|
|
+ ID: container.ID,
|
|
|
Service: service,
|
|
|
ExitCode: inspected.State.ExitCode,
|
|
|
Restarting: willRestart,
|
|
@@ -182,7 +206,7 @@ func (s *composeService) watchContainers(ctx context.Context, //nolint:gocyclo
|
|
|
if !willRestart {
|
|
|
// we're done with this one
|
|
|
delete(watched, container.ID)
|
|
|
- expected = expected.remove(container.ID)
|
|
|
+ expected = utils.Remove(expected, container.ID)
|
|
|
}
|
|
|
case "start":
|
|
|
count, ok := watched[container.ID]
|
|
@@ -190,7 +214,7 @@ func (s *composeService) watchContainers(ctx context.Context, //nolint:gocyclo
|
|
|
if !ok {
|
|
|
// A new container has just been added to service by scale
|
|
|
watched[container.ID] = 0
|
|
|
- expected = append(expected, container)
|
|
|
+ expected = append(expected, container.ID)
|
|
|
mustAttach = true
|
|
|
}
|
|
|
if mustAttach {
|
|
@@ -200,6 +224,21 @@ func (s *composeService) watchContainers(ctx context.Context, //nolint:gocyclo
|
|
|
return err
|
|
|
}
|
|
|
}
|
|
|
+ case "create":
|
|
|
+ if id, ok := container.Labels[api.ContainerReplaceLabel]; ok {
|
|
|
+ replaced = append(replaced, id)
|
|
|
+ err = onRecreate(container, event.Timestamp)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if utils.StringContains(expected, id) {
|
|
|
+ expected = append(expected, inspected.ID)
|
|
|
+ }
|
|
|
+ watched[container.ID] = 1
|
|
|
+ if utils.Contains(expected, id) {
|
|
|
+ expected = append(expected, container.ID)
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
if len(expected) == 0 {
|
|
|
stop()
|