[#1] Add route to list containers
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
d1cb88672c
commit
26f0ae93f4
12 changed files with 913 additions and 30 deletions
|
@ -43,6 +43,7 @@ const (
|
|||
testListenAddress = "localhost:8082"
|
||||
testHost = "http://" + testListenAddress
|
||||
testNode = "localhost:8080"
|
||||
containerName = "test-container"
|
||||
|
||||
// XNeofsTokenSignature header contains base64 encoded signature of the token body.
|
||||
XNeofsTokenSignature = "X-Neofs-Token-Signature"
|
||||
|
@ -72,7 +73,7 @@ func TestIntegration(t *testing.T) {
|
|||
aioContainer := createDockerContainer(ctx, t, aioImage+version)
|
||||
cancel := runServer(ctx, t)
|
||||
clientPool := getPool(ctx, t, key)
|
||||
cnrID := createContainer(ctx, t, clientPool, "test-container")
|
||||
cnrID := createContainer(ctx, t, clientPool, containerName)
|
||||
|
||||
t.Run("rest put object "+version, func(t *testing.T) { restObjectPut(ctx, t, clientPool, cnrID) })
|
||||
t.Run("rest get object "+version, func(t *testing.T) { restObjectGet(ctx, t, clientPool, cnrID) })
|
||||
|
@ -82,6 +83,7 @@ func TestIntegration(t *testing.T) {
|
|||
t.Run("rest delete container"+version, func(t *testing.T) { restContainerDelete(ctx, t, clientPool) })
|
||||
t.Run("rest put container eacl "+version, func(t *testing.T) { restContainerEACLPut(ctx, t, clientPool) })
|
||||
t.Run("rest get container eacl "+version, func(t *testing.T) { restContainerEACLGet(ctx, t, clientPool) })
|
||||
t.Run("rest list containers "+version, func(t *testing.T) { restContainerList(ctx, t, clientPool, cnrID) })
|
||||
|
||||
cancel()
|
||||
err = aioContainer.Terminate(ctx)
|
||||
|
@ -407,6 +409,35 @@ func restContainerEACLGet(ctx context.Context, t *testing.T, clientPool *pool.Po
|
|||
require.True(t, eacl.EqualTables(*expectedTable, *actualTable))
|
||||
}
|
||||
|
||||
func restContainerList(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *cid.ID) {
|
||||
var prm pool.PrmContainerList
|
||||
prm.SetOwnerID(*p.OwnerID())
|
||||
|
||||
ids, err := p.ListContainers(ctx, prm)
|
||||
require.NoError(t, err)
|
||||
|
||||
httpClient := defaultHTTPClient()
|
||||
|
||||
query := make(url.Values)
|
||||
query.Add("ownerId", p.OwnerID().String())
|
||||
|
||||
request, err := http.NewRequest(http.MethodGet, testHost+"/v1/containers?"+query.Encode(), nil)
|
||||
require.NoError(t, err)
|
||||
request = request.WithContext(ctx)
|
||||
|
||||
list := &models.ContainerList{}
|
||||
doRequest(t, httpClient, request, http.StatusOK, list)
|
||||
|
||||
require.Equal(t, len(ids), int(*list.Size))
|
||||
|
||||
expected := &models.ContainerBaseInfo{
|
||||
ContainerID: handlers.NewString(cnrID.String()),
|
||||
Name: containerName,
|
||||
}
|
||||
|
||||
require.Contains(t, list.Containers, expected)
|
||||
}
|
||||
|
||||
func makeAuthContainerTokenRequest(ctx context.Context, t *testing.T, bearer *models.Bearer, httpClient *http.Client) *handlers.BearerToken {
|
||||
return makeAuthTokenRequest(ctx, t, bearer, httpClient, models.TokenTypeContainer)
|
||||
}
|
||||
|
|
74
gen/models/container_base_info.go
Normal file
74
gen/models/container_base_info.go
Normal file
|
@ -0,0 +1,74 @@
|
|||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
package models
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// ContainerBaseInfo container base info
|
||||
//
|
||||
// swagger:model ContainerBaseInfo
|
||||
type ContainerBaseInfo struct {
|
||||
|
||||
// container Id
|
||||
// Required: true
|
||||
ContainerID *string `json:"containerId"`
|
||||
|
||||
// name
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this container base info
|
||||
func (m *ContainerBaseInfo) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateContainerID(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ContainerBaseInfo) validateContainerID(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("containerId", "body", m.ContainerID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this container base info based on context it is used
|
||||
func (m *ContainerBaseInfo) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *ContainerBaseInfo) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *ContainerBaseInfo) UnmarshalBinary(b []byte) error {
|
||||
var res ContainerBaseInfo
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
136
gen/models/container_list.go
Normal file
136
gen/models/container_list.go
Normal file
|
@ -0,0 +1,136 @@
|
|||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
package models
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// ContainerList container list
|
||||
//
|
||||
// swagger:model ContainerList
|
||||
type ContainerList struct {
|
||||
|
||||
// containers
|
||||
// Required: true
|
||||
Containers []*ContainerBaseInfo `json:"containers"`
|
||||
|
||||
// size
|
||||
// Required: true
|
||||
Size *int64 `json:"size"`
|
||||
}
|
||||
|
||||
// Validate validates this container list
|
||||
func (m *ContainerList) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateContainers(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateSize(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ContainerList) validateContainers(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("containers", "body", m.Containers); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(m.Containers); i++ {
|
||||
if swag.IsZero(m.Containers[i]) { // not required
|
||||
continue
|
||||
}
|
||||
|
||||
if m.Containers[i] != nil {
|
||||
if err := m.Containers[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("containers" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("containers" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ContainerList) validateSize(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("size", "body", m.Size); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this container list based on the context it is used
|
||||
func (m *ContainerList) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidateContainers(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ContainerList) contextValidateContainers(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
for i := 0; i < len(m.Containers); i++ {
|
||||
|
||||
if m.Containers[i] != nil {
|
||||
if err := m.Containers[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("containers" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("containers" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *ContainerList) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *ContainerList) UnmarshalBinary(b []byte) error {
|
||||
var res ContainerList
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
|
@ -94,10 +94,60 @@ func init() {
|
|||
}
|
||||
},
|
||||
"/containers": {
|
||||
"get": {
|
||||
"security": [],
|
||||
"summary": "Get list of containers",
|
||||
"operationId": "listContainers",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Base58 encoded owner id",
|
||||
"name": "ownerId",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"default": 0,
|
||||
"description": "The number of containers to skip before starting to collect the result set.",
|
||||
"name": "offset",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"maximum": 10000,
|
||||
"minimum": 1,
|
||||
"type": "integer",
|
||||
"default": 100,
|
||||
"description": "The numbers of containers to return.",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Containers info",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ContainerList"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"summary": "Create new container in NeoFS",
|
||||
"operationId": "putContainer",
|
||||
"parameters": [
|
||||
{
|
||||
"$ref": "#/parameters/signatureParam"
|
||||
},
|
||||
{
|
||||
"$ref": "#/parameters/signatureKeyParam"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
|
@ -159,15 +209,7 @@ func init() {
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"$ref": "#/parameters/signatureParam"
|
||||
},
|
||||
{
|
||||
"$ref": "#/parameters/signatureKeyParam"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/containers/{containerId}": {
|
||||
"get": {
|
||||
|
@ -433,6 +475,20 @@ func init() {
|
|||
}
|
||||
}
|
||||
},
|
||||
"ContainerBaseInfo": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"containerId"
|
||||
],
|
||||
"properties": {
|
||||
"containerId": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ContainerInfo": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -484,6 +540,24 @@ func init() {
|
|||
"version": "2.11"
|
||||
}
|
||||
},
|
||||
"ContainerList": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"size",
|
||||
"containers"
|
||||
],
|
||||
"properties": {
|
||||
"containers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/ContainerBaseInfo"
|
||||
}
|
||||
},
|
||||
"size": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Eacl": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -853,10 +927,69 @@ func init() {
|
|||
}
|
||||
},
|
||||
"/containers": {
|
||||
"get": {
|
||||
"security": [],
|
||||
"summary": "Get list of containers",
|
||||
"operationId": "listContainers",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Base58 encoded owner id",
|
||||
"name": "ownerId",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"default": 0,
|
||||
"description": "The number of containers to skip before starting to collect the result set.",
|
||||
"name": "offset",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"maximum": 10000,
|
||||
"minimum": 1,
|
||||
"type": "integer",
|
||||
"default": 100,
|
||||
"description": "The numbers of containers to return.",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Containers info",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ContainerList"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"summary": "Create new container in NeoFS",
|
||||
"operationId": "putContainer",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Base64 encoded signature for bearer token",
|
||||
"name": "X-Neofs-Token-Signature",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Hex encoded the public part of the key that signed the bearer token",
|
||||
"name": "X-Neofs-Token-Signature-Key",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
|
@ -918,23 +1051,7 @@ func init() {
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Base64 encoded signature for bearer token",
|
||||
"name": "X-Neofs-Token-Signature",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Hex encoded the public part of the key that signed the bearer token",
|
||||
"name": "X-Neofs-Token-Signature-Key",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/containers/{containerId}": {
|
||||
"get": {
|
||||
|
@ -1244,6 +1361,20 @@ func init() {
|
|||
}
|
||||
}
|
||||
},
|
||||
"ContainerBaseInfo": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"containerId"
|
||||
],
|
||||
"properties": {
|
||||
"containerId": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ContainerInfo": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -1295,6 +1426,24 @@ func init() {
|
|||
"version": "2.11"
|
||||
}
|
||||
},
|
||||
"ContainerList": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"size",
|
||||
"containers"
|
||||
],
|
||||
"properties": {
|
||||
"containers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/ContainerBaseInfo"
|
||||
}
|
||||
},
|
||||
"size": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Eacl": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
|
56
gen/restapi/operations/list_containers.go
Normal file
56
gen/restapi/operations/list_containers.go
Normal file
|
@ -0,0 +1,56 @@
|
|||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
package operations
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the generate command
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
)
|
||||
|
||||
// ListContainersHandlerFunc turns a function with the right signature into a list containers handler
|
||||
type ListContainersHandlerFunc func(ListContainersParams) middleware.Responder
|
||||
|
||||
// Handle executing the request and returning a response
|
||||
func (fn ListContainersHandlerFunc) Handle(params ListContainersParams) middleware.Responder {
|
||||
return fn(params)
|
||||
}
|
||||
|
||||
// ListContainersHandler interface for that can handle valid list containers params
|
||||
type ListContainersHandler interface {
|
||||
Handle(ListContainersParams) middleware.Responder
|
||||
}
|
||||
|
||||
// NewListContainers creates a new http.Handler for the list containers operation
|
||||
func NewListContainers(ctx *middleware.Context, handler ListContainersHandler) *ListContainers {
|
||||
return &ListContainers{Context: ctx, Handler: handler}
|
||||
}
|
||||
|
||||
/* ListContainers swagger:route GET /containers listContainers
|
||||
|
||||
Get list of containers
|
||||
|
||||
*/
|
||||
type ListContainers struct {
|
||||
Context *middleware.Context
|
||||
Handler ListContainersHandler
|
||||
}
|
||||
|
||||
func (o *ListContainers) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
route, rCtx, _ := o.Context.RouteInfo(r)
|
||||
if rCtx != nil {
|
||||
*r = *rCtx
|
||||
}
|
||||
var Params = NewListContainersParams()
|
||||
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
|
||||
o.Context.Respond(rw, r, route.Produces, route, err)
|
||||
return
|
||||
}
|
||||
|
||||
res := o.Handler.Handle(Params) // actually handle the request
|
||||
o.Context.Respond(rw, r, route.Produces, route, res)
|
||||
|
||||
}
|
196
gen/restapi/operations/list_containers_parameters.go
Normal file
196
gen/restapi/operations/list_containers_parameters.go
Normal file
|
@ -0,0 +1,196 @@
|
|||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
package operations
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// NewListContainersParams creates a new ListContainersParams object
|
||||
// with the default values initialized.
|
||||
func NewListContainersParams() ListContainersParams {
|
||||
|
||||
var (
|
||||
// initialize parameters with default values
|
||||
|
||||
limitDefault = int64(100)
|
||||
offsetDefault = int64(0)
|
||||
)
|
||||
|
||||
return ListContainersParams{
|
||||
Limit: &limitDefault,
|
||||
|
||||
Offset: &offsetDefault,
|
||||
}
|
||||
}
|
||||
|
||||
// ListContainersParams contains all the bound params for the list containers operation
|
||||
// typically these are obtained from a http.Request
|
||||
//
|
||||
// swagger:parameters listContainers
|
||||
type ListContainersParams struct {
|
||||
|
||||
// HTTP Request Object
|
||||
HTTPRequest *http.Request `json:"-"`
|
||||
|
||||
/*The numbers of containers to return.
|
||||
Maximum: 10000
|
||||
Minimum: 1
|
||||
In: query
|
||||
Default: 100
|
||||
*/
|
||||
Limit *int64
|
||||
/*The number of containers to skip before starting to collect the result set.
|
||||
Minimum: 0
|
||||
In: query
|
||||
Default: 0
|
||||
*/
|
||||
Offset *int64
|
||||
/*Base58 encoded owner id
|
||||
Required: true
|
||||
In: query
|
||||
*/
|
||||
OwnerID string
|
||||
}
|
||||
|
||||
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
|
||||
// for simple values it will use straight method calls.
|
||||
//
|
||||
// To ensure default values, the struct must have been initialized with NewListContainersParams() beforehand.
|
||||
func (o *ListContainersParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
|
||||
var res []error
|
||||
|
||||
o.HTTPRequest = r
|
||||
|
||||
qs := runtime.Values(r.URL.Query())
|
||||
|
||||
qLimit, qhkLimit, _ := qs.GetOK("limit")
|
||||
if err := o.bindLimit(qLimit, qhkLimit, route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
qOffset, qhkOffset, _ := qs.GetOK("offset")
|
||||
if err := o.bindOffset(qOffset, qhkOffset, route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
qOwnerID, qhkOwnerID, _ := qs.GetOK("ownerId")
|
||||
if err := o.bindOwnerID(qOwnerID, qhkOwnerID, route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindLimit binds and validates parameter Limit from query.
|
||||
func (o *ListContainersParams) bindLimit(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||
var raw string
|
||||
if len(rawData) > 0 {
|
||||
raw = rawData[len(rawData)-1]
|
||||
}
|
||||
|
||||
// Required: false
|
||||
// AllowEmptyValue: false
|
||||
|
||||
if raw == "" { // empty values pass all other validations
|
||||
// Default values have been previously initialized by NewListContainersParams()
|
||||
return nil
|
||||
}
|
||||
|
||||
value, err := swag.ConvertInt64(raw)
|
||||
if err != nil {
|
||||
return errors.InvalidType("limit", "query", "int64", raw)
|
||||
}
|
||||
o.Limit = &value
|
||||
|
||||
if err := o.validateLimit(formats); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateLimit carries on validations for parameter Limit
|
||||
func (o *ListContainersParams) validateLimit(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.MinimumInt("limit", "query", *o.Limit, 1, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := validate.MaximumInt("limit", "query", *o.Limit, 10000, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindOffset binds and validates parameter Offset from query.
|
||||
func (o *ListContainersParams) bindOffset(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||
var raw string
|
||||
if len(rawData) > 0 {
|
||||
raw = rawData[len(rawData)-1]
|
||||
}
|
||||
|
||||
// Required: false
|
||||
// AllowEmptyValue: false
|
||||
|
||||
if raw == "" { // empty values pass all other validations
|
||||
// Default values have been previously initialized by NewListContainersParams()
|
||||
return nil
|
||||
}
|
||||
|
||||
value, err := swag.ConvertInt64(raw)
|
||||
if err != nil {
|
||||
return errors.InvalidType("offset", "query", "int64", raw)
|
||||
}
|
||||
o.Offset = &value
|
||||
|
||||
if err := o.validateOffset(formats); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateOffset carries on validations for parameter Offset
|
||||
func (o *ListContainersParams) validateOffset(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.MinimumInt("offset", "query", *o.Offset, 0, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindOwnerID binds and validates parameter OwnerID from query.
|
||||
func (o *ListContainersParams) bindOwnerID(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||
if !hasKey {
|
||||
return errors.Required("ownerId", "query", rawData)
|
||||
}
|
||||
var raw string
|
||||
if len(rawData) > 0 {
|
||||
raw = rawData[len(rawData)-1]
|
||||
}
|
||||
|
||||
// Required: true
|
||||
// AllowEmptyValue: false
|
||||
|
||||
if err := validate.RequiredString("ownerId", "query", raw); err != nil {
|
||||
return err
|
||||
}
|
||||
o.OwnerID = raw
|
||||
|
||||
return nil
|
||||
}
|
100
gen/restapi/operations/list_containers_responses.go
Normal file
100
gen/restapi/operations/list_containers_responses.go
Normal file
|
@ -0,0 +1,100 @@
|
|||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
package operations
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
|
||||
"github.com/nspcc-dev/neofs-rest-gw/gen/models"
|
||||
)
|
||||
|
||||
// ListContainersOKCode is the HTTP code returned for type ListContainersOK
|
||||
const ListContainersOKCode int = 200
|
||||
|
||||
/*ListContainersOK Containers info
|
||||
|
||||
swagger:response listContainersOK
|
||||
*/
|
||||
type ListContainersOK struct {
|
||||
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.ContainerList `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewListContainersOK creates ListContainersOK with default headers values
|
||||
func NewListContainersOK() *ListContainersOK {
|
||||
|
||||
return &ListContainersOK{}
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the list containers o k response
|
||||
func (o *ListContainersOK) WithPayload(payload *models.ContainerList) *ListContainersOK {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the list containers o k response
|
||||
func (o *ListContainersOK) SetPayload(payload *models.ContainerList) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
// WriteResponse to the client
|
||||
func (o *ListContainersOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
|
||||
rw.WriteHeader(200)
|
||||
if o.Payload != nil {
|
||||
payload := o.Payload
|
||||
if err := producer.Produce(rw, payload); err != nil {
|
||||
panic(err) // let the recovery middleware deal with this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ListContainersBadRequestCode is the HTTP code returned for type ListContainersBadRequest
|
||||
const ListContainersBadRequestCode int = 400
|
||||
|
||||
/*ListContainersBadRequest Bad request
|
||||
|
||||
swagger:response listContainersBadRequest
|
||||
*/
|
||||
type ListContainersBadRequest struct {
|
||||
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload models.Error `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewListContainersBadRequest creates ListContainersBadRequest with default headers values
|
||||
func NewListContainersBadRequest() *ListContainersBadRequest {
|
||||
|
||||
return &ListContainersBadRequest{}
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the list containers bad request response
|
||||
func (o *ListContainersBadRequest) WithPayload(payload models.Error) *ListContainersBadRequest {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the list containers bad request response
|
||||
func (o *ListContainersBadRequest) SetPayload(payload models.Error) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
// WriteResponse to the client
|
||||
func (o *ListContainersBadRequest) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
|
||||
rw.WriteHeader(400)
|
||||
payload := o.Payload
|
||||
if err := producer.Produce(rw, payload); err != nil {
|
||||
panic(err) // let the recovery middleware deal with this
|
||||
}
|
||||
}
|
|
@ -59,6 +59,9 @@ func NewNeofsRestGwAPI(spec *loads.Document) *NeofsRestGwAPI {
|
|||
GetObjectInfoHandler: GetObjectInfoHandlerFunc(func(params GetObjectInfoParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation GetObjectInfo has not yet been implemented")
|
||||
}),
|
||||
ListContainersHandler: ListContainersHandlerFunc(func(params ListContainersParams) middleware.Responder {
|
||||
return middleware.NotImplemented("operation ListContainers has not yet been implemented")
|
||||
}),
|
||||
PutContainerHandler: PutContainerHandlerFunc(func(params PutContainerParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation PutContainer has not yet been implemented")
|
||||
}),
|
||||
|
@ -128,6 +131,8 @@ type NeofsRestGwAPI struct {
|
|||
GetContainerEACLHandler GetContainerEACLHandler
|
||||
// GetObjectInfoHandler sets the operation handler for the get object info operation
|
||||
GetObjectInfoHandler GetObjectInfoHandler
|
||||
// ListContainersHandler sets the operation handler for the list containers operation
|
||||
ListContainersHandler ListContainersHandler
|
||||
// PutContainerHandler sets the operation handler for the put container operation
|
||||
PutContainerHandler PutContainerHandler
|
||||
// PutContainerEACLHandler sets the operation handler for the put container e ACL operation
|
||||
|
@ -230,6 +235,9 @@ func (o *NeofsRestGwAPI) Validate() error {
|
|||
if o.GetObjectInfoHandler == nil {
|
||||
unregistered = append(unregistered, "GetObjectInfoHandler")
|
||||
}
|
||||
if o.ListContainersHandler == nil {
|
||||
unregistered = append(unregistered, "ListContainersHandler")
|
||||
}
|
||||
if o.PutContainerHandler == nil {
|
||||
unregistered = append(unregistered, "PutContainerHandler")
|
||||
}
|
||||
|
@ -358,6 +366,10 @@ func (o *NeofsRestGwAPI) initHandlerCache() {
|
|||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["GET"]["/objects/{containerId}/{objectId}"] = NewGetObjectInfo(o.context, o.GetObjectInfoHandler)
|
||||
if o.handlers["GET"] == nil {
|
||||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["GET"]["/containers"] = NewListContainers(o.context, o.ListContainersHandler)
|
||||
if o.handlers["PUT"] == nil {
|
||||
o.handlers["PUT"] = make(map[string]http.Handler)
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@ func (a *API) Configure(api *operations.NeofsRestGwAPI) http.Handler {
|
|||
api.DeleteContainerHandler = operations.DeleteContainerHandlerFunc(a.DeleteContainer)
|
||||
api.PutContainerEACLHandler = operations.PutContainerEACLHandlerFunc(a.PutContainerEACL)
|
||||
api.GetContainerEACLHandler = operations.GetContainerEACLHandlerFunc(a.GetContainerEACL)
|
||||
api.ListContainersHandler = operations.ListContainersHandlerFunc(a.ListContainer)
|
||||
|
||||
api.BearerAuthAuth = func(s string) (*models.Principal, error) {
|
||||
if !strings.HasPrefix(s, BearerPrefix) {
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/owner"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -124,6 +125,57 @@ func (a *API) GetContainerEACL(params operations.GetContainerEACLParams) middlew
|
|||
return operations.NewGetContainerEACLOK().WithPayload(resp)
|
||||
}
|
||||
|
||||
// ListContainer handler that returns containers.
|
||||
func (a *API) ListContainer(params operations.ListContainersParams) middleware.Responder {
|
||||
ctx := params.HTTPRequest.Context()
|
||||
|
||||
var ownerID owner.ID
|
||||
if err := ownerID.Parse(params.OwnerID); err != nil {
|
||||
a.log.Error("invalid owner id", zap.Error(err))
|
||||
return operations.NewListContainersBadRequest().WithPayload("invalid owner id")
|
||||
}
|
||||
|
||||
var prm pool.PrmContainerList
|
||||
prm.SetOwnerID(ownerID)
|
||||
|
||||
ids, err := a.pool.ListContainers(ctx, prm)
|
||||
if err != nil {
|
||||
a.log.Error("list containers", zap.Error(err))
|
||||
return operations.NewListContainersBadRequest().WithPayload("failed to get containers")
|
||||
}
|
||||
|
||||
offset := int(*params.Offset)
|
||||
size := int(*params.Limit)
|
||||
|
||||
if offset > len(ids)-1 {
|
||||
res := &models.ContainerList{
|
||||
Size: NewInteger(0),
|
||||
Containers: []*models.ContainerBaseInfo{},
|
||||
}
|
||||
return operations.NewListContainersOK().WithPayload(res)
|
||||
}
|
||||
|
||||
if offset+size > len(ids) {
|
||||
size = len(ids) - offset
|
||||
}
|
||||
|
||||
res := &models.ContainerList{
|
||||
Size: NewInteger(int64(size)),
|
||||
Containers: make([]*models.ContainerBaseInfo, 0, size),
|
||||
}
|
||||
|
||||
for _, id := range ids[offset : offset+size] {
|
||||
baseInfo, err := getContainerBaseInfo(ctx, a.pool, id)
|
||||
if err != nil {
|
||||
a.log.Error("get container", zap.String("cid", id.String()), zap.Error(err))
|
||||
return operations.NewListContainersBadRequest().WithPayload("failed to get container")
|
||||
}
|
||||
res.Containers = append(res.Containers, baseInfo)
|
||||
}
|
||||
|
||||
return operations.NewListContainersOK().WithPayload(res)
|
||||
}
|
||||
|
||||
// DeleteContainer handler that returns container info.
|
||||
func (a *API) DeleteContainer(params operations.DeleteContainerParams, principal *models.Principal) middleware.Responder {
|
||||
bt := &BearerToken{
|
||||
|
@ -155,6 +207,26 @@ func (a *API) DeleteContainer(params operations.DeleteContainerParams, principal
|
|||
return operations.NewDeleteContainerNoContent()
|
||||
}
|
||||
|
||||
func getContainerBaseInfo(ctx context.Context, p *pool.Pool, cnrID cid.ID) (*models.ContainerBaseInfo, error) {
|
||||
var prm pool.PrmContainerGet
|
||||
prm.SetContainerID(cnrID)
|
||||
|
||||
cnr, err := p.GetContainer(ctx, prm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
baseInfo := &models.ContainerBaseInfo{ContainerID: NewString(cnrID.String())}
|
||||
|
||||
for _, attr := range cnr.Attributes() {
|
||||
if attr.Key() == container.AttributeName {
|
||||
baseInfo.Name = attr.Value()
|
||||
}
|
||||
}
|
||||
|
||||
return baseInfo, nil
|
||||
}
|
||||
|
||||
func prepareUserAttributes(header http.Header) map[string]string {
|
||||
filtered := filterHeaders(header)
|
||||
delete(filtered, container.AttributeName)
|
||||
|
|
|
@ -219,6 +219,10 @@ func NewString(val string) *string {
|
|||
return &val
|
||||
}
|
||||
|
||||
func NewInteger(val int64) *int64 {
|
||||
return &val
|
||||
}
|
||||
|
||||
func NewError(err error) models.Error {
|
||||
return models.Error(err.Error())
|
||||
}
|
||||
|
|
|
@ -168,13 +168,12 @@ paths:
|
|||
$ref: '#/definitions/Error'
|
||||
|
||||
/containers:
|
||||
parameters:
|
||||
- $ref: '#/parameters/signatureParam'
|
||||
- $ref: '#/parameters/signatureKeyParam'
|
||||
put:
|
||||
operationId: putContainer
|
||||
summary: Create new container in NeoFS
|
||||
parameters:
|
||||
- $ref: '#/parameters/signatureParam'
|
||||
- $ref: '#/parameters/signatureKeyParam'
|
||||
- in: query
|
||||
name: skip-native-name
|
||||
description: Provide this parameter to skip registration container name in NNS service
|
||||
|
@ -215,6 +214,38 @@ paths:
|
|||
description: Bad request
|
||||
schema:
|
||||
$ref: '#/definitions/Error'
|
||||
get:
|
||||
operationId: listContainers
|
||||
summary: Get list of containers
|
||||
security: [ ]
|
||||
parameters:
|
||||
- in: query
|
||||
name: ownerId
|
||||
required: true
|
||||
type: string
|
||||
description: Base58 encoded owner id
|
||||
- in: query
|
||||
name: offset
|
||||
type: integer
|
||||
default: 0
|
||||
minimum: 0
|
||||
description: The number of containers to skip before starting to collect the result set.
|
||||
- in: query
|
||||
name: limit
|
||||
type: integer
|
||||
default: 100
|
||||
minimum: 1
|
||||
maximum: 10000
|
||||
description: The numbers of containers to return.
|
||||
responses:
|
||||
200:
|
||||
description: Containers info
|
||||
schema:
|
||||
$ref: '#/definitions/ContainerList'
|
||||
400:
|
||||
description: Bad request
|
||||
schema:
|
||||
$ref: '#/definitions/Error'
|
||||
|
||||
/containers/{containerId}:
|
||||
parameters:
|
||||
|
@ -457,6 +488,27 @@ definitions:
|
|||
value: "1648810072"
|
||||
- key: Name
|
||||
value: container
|
||||
ContainerList:
|
||||
type: object
|
||||
properties:
|
||||
size:
|
||||
type: integer
|
||||
containers:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/ContainerBaseInfo'
|
||||
required:
|
||||
- size
|
||||
- containers
|
||||
ContainerBaseInfo:
|
||||
type: object
|
||||
properties:
|
||||
containerId:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
required:
|
||||
- containerId
|
||||
ObjectInfo:
|
||||
type: object
|
||||
properties:
|
||||
|
|
Reference in a new issue