From fe750d627eafc1c27506b26e56b39dca2c54b753 Mon Sep 17 00:00:00 2001 From: Jonathan Reem Date: Fri, 25 Sep 2015 12:16:28 -0700 Subject: [PATCH 1/2] Provide a new command, gof3r info, which fetches metadata about an object. The new command will print some small bits of metadata about an object on success and will exit with a non-zero exit code on failure. The info command can be used to query for a file's existence without downloading it, and performs only a HEAD request. Fixes #71 --- getter.go | 29 +++++++++++++++++++++++ gof3r/info.go | 59 ++++++++++++++++++++++++++++++++++++++++++++++ gof3r/main_test.go | 9 +++++++ 3 files changed, 97 insertions(+) create mode 100644 gof3r/info.go diff --git a/getter.go b/getter.go index 600dae0..093d126 100644 --- a/getter.go +++ b/getter.go @@ -307,6 +307,35 @@ func (g *getter) Close() error { return nil } +func GetInfo(b *Bucket, c *Config, key string, version string) (*http.Response, error) { + urlStr, err := b.url(key, c) + + if err != nil { + return nil, err + } + + for i := 0; i < c.NTry; i++ { + var req *http.Request + req, err := http.NewRequest("HEAD", urlStr.String(), nil) + + if err != nil { + return nil, err + } + + b.Sign(req) + + resp, err := c.Client.Do(req) + + if err != nil { + return nil, err + } + + return resp, nil + } + + return nil, fmt.Errorf("Could not get info.") +} + func (g *getter) checkMd5() (err error) { calcMd5 := fmt.Sprintf("%x", g.md5.Sum(nil)) md5Path := fmt.Sprint(".md5", g.url.Path, ".md5") diff --git a/gof3r/info.go b/gof3r/info.go new file mode 100644 index 0000000..c188802 --- /dev/null +++ b/gof3r/info.go @@ -0,0 +1,59 @@ +package main + +import ( + "log" + + "github.com/rlmcpherson/s3gof3r" +) + +var info infoOpts + +type infoOpts struct { + Key string `long:"key" short:"k" description:"S3 object key" required:"true" no-ini:"true"` + Bucket string `long:"bucket" short:"b" description:"S3 bucket" required:"true" no-ini:"true"` + VersionID string `short:"v" long:"versionId" description:"Version ID of the object. Incompatible with md5 check (use --no-md5)." no-ini:"true"` +} + +func (info *infoOpts) Execute(args []string) (err error) { + conf := new(s3gof3r.Config) + *conf = *s3gof3r.DefaultConfig + k, err := getAWSKeys() + if err != nil { + return err + } + + s3 := s3gof3r.New(get.EndPoint, k) + b := s3.Bucket(info.Bucket) + conf.Concurrency = get.Concurrency + + if get.NoSSL { + conf.Scheme = "http" + } + + resp, err := s3gof3r.GetInfo(b, s3gof3r.DefaultConfig, info.Key, info.VersionID) + + if err != nil { + return err + } + + if resp.StatusCode >= 200 && resp.StatusCode < 300 { + log.Println("Found object:") + log.Println(" Status: ", resp.StatusCode) + log.Println(" Last-Modified: ", resp.Header["Last-Modified"]) + log.Println(" Size: ", resp.Header["Content-Length"]) + } else if resp.StatusCode == 403 { + log.Fatal("Access Denied") + } else { + log.Fatal("Non-2XX status code: ", resp.StatusCode) + } + + return nil +} + +func init() { + _, err := parser.AddCommand("info", "check info from S3", "get information about an object from S3", &info) + + if err != nil { + log.Fatal(err) + } +} diff --git a/gof3r/main_test.go b/gof3r/main_test.go index 9177aa7..9dae0a7 100644 --- a/gof3r/main_test.go +++ b/gof3r/main_test.go @@ -35,6 +35,15 @@ var flagTests = []flagTest{ errors.New("expected argument for flag")}, {[]string{"gof3r", "get"}, errors.New("required flags")}, + {[]string{"gof3r", "info"}, + errors.New("required flags")}, + {[]string{"gof3r", "info", "-b"}, + errors.New("expected argument for flag")}, + {[]string{"gof3r", "info", "-b", "fake-bucket", "-k", "test-key"}, + errors.New("Access Denied")}, + {[]string{"gof3r", "info", "-b", "fake-bucket", "-k", "key", + "-c", "1", "-s", "1024", "--debug", "--no-ssl", "--no-md5"}, + errors.New("Access Denied")}, } func TestFlags(t *testing.T) { From 7639ce6879bf896623a8f9b3c59975c0fc6870b8 Mon Sep 17 00:00:00 2001 From: Jonathan Reem Date: Fri, 8 Jan 2016 19:00:10 -0800 Subject: [PATCH 2/2] Add common options to info command. --- gof3r/info.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/gof3r/info.go b/gof3r/info.go index c188802..50dfc5b 100644 --- a/gof3r/info.go +++ b/gof3r/info.go @@ -9,6 +9,7 @@ import ( var info infoOpts type infoOpts struct { + CommonOpts Key string `long:"key" short:"k" description:"S3 object key" required:"true" no-ini:"true"` Bucket string `long:"bucket" short:"b" description:"S3 bucket" required:"true" no-ini:"true"` VersionID string `short:"v" long:"versionId" description:"Version ID of the object. Incompatible with md5 check (use --no-md5)." no-ini:"true"` @@ -22,13 +23,8 @@ func (info *infoOpts) Execute(args []string) (err error) { return err } - s3 := s3gof3r.New(get.EndPoint, k) + s3 := s3gof3r.New(info.EndPoint, k) b := s3.Bucket(info.Bucket) - conf.Concurrency = get.Concurrency - - if get.NoSSL { - conf.Scheme = "http" - } resp, err := s3gof3r.GetInfo(b, s3gof3r.DefaultConfig, info.Key, info.VersionID)