Skip to content

Commit

Permalink
s3 backend: "permanent redirect" vs "moved"; CLI embedded prefix
Browse files Browse the repository at this point in the history
* patch s3 backend to return "bucket not found"
  - (comment inside: status 301 vs 308)
* CLI: embedded prefix part three, prev. commit: 82e93fc
  - (usability)

Signed-off-by: Alex Aizman <[email protected]>
  • Loading branch information
alex-aizman committed Oct 30, 2024
1 parent 1e9122c commit 5f81526
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 18 deletions.
8 changes: 8 additions & 0 deletions ais/backend/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,14 @@ func awsErrorToAISError(awsError error, bck *cmn.Bck, objName string) (int, erro
code = reqErr.ErrorCode()
)
if errors.As(awsError, &rspErr) {
// [NOTE] when bucket does not exist, or is not accessible AWS may
// return http status 301 ("MovedPermanently") and,
// to further confusion, supplies it with ErrorCode() == "PermanentRedirect",
// which is supposed to be 308
if rspErr.HTTPStatusCode() == http.StatusMovedPermanently {
return http.StatusNotFound, cmn.NewErrRemoteBckNotFound(bck)
}

return rspErr.HTTPStatusCode(), _awsErr(awsError, code)
}

Expand Down
15 changes: 14 additions & 1 deletion cmd/cli/cli/bucket_hdlr.go
Original file line number Diff line number Diff line change
Expand Up @@ -617,9 +617,22 @@ func listAnyHandler(c *cli.Context) error {
if errV := errBucketNameInvalid(c, uri, err); errV != nil {
return errV
}
// (e.g. 'ais ls object ais://blah ...')
if cmn.IsErrEmptyProvider(err) {
uri = c.Args().Get(1)
var (
err2 error
warn = fmt.Sprintf("word %q is misplaced, see 'ais ls --help' for details", c.Args().Get(0))
)
actionWarn(c, warn)
bck, objName, err2 = cmn.ParseBckObjectURI(uri, opts)
if err2 == nil {
goto proceed
}
}
return err
}

proceed:
switch {
case objName != "":
// (1) list archive, or
Expand Down
15 changes: 9 additions & 6 deletions cmd/cli/cli/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ func showObjProps(c *cli.Context, bck cmn.Bck, objName string, silent bool) (not
selectedProps []string
hargs = api.HeadArgs{
FltPresence: apc.FltPresentCluster,
Silent: flagIsSet(c, silentFlag),
Silent: flagIsSet(c, silentFlag) || silent,
}
isList = actionIsHandler(c.Command.Action, listAnyHandler)
isRemote = bck.IsRemote()
Expand All @@ -269,26 +269,29 @@ func showObjProps(c *cli.Context, bck cmn.Bck, objName string, silent bool) (not
}
if flagIsSet(c, objNotCachedPropsFlag) || flagIsSet(c, allObjsOrBcksFlag) {
hargs.FltPresence = apc.FltExists
} else if silent && !hargs.Silent {
hargs.Silent = isRemote // silence 404 when called via 'ais ls <remote-bucket>', `ais prefetch`, etc.
}

// do
objProps, err := api.HeadObject(apiBP, bck, objName, hargs)
if err != nil {
notfound = cmn.IsStatusNotFound(err)
if !notfound {
return notfound, err
}
var hint string
var hint, tag string
if !isList {
tag = "object "
}
if apc.IsFltPresent(hargs.FltPresence) && isRemote {
if isList {
if flagIsSet(c, listObjCachedFlag) {
hint = fmt.Sprintf(" (tip: try 'ais ls' without %s option)", qflprn(listObjCachedFlag))
}
} else {
hint = fmt.Sprintf(" (tip: try %s option)", qflprn(objNotCachedPropsFlag))
hint = fmt.Sprintf(" (tip: try %s option or use 'ais ls' to lookup by prefix)", qflprn(objNotCachedPropsFlag))
}
}
return notfound, fmt.Errorf("%q not found in %s%s", objName, bck.Cname(""), hint)
return notfound, fmt.Errorf("%s%q not found in %s%s", tag, objName, bck.Cname(""), hint)
}

if flagIsSet(c, allPropsFlag) {
Expand Down
2 changes: 1 addition & 1 deletion cmd/cli/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/NVIDIA/aistore/cmd/cli
go 1.23.2

require (
github.com/NVIDIA/aistore v1.3.26-0.20241022221110-ec9d71b82df4
github.com/NVIDIA/aistore v1.3.26-0.20241030143942-035070df9f54
github.com/fatih/color v1.17.0
github.com/json-iterator/go v1.1.12
github.com/onsi/ginkgo/v2 v2.20.2
Expand Down
4 changes: 2 additions & 2 deletions cmd/cli/go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
code.cloudfoundry.org/bytefmt v0.0.0-20190710193110-1eb035ffe2b6/go.mod h1:wN/zk7mhREp/oviagqUXY3EwuHhWyOvAdsn5Y4CzOrc=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/NVIDIA/aistore v1.3.26-0.20241022221110-ec9d71b82df4 h1:bb2bM8SR+E28B+asH0kbWzfp/b+Yd/96NK/BhimfPL0=
github.com/NVIDIA/aistore v1.3.26-0.20241022221110-ec9d71b82df4/go.mod h1:Q6J3YIeiL4A6oWga3qCJ8+XI1CUvdde7Gua/HfueGlQ=
github.com/NVIDIA/aistore v1.3.26-0.20241030143942-035070df9f54 h1:j/phqhzqYkIPwydLekPQkW2jlIGmooNiVx3IUivz1M4=
github.com/NVIDIA/aistore v1.3.26-0.20241030143942-035070df9f54/go.mod h1:Q6J3YIeiL4A6oWga3qCJ8+XI1CUvdde7Gua/HfueGlQ=
github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
Expand Down
5 changes: 3 additions & 2 deletions cmn/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,14 +203,15 @@ func (bp *Bprops) Validate(targetCnt int) error {
debug.Assert(apc.IsProvider(bp.Provider))
if !bp.BackendBck.IsEmpty() {
if bp.Provider != apc.AIS {
return fmt.Errorf("wrong bucket provider %q: only AIS buckets can have remote backend (%q)",
return fmt.Errorf("invalid provider %q: only ais:// buckets can have remote backend (%q)",
bp.Provider, bp.BackendBck)
}
if bp.BackendBck.Provider == "" {
// (compare with `ErrEmptyProvider`)
return fmt.Errorf("backend bucket %q: provider is empty", bp.BackendBck)
}
if bp.BackendBck.Name == "" {
return fmt.Errorf("backend bucket %q name is empty", bp.BackendBck)
return fmt.Errorf("backend bucket %q: name is empty", bp.BackendBck)
}
if !bp.BackendBck.IsRemote() {
return fmt.Errorf("backend bucket %q must be remote", bp.BackendBck)
Expand Down
26 changes: 20 additions & 6 deletions cmn/uri.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,24 @@ import (
"github.com/OneOfOne/xxhash"
)

type ParseURIOpts struct {
DefaultProvider string // If set the provider will be used as provider.
IsQuery bool // Determines if the URI should be parsed as query.
type (
ParseURIOpts struct {
DefaultProvider string // If set the provider will be used as provider.
IsQuery bool // Determines if the URI should be parsed as query.
}
ErrEmptyProvider struct {
name string
detail string
}
)

func (e *ErrEmptyProvider) Error() string {
return fmt.Sprintf("backend provider cannot be empty%s (did you mean \"ais://%s\"?)", e.detail, e.name)
}

func IsErrEmptyProvider(err error) bool {
_, ok := err.(*ErrEmptyProvider)
return ok
}

//
Expand All @@ -45,7 +60,6 @@ func OrigURLBck2Name(origURLBck string) (bckName string) {
}

func ParseBckObjectURI(uri string, opts ParseURIOpts) (bck Bck, objName string, err error) {
const fmtErrEmpty = "backend provider cannot be empty%s (did you mean \"ais://%s\"?)"
parts := strings.SplitN(uri, apc.BckProviderSeparator, 2)
if len(parts) > 1 && parts[0] != "" {
if bck.Provider, err = NormalizeProvider(parts[0]); err != nil {
Expand All @@ -63,7 +77,7 @@ func ParseBckObjectURI(uri string, opts ParseURIOpts) (bck Bck, objName string,
return bck, "", err
}
if !opts.IsQuery && bck.Provider == "" {
return bck, "", fmt.Errorf(fmtErrEmpty, " when namespace is not", bck)
return bck, "", &ErrEmptyProvider{uri, " when namespace is not"}
}
if len(parts) == 1 {
if parts[0] == string(apc.NsUUIDPrefix) && opts.IsQuery {
Expand All @@ -87,7 +101,7 @@ func ParseBckObjectURI(uri string, opts ParseURIOpts) (bck Bck, objName string,
return bck, "", err
}
if bck.Provider == "" {
return bck, "", fmt.Errorf(fmtErrEmpty, "", bck)
return bck, "", &ErrEmptyProvider{uri, ""}
}
}
if len(parts) > 1 {
Expand Down

0 comments on commit 5f81526

Please sign in to comment.