frostfs-s3-gw/neofs/api/handler/container.go

172 lines
4.2 KiB
Go
Raw Normal View History

2020-07-24 16:10:41 +00:00
package handler
import (
"context"
"encoding/xml"
"net/http"
"time"
"github.com/minio/minio/auth"
2020-07-24 16:10:41 +00:00
"github.com/minio/minio/neofs/api"
"github.com/nspcc-dev/neofs-api-go/container"
"github.com/nspcc-dev/neofs-api-go/refs"
"github.com/nspcc-dev/neofs-api-go/service"
"github.com/pkg/errors"
"go.uber.org/zap"
"google.golang.org/grpc"
)
type (
// Owner - bucket owner/principal
Owner struct {
ID string
DisplayName string
}
// Bucket container for bucket metadata
Bucket struct {
CID refs.CID `xml:"-"` // ignored by response
2020-07-24 16:10:41 +00:00
Name string
CreationDate string // time string of format "2006-01-02T15:04:05.000Z"
}
// ListBucketsResponse - format for list buckets response
ListBucketsResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListAllMyBucketsResult" json:"-"`
Owner Owner
// Container for one or more buckets.
Buckets struct {
Buckets []*Bucket `xml:"Bucket"`
} // Buckets are nested
}
cnrInfoParams struct {
cid refs.CID
tkn *service.BearerTokenMsg
}
)
func (h *handler) getContainerInfo(ctx context.Context, p cnrInfoParams) (*Bucket, error) {
var (
err error
2020-07-27 06:49:23 +00:00
con *grpc.ClientConn
2020-07-24 16:10:41 +00:00
res *container.GetResponse
)
req := new(container.GetRequest)
req.SetCID(p.cid)
req.SetTTL(service.SingleForwardingTTL)
req.SetBearer(p.tkn)
2020-07-27 06:49:23 +00:00
if con, err = h.cli.GetConnection(ctx); err != nil {
return nil, errors.Wrap(err, "could not fetch connection")
} else if err = service.SignRequestData(h.key, req); err != nil {
2020-07-24 16:10:41 +00:00
return nil, errors.Wrap(err, "could not sign container info request")
2020-07-27 06:49:23 +00:00
} else if res, err = container.NewServiceClient(con).Get(ctx, req); err != nil {
2020-07-24 16:10:41 +00:00
return nil, errors.Wrap(err, "could not fetch container info")
}
// TODO should extract nice name
// and datetime from container info:
_ = res
return &Bucket{
CID: p.cid,
2020-07-24 16:10:41 +00:00
Name: p.cid.String(),
CreationDate: new(time.Time).Format(time.RFC3339),
}, nil
}
func (h *handler) getContainerList(ctx context.Context, tkn *service.BearerTokenMsg) ([]*Bucket, error) {
2020-07-24 16:10:41 +00:00
var (
err error
inf *Bucket
2020-07-24 16:10:41 +00:00
con *grpc.ClientConn
res *container.ListResponse
)
req := new(container.ListRequest)
2020-07-27 06:49:23 +00:00
req.OwnerID = tkn.OwnerID
2020-07-24 16:10:41 +00:00
req.SetTTL(service.SingleForwardingTTL)
req.SetBearer(tkn)
2020-07-24 16:10:41 +00:00
if con, err = h.cli.GetConnection(ctx); err != nil {
2020-07-27 06:49:23 +00:00
return nil, errors.Wrap(err, "could not fetch connection")
} else if err = service.SignRequestData(h.key, req); err != nil {
return nil, errors.Wrap(err, "could not sign request")
} else if res, err = container.NewServiceClient(con).List(ctx, req); err != nil {
return nil, errors.Wrap(err, "could not fetch list containers")
}
2020-07-24 16:10:41 +00:00
params := cnrInfoParams{tkn: tkn}
result := make([]*Bucket, 0, len(res.CID))
for _, cid := range res.CID {
params.cid = cid
if inf, err = h.getContainerInfo(ctx, params); err != nil {
return nil, errors.Wrap(err, "could not fetch container info")
}
result = append(result, inf)
}
return result, nil
2020-07-27 06:49:23 +00:00
}
2020-07-24 16:10:41 +00:00
2020-07-27 06:49:23 +00:00
func (h *handler) ListBucketsHandler(w http.ResponseWriter, r *http.Request) {
var (
err error
lst []*Bucket
2020-07-27 06:49:23 +00:00
tkn *service.BearerTokenMsg
)
2020-07-24 16:10:41 +00:00
2020-07-27 06:49:23 +00:00
// TODO think about deadlines
ctx, cancel := context.WithTimeout(r.Context(), 30*time.Second)
defer cancel()
if tkn, err = auth.GetBearerToken(ctx); err != nil {
h.log.Error("could not fetch bearer token",
2020-07-24 16:10:41 +00:00
zap.Error(err))
e := api.GetAPIError(api.ErrInternalError)
api.WriteErrorResponse(ctx, w, api.Error{
Code: e.Code,
Description: err.Error(),
HTTPStatusCode: e.HTTPStatusCode,
}, r.URL)
return
2020-07-27 06:49:23 +00:00
} else if lst, err = h.getContainerList(ctx, tkn); err != nil {
h.log.Error("could not fetch bearer token",
2020-07-24 16:10:41 +00:00
zap.Error(err))
2020-07-27 06:49:23 +00:00
// TODO check that error isn't gRPC error
2020-07-24 16:10:41 +00:00
e := api.GetAPIError(api.ErrInternalError)
api.WriteErrorResponse(ctx, w, api.Error{
Code: e.Code,
Description: err.Error(),
HTTPStatusCode: e.HTTPStatusCode,
}, r.URL)
return
}
result := &ListBucketsResponse{Owner: Owner{
2020-07-27 06:49:23 +00:00
ID: tkn.OwnerID.String(),
DisplayName: tkn.OwnerID.String(),
2020-07-24 16:10:41 +00:00
}}
result.Buckets.Buckets = lst
2020-07-24 16:10:41 +00:00
// Generate response.
encodedSuccessResponse := api.EncodeResponse(result)
// Write response.
api.WriteSuccessResponseXML(w, encodedSuccessResponse)
}