diff --git a/cmd/backup/stop_restart.go b/cmd/backup/stop_restart.go index 73af5d2c..0baae201 100644 --- a/cmd/backup/stop_restart.go +++ b/cmd/backup/stop_restart.go @@ -81,6 +81,16 @@ func awaitContainerCountForService(cli *client.Client, serviceID string, count i } } +func isSwarm(c interface { + Info(context.Context) (types.Info, error) +}) (bool, error) { + info, err := c.Info(context.Background()) + if err != nil { + return false, errwrap.Wrap(err, "error getting docker info") + } + return info.Swarm.LocalNodeState != "" && info.Swarm.LocalNodeState != swarm.LocalNodeStateInactive, nil +} + // stopContainersAndServices stops all Docker containers that are marked as to being // stopped during the backup and returns a function that can be called to // restart everything that has been stopped. @@ -89,11 +99,10 @@ func (s *script) stopContainersAndServices() (func() error, error) { return noop, nil } - dockerInfo, err := s.cli.Info(context.Background()) + isDockerSwarm, err := isSwarm(s.cli) if err != nil { - return noop, errwrap.Wrap(err, "error getting docker info") + return noop, errwrap.Wrap(err, "error determining swarm state") } - isDockerSwarm := dockerInfo.Swarm.LocalNodeState != "inactive" labelValue := s.c.BackupStopDuringBackupLabel if s.c.BackupStopContainerLabel != "" { diff --git a/cmd/backup/stop_restart_test.go b/cmd/backup/stop_restart_test.go new file mode 100644 index 00000000..ff866b31 --- /dev/null +++ b/cmd/backup/stop_restart_test.go @@ -0,0 +1,85 @@ +package main + +import ( + "context" + "errors" + "testing" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/swarm" +) + +type mockInfoClient struct { + result types.Info + err error +} + +func (m *mockInfoClient) Info(context.Context) (types.Info, error) { + return m.result, m.err +} + +func TestIsSwarm(t *testing.T) { + tests := []struct { + name string + client *mockInfoClient + expected bool + expectError bool + }{ + { + "swarm", + &mockInfoClient{ + result: types.Info{ + Swarm: swarm.Info{ + LocalNodeState: swarm.LocalNodeStateActive, + }, + }, + }, + true, + false, + }, + { + "compose", + &mockInfoClient{ + result: types.Info{ + Swarm: swarm.Info{ + LocalNodeState: swarm.LocalNodeStateInactive, + }, + }, + }, + false, + false, + }, + { + "balena", + &mockInfoClient{ + result: types.Info{ + Swarm: swarm.Info{ + LocalNodeState: "", + }, + }, + }, + false, + false, + }, + { + "error", + &mockInfoClient{ + err: errors.New("the dinosaurs escaped"), + }, + false, + true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result, err := isSwarm(test.client) + if (err != nil) != test.expectError { + t.Errorf("Unexpected error value %v", err) + } + if test.expected != result { + t.Errorf("Expected %v, got %v", test.expected, result) + } + }) + } +} diff --git a/docs/index.md b/docs/index.md index 90c43c03..83272659 100644 --- a/docs/index.md +++ b/docs/index.md @@ -100,6 +100,11 @@ docker pull ghcr.io/offen/docker-volume-backup:v2 Documentation references Docker Hub, but all examples will work using ghcr.io just as well. +### Supported Engines + +This tool is developed and tested against the Docker CE engine exclusively. +While it may work against different implementations (e.g. Balena Engine), there are no guarantees about support for non-Docker engines. + ## Differences to `jareware/docker-volume-backup` This image is heavily inspired by `jareware/docker-volume-backup`. We decided to publish this image as a simpler and more lightweight alternative because of the following requirements: