Add Azure Blob Storage replica type

This commit is contained in:
Ben Johnson
2021-05-23 07:56:32 -06:00
parent ac32e8e089
commit 84dc68c09c
7 changed files with 684 additions and 3 deletions

View File

@@ -19,6 +19,7 @@ import (
"time"
"github.com/benbjohnson/litestream"
"github.com/benbjohnson/litestream/abs"
"github.com/benbjohnson/litestream/file"
"github.com/benbjohnson/litestream/gcs"
"github.com/benbjohnson/litestream/s3"
@@ -292,6 +293,10 @@ type ReplicaConfig struct {
Endpoint string `yaml:"endpoint"`
ForcePathStyle *bool `yaml:"force-path-style"`
SkipVerify bool `yaml:"skip-verify"`
// ABS settings
AccountName string `yaml:"account-name"`
AccountKey string `yaml:"account-key"`
}
// NewReplicaFromConfig instantiates a replica for a DB based on a config.
@@ -335,6 +340,10 @@ func NewReplicaFromConfig(c *ReplicaConfig, db *litestream.DB) (_ *litestream.Re
if r.Client, err = newGCSReplicaClientFromConfig(c, r); err != nil {
return nil, err
}
case "abs":
if r.Client, err = newABSReplicaClientFromConfig(c, r); err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unknown replica type in config: %q", c.Type)
}
@@ -475,6 +484,48 @@ func newGCSReplicaClientFromConfig(c *ReplicaConfig, r *litestream.Replica) (_ *
return client, nil
}
// newABSReplicaClientFromConfig returns a new instance of abs.ReplicaClient built from config.
func newABSReplicaClientFromConfig(c *ReplicaConfig, r *litestream.Replica) (_ *abs.ReplicaClient, err error) {
// Ensure URL & constituent parts are not both specified.
if c.URL != "" && c.Path != "" {
return nil, fmt.Errorf("cannot specify url & path for abs replica")
} else if c.URL != "" && c.Bucket != "" {
return nil, fmt.Errorf("cannot specify url & bucket for abs replica")
}
bucket, path := c.Bucket, c.Path
// Apply settings from URL, if specified.
if c.URL != "" {
_, uhost, upath, err := ParseReplicaURL(c.URL)
if err != nil {
return nil, err
}
// Only apply URL parts to field that have not been overridden.
if path == "" {
path = upath
}
if bucket == "" {
bucket = uhost
}
}
// Ensure required settings are set.
if bucket == "" {
return nil, fmt.Errorf("bucket required for abs replica")
}
// Build replica.
client := abs.NewReplicaClient()
client.AccountName = c.AccountName
client.AccountKey = c.AccountKey
client.Bucket = bucket
client.Path = path
client.Endpoint = c.Endpoint
return client, nil
}
// applyLitestreamEnv copies "LITESTREAM" prefixed environment variables to
// their AWS counterparts as the "AWS" prefix can be confusing when using a
// non-AWS S3-compatible service.

View File

@@ -11,6 +11,7 @@ import (
"os"
"github.com/benbjohnson/litestream"
"github.com/benbjohnson/litestream/abs"
"github.com/benbjohnson/litestream/file"
"github.com/benbjohnson/litestream/gcs"
"github.com/benbjohnson/litestream/s3"
@@ -111,6 +112,8 @@ func (c *ReplicateCommand) Run(ctx context.Context) (err error) {
log.Printf("replicating to: name=%q type=%q bucket=%q path=%q region=%q endpoint=%q sync-interval=%s", r.Name(), client.Type(), client.Bucket, client.Path, client.Region, client.Endpoint, r.SyncInterval)
case *gcs.ReplicaClient:
log.Printf("replicating to: name=%q type=%q bucket=%q path=%q sync-interval=%s", r.Name(), client.Type(), client.Bucket, client.Path, r.SyncInterval)
case *abs.ReplicaClient:
log.Printf("replicating to: name=%q type=%q bucket=%q path=%q endpoint=%q sync-interval=%s", r.Name(), client.Type(), client.Bucket, client.Path, client.Endpoint, r.SyncInterval)
default:
log.Printf("replicating to: name=%q type=%q", r.Name(), client.Type())
}