Commit 49073cd2 authored by Brian Downs's avatar Brian Downs

add timeouts around s3 operations

parent 78067d4d
package cmds package cmds
import ( import (
"errors"
"fmt" "fmt"
"os" "os"
"runtime" "runtime"
...@@ -20,6 +21,8 @@ var ( ...@@ -20,6 +21,8 @@ var (
} }
) )
var ErrCommandNoArgs = errors.New("this command does not take any arguments")
func init() { func init() {
// hack - force "file,dns" lookup order if go dns is used // hack - force "file,dns" lookup order if go dns is used
if os.Getenv("RES_OPTIONS") == "" { if os.Getenv("RES_OPTIONS") == "" {
......
...@@ -18,21 +18,21 @@ import ( ...@@ -18,21 +18,21 @@ import (
// commandSetup setups up common things needed // commandSetup setups up common things needed
// for each etcd command. // for each etcd command.
func commandSetup(app *cli.Context) error { func commandSetup(app *cli.Context, cfg *cmds.Server) (string, error) {
gspt.SetProcTitle(os.Args[0]) gspt.SetProcTitle(os.Args[0])
nodeName := app.String("node-name") nodeName := app.String("node-name")
if nodeName == "" { if nodeName == "" {
h, err := os.Hostname() h, err := os.Hostname()
if err != nil { if err != nil {
return err return "", err
} }
nodeName = h nodeName = h
} }
os.Setenv("NODE_NAME", nodeName) os.Setenv("NODE_NAME", nodeName)
return nil return server.ResolveDataDir(cfg.DataDir)
} }
func Run(app *cli.Context) error { func Run(app *cli.Context) error {
...@@ -43,17 +43,13 @@ func Run(app *cli.Context) error { ...@@ -43,17 +43,13 @@ func Run(app *cli.Context) error {
} }
func run(app *cli.Context, cfg *cmds.Server) error { func run(app *cli.Context, cfg *cmds.Server) error {
if err := commandSetup(app); err != nil { dataDir, err := commandSetup(app, cfg)
if err != nil {
return err return err
} }
if len(app.Args()) > 0 { if len(app.Args()) > 0 {
return errors.New("the etcd-snapshot command does not take any arguments") return cmds.ErrCommandNoArgs
}
dataDir, err := server.ResolveDataDir(cfg.DataDir)
if err != nil {
return err
} }
var serverConfig server.Config var serverConfig server.Config
...@@ -112,7 +108,8 @@ func Delete(app *cli.Context) error { ...@@ -112,7 +108,8 @@ func Delete(app *cli.Context) error {
} }
func delete(app *cli.Context, cfg *cmds.Server) error { func delete(app *cli.Context, cfg *cmds.Server) error {
if err := commandSetup(app); err != nil { dataDir, err := commandSetup(app, cfg)
if err != nil {
return err return err
} }
...@@ -121,11 +118,6 @@ func delete(app *cli.Context, cfg *cmds.Server) error { ...@@ -121,11 +118,6 @@ func delete(app *cli.Context, cfg *cmds.Server) error {
return errors.New("no snapshots given for removal") return errors.New("no snapshots given for removal")
} }
dataDir, err := server.ResolveDataDir(cfg.DataDir)
if err != nil {
return err
}
var serverConfig server.Config var serverConfig server.Config
serverConfig.DisableAgent = true serverConfig.DisableAgent = true
serverConfig.ControlConfig.DataDir = dataDir serverConfig.ControlConfig.DataDir = dataDir
......
...@@ -991,25 +991,36 @@ func (e *ETCD) DeleteSnapshots(ctx context.Context, snapshots []string) error { ...@@ -991,25 +991,36 @@ func (e *ETCD) DeleteSnapshots(ctx context.Context, snapshots []string) error {
objectsCh := make(chan minio.ObjectInfo) objectsCh := make(chan minio.ObjectInfo)
go func() { toCtx, cancel := context.WithTimeout(ctx, time.Second*30)
for obj := range e.s3.client.ListObjects(ctx, e.config.EtcdS3BucketName, minio.ListObjectsOptions{}) { defer cancel()
if obj.Err != nil {
logrus.Error(obj.Err) go func(ctx context.Context) {
continue defer close(objectsCh)
}
for {
// iterate through the given snapshots and only select {
// add them to the channel for remove if they're case <-ctx.Done():
// actually found from the bucket listing. return
for _, snapshot := range snapshots { default:
if snapshot == obj.Key { for obj := range e.s3.client.ListObjects(ctx, e.config.EtcdS3BucketName, minio.ListObjectsOptions{}) {
objectsCh <- obj if obj.Err != nil {
logrus.Error(obj.Err)
continue
}
// iterate through the given snapshots and only
// add them to the channel for remove if they're
// actually found from the bucket listing.
for _, snapshot := range snapshots {
if snapshot == obj.Key {
objectsCh <- obj
}
}
} }
} }
} }
close(objectsCh) }(toCtx)
}()
for roErr := range e.s3.client.RemoveObjects(ctx, e.config.EtcdS3BucketName, objectsCh, minio.RemoveObjectsOptions{}) { for roErr := range e.s3.client.RemoveObjects(ctx, e.config.EtcdS3BucketName, objectsCh, minio.RemoveObjectsOptions{}) {
logrus.Errorf("Error detected during deletion: %v", roErr) logrus.Errorf("Error detected during deletion: %v", roErr)
......
...@@ -14,6 +14,7 @@ import ( ...@@ -14,6 +14,7 @@ import (
"path/filepath" "path/filepath"
"sort" "sort"
"strings" "strings"
"time"
"github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials" "github.com/minio/minio-go/v7/pkg/credentials"
...@@ -22,6 +23,8 @@ import ( ...@@ -22,6 +23,8 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
const defaultS3OpTimeout = time.Second * 30
// s3 maintains state for S3 functionality. // s3 maintains state for S3 functionality.
type s3 struct { type s3 struct {
config *config.Control config *config.Control
...@@ -61,7 +64,11 @@ func newS3(ctx context.Context, config *config.Control) (*s3, error) { ...@@ -61,7 +64,11 @@ func newS3(ctx context.Context, config *config.Control) (*s3, error) {
} }
logrus.Infof("Checking if S3 bucket %s exists", config.EtcdS3BucketName) logrus.Infof("Checking if S3 bucket %s exists", config.EtcdS3BucketName)
exists, err := c.BucketExists(ctx, config.EtcdS3BucketName)
toCtx, cancel := context.WithTimeout(ctx, defaultS3OpTimeout)
defer cancel()
exists, err := c.BucketExists(toCtx, config.EtcdS3BucketName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -87,11 +94,13 @@ func (s *s3) upload(ctx context.Context, snapshot string) error { ...@@ -87,11 +94,13 @@ func (s *s3) upload(ctx context.Context, snapshot string) error {
snapshotFileName = basename snapshotFileName = basename
} }
toCtx, cancel := context.WithTimeout(ctx, defaultS3OpTimeout)
defer cancel()
opts := minio.PutObjectOptions{ opts := minio.PutObjectOptions{
ContentType: "application/zip", ContentType: "application/zip",
NumThreads: 2, NumThreads: 2,
} }
if _, err := s.client.FPutObject(ctx, s.config.EtcdS3BucketName, snapshotFileName, snapshot, opts); err != nil { if _, err := s.client.FPutObject(toCtx, s.config.EtcdS3BucketName, snapshotFileName, snapshot, opts); err != nil {
logrus.Errorf("Error received in attempt to upload snapshot to S3: %s", err) logrus.Errorf("Error received in attempt to upload snapshot to S3: %s", err)
} }
...@@ -109,7 +118,10 @@ func (s *s3) download(ctx context.Context) error { ...@@ -109,7 +118,10 @@ func (s *s3) download(ctx context.Context) error {
} }
logrus.Debugf("retrieving snapshot: %s", remotePath) logrus.Debugf("retrieving snapshot: %s", remotePath)
r, err := s.client.GetObject(ctx, s.config.EtcdS3BucketName, remotePath, minio.GetObjectOptions{}) toCtx, cancel := context.WithTimeout(ctx, defaultS3OpTimeout)
defer cancel()
r, err := s.client.GetObject(toCtx, s.config.EtcdS3BucketName, remotePath, minio.GetObjectOptions{})
if err != nil { if err != nil {
return nil return nil
} }
...@@ -160,11 +172,14 @@ func (s *s3) snapshotPrefix() string { ...@@ -160,11 +172,14 @@ func (s *s3) snapshotPrefix() string {
func (s *s3) snapshotRetention(ctx context.Context) error { func (s *s3) snapshotRetention(ctx context.Context) error {
var snapshotFiles []minio.ObjectInfo var snapshotFiles []minio.ObjectInfo
toCtx, cancel := context.WithTimeout(ctx, defaultS3OpTimeout)
defer cancel()
loo := minio.ListObjectsOptions{ loo := minio.ListObjectsOptions{
Recursive: true, Recursive: true,
Prefix: s.snapshotPrefix(), Prefix: s.snapshotPrefix(),
} }
for info := range s.client.ListObjects(ctx, s.config.EtcdS3BucketName, loo) { for info := range s.client.ListObjects(toCtx, s.config.EtcdS3BucketName, loo) {
if info.Err != nil { if info.Err != nil {
return info.Err return info.Err
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment