mirror of
https://github.com/offen/docker-volume-backup.git
synced 2025-12-05 09:08:02 +01:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
baf34ec1f7 | ||
|
|
e8562b1785 | ||
|
|
5d7451410b | ||
|
|
440bcf76ce | ||
|
|
2d3e79cf5e | ||
|
|
5abfe5bb39 | ||
|
|
6c8b0ccce5 | ||
|
|
f4c61125af | ||
|
|
9b768c71e6 |
@@ -1,5 +1,5 @@
|
||||
<a href="https://www.offen.dev/">
|
||||
<img src="https://offen.github.io/press-kit/offen-material/gfx-GitHub-Offen-logo.svg" alt="Offen logo" title="Offen" width="150px"/>
|
||||
<a href="https://www.offen.software/">
|
||||
<img src="https://offen.github.io/press-kit/avatars/avatar-OS-header.svg" alt="offen.software logo" title="offen.software" width="60px"/>
|
||||
</a>
|
||||
|
||||
# docker-volume-backup
|
||||
|
||||
@@ -72,6 +72,7 @@ type Config struct {
|
||||
LockTimeout time.Duration `split_words:"true" default:"60m"`
|
||||
AzureStorageAccountName string `split_words:"true"`
|
||||
AzureStoragePrimaryAccountKey string `split_words:"true"`
|
||||
AzureStorageConnectionString string `split_words:"true"`
|
||||
AzureStorageContainerName string `split_words:"true"`
|
||||
AzureStoragePath string `split_words:"true"`
|
||||
AzureStorageEndpoint string `split_words:"true" default:"https://{{ .AccountName }}.blob.core.windows.net/"`
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/offen/docker-volume-backup/internal/errwrap"
|
||||
@@ -136,6 +137,10 @@ func source(path string) (map[string]string, error) {
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
withExpansion, err := shell.Expand(line, nil)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrap(err, "error expanding env")
|
||||
|
||||
@@ -49,6 +49,15 @@ func TestSource(t *testing.T) {
|
||||
"QUX": "yyy",
|
||||
},
|
||||
},
|
||||
{
|
||||
"comments",
|
||||
"testdata/comments.env",
|
||||
false,
|
||||
map[string]string{
|
||||
"BAR": "xxx",
|
||||
"BAZ": "yyy",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
os.Setenv("QUX", "yyy")
|
||||
|
||||
@@ -45,15 +45,23 @@ func (s *script) exec(containerRef string, command string, user string) ([]byte,
|
||||
}
|
||||
defer resp.Close()
|
||||
|
||||
var outBuf, errBuf bytes.Buffer
|
||||
var outBuf, errBuf, fullRespBuf bytes.Buffer
|
||||
outputDone := make(chan error)
|
||||
|
||||
tee := io.TeeReader(resp.Reader, &fullRespBuf)
|
||||
|
||||
go func() {
|
||||
_, err := stdcopy.StdCopy(&outBuf, &errBuf, resp.Reader)
|
||||
_, err := stdcopy.StdCopy(&outBuf, &errBuf, tee)
|
||||
outputDone <- err
|
||||
}()
|
||||
|
||||
if err := <-outputDone; err != nil {
|
||||
if body, bErr := io.ReadAll(&fullRespBuf); bErr == nil {
|
||||
// if possible, try to append the exec output to the error
|
||||
// as it's likely to be more relevant for users than the error from
|
||||
// calling stdcopy.Copy
|
||||
err = errwrap.Wrap(errors.New(string(body)), err.Error())
|
||||
}
|
||||
return nil, nil, errwrap.Wrap(err, "error demultiplexing output")
|
||||
}
|
||||
|
||||
|
||||
@@ -193,6 +193,7 @@ func (s *script) init() error {
|
||||
PrimaryAccountKey: s.c.AzureStoragePrimaryAccountKey,
|
||||
Endpoint: s.c.AzureStorageEndpoint,
|
||||
RemotePath: s.c.AzureStoragePath,
|
||||
ConnectionString: s.c.AzureStorageConnectionString,
|
||||
}
|
||||
azureBackend, err := azure.NewStorageBackend(azureConfig, logFunc)
|
||||
if err != nil {
|
||||
|
||||
@@ -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 != "" {
|
||||
|
||||
85
cmd/backup/stop_restart_test.go
Normal file
85
cmd/backup/stop_restart_test.go
Normal file
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
7
cmd/backup/testdata/comments.env
vendored
Normal file
7
cmd/backup/testdata/comments.env
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# This is a comment about `why` things are here
|
||||
# FOO="${bar:-qux}"
|
||||
# e.g. `backup-$HOSTNAME-%Y-%m-%dT%H-%M-%S.tar.gz`. Expansion happens before`
|
||||
|
||||
BAR=xxx
|
||||
|
||||
BAZ=$QUX
|
||||
@@ -46,6 +46,10 @@ If you have more than one `docker-volume-backup` container (possibly across seve
|
||||
multiple backup schedules, you will need to use `EXEC_LABEL` in the configuration and a `docker-volume-backup.exec-label` label on each
|
||||
container using custom commands to ensure that the commands are only run by the correct `docker-volume-backup` instance.
|
||||
|
||||
{: .important }
|
||||
In case you use `EXEC_LABEL` together with configuration mounted from `conf.d` it's important to understand that a distinct `EXEC_LABEL` __should be set in each configuration__.
|
||||
Else, schedules that do not specify an `EXEC_LABEL` will still trigger commands on all containers with such labels, no matter whether they specify `docker-volume-backup.exec-label` or not.
|
||||
|
||||
```yml
|
||||
version: '3'
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ docker run --rm \
|
||||
|
||||
Alternatively, pass a `--env-file` in order to use a full config as described below.
|
||||
|
||||
### Available image registries
|
||||
## Available image registries
|
||||
|
||||
This Docker image is published to both Docker Hub and the GitHub container registry.
|
||||
Depending on your preferences and needs, you can reference both `offen/docker-volume-backup` as well as `ghcr.io/offen/docker-volume-backup`:
|
||||
@@ -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:
|
||||
|
||||
@@ -245,10 +245,17 @@ You can populate below template according to your requirements and use it as you
|
||||
# AZURE_STORAGE_ACCOUNT_NAME="account-name"
|
||||
|
||||
# The credential's primary account key when using Azure Blob Storage. If this
|
||||
# is not given, the command tries to fall back to using a managed identity.
|
||||
# is not given, the command tries to fall back to using a connection string
|
||||
# (if given) or a managed identity (if nothing is given).
|
||||
|
||||
# AZURE_STORAGE_PRIMARY_ACCOUNT_KEY="<xxx>"
|
||||
|
||||
# A connection string for accessing Azure Blob Storage. If this
|
||||
# is not given, the command tries to fall back to using a primary account key
|
||||
# (if given) or a managed identity (if nothing is given).
|
||||
|
||||
# AZURE_STORAGE_CONNECTION_STRING="<xxx>"
|
||||
|
||||
# The container name when using Azure Blob Storage.
|
||||
|
||||
# AZURE_STORAGE_CONTAINER_NAME="container-name"
|
||||
|
||||
10
go.mod
10
go.mod
@@ -11,9 +11,9 @@ require (
|
||||
github.com/docker/docker v24.0.7+incompatible
|
||||
github.com/gofrs/flock v0.8.1
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/klauspost/compress v1.17.6
|
||||
github.com/klauspost/compress v1.17.7
|
||||
github.com/leekchan/timeutil v0.0.0-20150802142658-28917288c48d
|
||||
github.com/minio/minio-go/v7 v7.0.67
|
||||
github.com/minio/minio-go/v7 v7.0.68
|
||||
github.com/offen/envconfig v1.5.0
|
||||
github.com/otiai10/copy v1.14.0
|
||||
github.com/pkg/sftp v1.13.6
|
||||
@@ -22,6 +22,7 @@ require (
|
||||
golang.org/x/crypto v0.19.0
|
||||
golang.org/x/oauth2 v0.17.0
|
||||
golang.org/x/sync v0.6.0
|
||||
mvdan.cc/sh/v3 v3.8.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -32,7 +33,6 @@ require (
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
mvdan.cc/sh/v3 v3.8.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -40,7 +40,7 @@ require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 // indirect
|
||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.0-alpha.0
|
||||
github.com/ProtonMail/go-crypto v1.1.0-alpha.1
|
||||
github.com/docker/distribution v2.8.2+incompatible // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
@@ -48,7 +48,7 @@ require (
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/uuid v1.5.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
||||
github.com/klauspost/pgzip v1.2.6
|
||||
|
||||
25
go.sum
25
go.sum
@@ -201,8 +201,8 @@ github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3
|
||||
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/ProtonMail/go-crypto v1.1.0-alpha.0 h1:nHGfwXmFvJrSR9xu8qL7BkO4DqTHXE9N5vPhgY2I+j0=
|
||||
github.com/ProtonMail/go-crypto v1.1.0-alpha.0/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/ProtonMail/go-crypto v1.1.0-alpha.1 h1:iKLDnKGL+3u4Q5OjYgixAxWdkkGBPidCQumqVryUgtY=
|
||||
github.com/ProtonMail/go-crypto v1.1.0-alpha.1/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
@@ -283,6 +283,8 @@ github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
@@ -358,8 +360,9 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
@@ -384,8 +387,8 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
|
||||
@@ -458,8 +461,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI=
|
||||
github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
|
||||
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
@@ -474,6 +477,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@@ -504,8 +509,8 @@ github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKju
|
||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||
github.com/minio/minio-go/v7 v7.0.67 h1:BeBvZWAS+kRJm1vGTMJYVjKUNoo0FoEt/wUWdUtfmh8=
|
||||
github.com/minio/minio-go/v7 v7.0.67/go.mod h1:+UXocnUeZ3wHvVh5s95gcrA4YjMIbccT6ubB+1m054A=
|
||||
github.com/minio/minio-go/v7 v7.0.68 h1:hTqSIfLlpXaKuNy4baAp4Jjy2sqZEN9hRxD0M4aOfrQ=
|
||||
github.com/minio/minio-go/v7 v7.0.68/go.mod h1:XAvOPJQ5Xlzk5o3o/ArO2NMbhSGkimC+bpW/ngRKDmQ=
|
||||
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
|
||||
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
@@ -600,6 +605,8 @@ github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzG
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
|
||||
@@ -33,12 +33,17 @@ type Config struct {
|
||||
AccountName string
|
||||
ContainerName string
|
||||
PrimaryAccountKey string
|
||||
ConnectionString string
|
||||
Endpoint string
|
||||
RemotePath string
|
||||
}
|
||||
|
||||
// NewStorageBackend creates and initializes a new Azure Blob Storage backend.
|
||||
func NewStorageBackend(opts Config, logFunc storage.Log) (storage.Backend, error) {
|
||||
if opts.PrimaryAccountKey != "" && opts.ConnectionString != "" {
|
||||
return nil, errwrap.Wrap(nil, "using primary account key and connection string are mutually exclusive")
|
||||
}
|
||||
|
||||
endpointTemplate, err := template.New("endpoint").Parse(opts.Endpoint)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrap(err, "error parsing endpoint template")
|
||||
@@ -58,7 +63,12 @@ func NewStorageBackend(opts Config, logFunc storage.Log) (storage.Backend, error
|
||||
|
||||
client, err = azblob.NewClientWithSharedKeyCredential(normalizedEndpoint, cred, nil)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrap(err, "error creating Azure client")
|
||||
return nil, errwrap.Wrap(err, "error creating azure client from primary account key")
|
||||
}
|
||||
} else if opts.ConnectionString != "" {
|
||||
client, err = azblob.NewClientFromConnectionString(opts.ConnectionString, nil)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrap(err, "error creating azure client from connection string")
|
||||
}
|
||||
} else {
|
||||
cred, err := azidentity.NewManagedIdentityCredential(nil)
|
||||
@@ -67,7 +77,7 @@ func NewStorageBackend(opts Config, logFunc storage.Log) (storage.Backend, error
|
||||
}
|
||||
client, err = azblob.NewClient(normalizedEndpoint, cred, nil)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrap(err, "error creating Azure client")
|
||||
return nil, errwrap.Wrap(err, "error creating azure client from managed identity")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
# This is a comment
|
||||
# NOT=$(docker ps -aq)
|
||||
# e.g. `backup-$HOSTNAME-%Y-%m-%dT%H-%M-%S.tar.gz`. Expansion happens before`
|
||||
|
||||
NAME="$EXPANSION_VALUE"
|
||||
BACKUP_CRON_EXPRESSION="*/1 * * * *"
|
||||
|
||||
Reference in New Issue
Block a user