diff --git a/cmd/backup/script.go b/cmd/backup/script.go index 3d66aac..a5535e1 100644 --- a/cmd/backup/script.go +++ b/cmd/backup/script.go @@ -326,6 +326,12 @@ func (s *script) stopContainersAndServices() (func() error, error) { return noop, nil } + dockerInfo, err := s.cli.Info(context.Background()) + if err != nil { + return noop, fmt.Errorf("stopContainers: error getting docker info: %w", err) + } + isDockerSwarm := dockerInfo.Swarm.LocalNodeState != "inactive" + matchLabel := fmt.Sprintf( "docker-volume-backup.stop-during-backup=%s", s.c.BackupStopContainerLabel, @@ -345,18 +351,22 @@ func (s *script) stopContainersAndServices() (func() error, error) { return noop, fmt.Errorf("stopContainers: error querying for containers to stop: %w", err) } - allServices, err := s.cli.ServiceList(context.Background(), types.ServiceListOptions{}) - if err != nil { - return noop, fmt.Errorf("stopContainers: error querying for services: %w", err) - } - servicesToScaleDown, err := s.cli.ServiceList(context.Background(), types.ServiceListOptions{ - Filters: filters.NewArgs(filters.KeyValuePair{ - Key: "label", - Value: matchLabel, - }), - }) - if err != nil { - return noop, fmt.Errorf("stopContainers: error querying for services to scale down: %w", err) + var allServices []swarm.Service + var servicesToScaleDown []swarm.Service + if isDockerSwarm { + allServices, err = s.cli.ServiceList(context.Background(), types.ServiceListOptions{}) + if err != nil { + return noop, fmt.Errorf("stopContainers: error querying for services: %w", err) + } + servicesToScaleDown, err = s.cli.ServiceList(context.Background(), types.ServiceListOptions{ + Filters: filters.NewArgs(filters.KeyValuePair{ + Key: "label", + Value: matchLabel, + }), + }) + if err != nil { + return noop, fmt.Errorf("stopContainers: error querying for services to scale down: %w", err) + } } if len(containersToStop) == 0 && len(servicesToScaleDown) == 0 { @@ -393,10 +403,33 @@ func (s *script) stopContainersAndServices() (func() error, error) { ) } + var scaledDownServices []swarm.Service + var scaleDownErrors []error + if isDockerSwarm { + for _, service := range servicesToScaleDown { + var zero uint64 + service.Spec.Mode.Replicated.Replicas = &zero + service.Spec.TaskTemplate.ForceUpdate += 1 + if _, err := s.cli.ServiceUpdate(context.Background(), service.ID, service.Version, service.Spec, types.ServiceUpdateOptions{}); err != nil { + scaleDownErrors = append(scaleDownErrors, err) + } else { + scaledDownServices = append(scaledDownServices, service) + } + } + } + s.stats.Containers = ContainersStats{ - All: uint(len(allContainers)), - ToStop: uint(len(containersToStop)), - Stopped: uint(len(stoppedContainers)), + All: uint(len(allContainers)), + ToStop: uint(len(containersToStop)), + Stopped: uint(len(stoppedContainers)), + StopErrors: uint(len(stopErrors)), + } + + s.stats.Services = ServicesStats{ + All: uint(len(allServices)), + ToScaleDown: uint(len(servicesToScaleDown)), + ScaledDown: uint(len(scaledDownServices)), + ScaleDownErrors: uint(len(scaleDownErrors)), } return func() error { diff --git a/cmd/backup/stats.go b/cmd/backup/stats.go index 4eed0d9..9728e94 100644 --- a/cmd/backup/stats.go +++ b/cmd/backup/stats.go @@ -17,6 +17,15 @@ type ContainersStats struct { StopErrors uint } +// ServicesStats contains info about Swarm services that have been +// operated upon +type ServicesStats struct { + All uint + ToScaleDown uint + ScaledDown uint + ScaleDownErrors uint +} + // BackupFileStats stats about the created backup file type BackupFileStats struct { Name string @@ -40,6 +49,7 @@ type Stats struct { LockedTime time.Duration LogOutput *bytes.Buffer Containers ContainersStats + Services ServicesStats BackupFile BackupFileStats Storages map[string]StorageStats }