Skip to content

Commit

Permalink
Swarm mode check fails on non-standard Info responses (#376)
Browse files Browse the repository at this point in the history
* Swarm mode check fails on non-standard Info responses

* Add unit test

* Remove balena tests, add note to docs
  • Loading branch information
m90 authored Feb 27, 2024
1 parent 6c8b0cc commit 5abfe5b
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 3 deletions.
15 changes: 12 additions & 3 deletions cmd/backup/stop_restart.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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 != "" {
Expand Down
85 changes: 85 additions & 0 deletions cmd/backup/stop_restart_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
})
}
}
5 changes: 5 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down

0 comments on commit 5abfe5b

Please sign in to comment.