[#25] Synchronize container get and put params
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
bacf909594
commit
665bcfb52d
9 changed files with 270 additions and 164 deletions
|
@ -322,7 +322,7 @@ func mixTokens(ctx context.Context, t *testing.T, cnrID cid.ID) {
|
||||||
func checkPutContainerWithError(t *testing.T, httpClient *http.Client, token *handlers.BearerToken) {
|
func checkPutContainerWithError(t *testing.T, httpClient *http.Client, token *handlers.BearerToken) {
|
||||||
reqURL, err := url.Parse(testHost + "/v1/containers")
|
reqURL, err := url.Parse(testHost + "/v1/containers")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
body, err := json.Marshal(&operations.PutContainerBody{ContainerName: "container"})
|
body, err := json.Marshal(&models.ContainerPutInfo{ContainerName: "container"})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
request, err := http.NewRequest(http.MethodPut, reqURL.String(), bytes.NewReader(body))
|
request, err := http.NewRequest(http.MethodPut, reqURL.String(), bytes.NewReader(body))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -692,6 +692,7 @@ func restContainerGet(ctx context.Context, t *testing.T, owner user.ID, cnrID ci
|
||||||
|
|
||||||
require.Equal(t, cnrID.EncodeToString(), *cnrInfo.ContainerID)
|
require.Equal(t, cnrID.EncodeToString(), *cnrInfo.ContainerID)
|
||||||
require.Equal(t, owner.EncodeToString(), *cnrInfo.OwnerID)
|
require.Equal(t, owner.EncodeToString(), *cnrInfo.OwnerID)
|
||||||
|
require.Equal(t, containerName, *cnrInfo.ContainerName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func restContainerDelete(ctx context.Context, t *testing.T, clientPool *pool.Pool, owner user.ID) {
|
func restContainerDelete(ctx context.Context, t *testing.T, clientPool *pool.Pool, owner user.ID) {
|
||||||
|
@ -953,7 +954,7 @@ func restContainerPutInvalid(ctx context.Context, t *testing.T) {
|
||||||
query.Add(walletConnectQuery, strconv.FormatBool(useWalletConnect))
|
query.Add(walletConnectQuery, strconv.FormatBool(useWalletConnect))
|
||||||
reqURL.RawQuery = query.Encode()
|
reqURL.RawQuery = query.Encode()
|
||||||
|
|
||||||
body, err := json.Marshal(&operations.PutContainerBody{ContainerName: "nameWithCapitalLetters"})
|
body, err := json.Marshal(&models.ContainerPutInfo{ContainerName: "nameWithCapitalLetters"})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
request, err := http.NewRequest(http.MethodPut, reqURL.String(), bytes.NewReader(body))
|
request, err := http.NewRequest(http.MethodPut, reqURL.String(), bytes.NewReader(body))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -982,7 +983,7 @@ func restContainerPut(ctx context.Context, t *testing.T, clientPool *pool.Pool)
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to create container without name but with name-scope-global
|
// try to create container without name but with name-scope-global
|
||||||
body, err := json.Marshal(&operations.PutContainerBody{})
|
body, err := json.Marshal(&models.ContainerPutInfo{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
reqURL, err := url.Parse(testHost + "/v1/containers")
|
reqURL, err := url.Parse(testHost + "/v1/containers")
|
||||||
|
@ -999,7 +1000,13 @@ func restContainerPut(ctx context.Context, t *testing.T, clientPool *pool.Pool)
|
||||||
doRequest(t, httpClient, request, http.StatusBadRequest, nil)
|
doRequest(t, httpClient, request, http.StatusBadRequest, nil)
|
||||||
|
|
||||||
// create container with name in local scope
|
// create container with name in local scope
|
||||||
body, err = json.Marshal(&operations.PutContainerBody{})
|
containerPutInfo := &models.ContainerPutInfo{
|
||||||
|
Attributes: []*models.Attribute{{
|
||||||
|
Key: util.NewString(attrKey),
|
||||||
|
Value: util.NewString(attrValue),
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
body, err = json.Marshal(containerPutInfo)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
reqURL, err = url.Parse(testHost + "/v1/containers")
|
reqURL, err = url.Parse(testHost + "/v1/containers")
|
||||||
|
@ -1011,7 +1018,6 @@ func restContainerPut(ctx context.Context, t *testing.T, clientPool *pool.Pool)
|
||||||
request, err = http.NewRequest(http.MethodPut, reqURL.String(), bytes.NewReader(body))
|
request, err = http.NewRequest(http.MethodPut, reqURL.String(), bytes.NewReader(body))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
prepareCommonHeaders(request.Header, bearerToken)
|
prepareCommonHeaders(request.Header, bearerToken)
|
||||||
request.Header.Add("X-Attribute-"+attrKey, attrValue)
|
|
||||||
|
|
||||||
addr := &operations.PutContainerOKBody{}
|
addr := &operations.PutContainerOKBody{}
|
||||||
doRequest(t, httpClient, request, http.StatusOK, addr)
|
doRequest(t, httpClient, request, http.StatusOK, addr)
|
||||||
|
|
|
@ -33,6 +33,10 @@ type ContainerInfo struct {
|
||||||
// Required: true
|
// Required: true
|
||||||
ContainerID *string `json:"containerId"`
|
ContainerID *string `json:"containerId"`
|
||||||
|
|
||||||
|
// container name
|
||||||
|
// Required: true
|
||||||
|
ContainerName *string `json:"containerName"`
|
||||||
|
|
||||||
// owner Id
|
// owner Id
|
||||||
// Required: true
|
// Required: true
|
||||||
OwnerID *string `json:"ownerId"`
|
OwnerID *string `json:"ownerId"`
|
||||||
|
@ -62,6 +66,10 @@ func (m *ContainerInfo) Validate(formats strfmt.Registry) error {
|
||||||
res = append(res, err)
|
res = append(res, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := m.validateContainerName(formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := m.validateOwnerID(formats); err != nil {
|
if err := m.validateOwnerID(formats); err != nil {
|
||||||
res = append(res, err)
|
res = append(res, err)
|
||||||
}
|
}
|
||||||
|
@ -125,6 +133,15 @@ func (m *ContainerInfo) validateContainerID(formats strfmt.Registry) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *ContainerInfo) validateContainerName(formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
if err := validate.Required("containerName", "body", m.ContainerName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *ContainerInfo) validateOwnerID(formats strfmt.Registry) error {
|
func (m *ContainerInfo) validateOwnerID(formats strfmt.Registry) error {
|
||||||
|
|
||||||
if err := validate.Required("ownerId", "body", m.OwnerID); err != nil {
|
if err := validate.Required("ownerId", "body", m.OwnerID); err != nil {
|
||||||
|
|
126
gen/models/container_put_info.go
Normal file
126
gen/models/container_put_info.go
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
// 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ContainerPutInfo Represent request body to create container. To specify container name use appropriate property (name provided in attributes will be ignored).
|
||||||
|
// Example: {"attributes":[{"key":"Custom-Attribute","value":"value"}],"basicAcl":"public-read-write","containerName":"container","placementPolicy":"REP 3"}
|
||||||
|
//
|
||||||
|
// swagger:model ContainerPutInfo
|
||||||
|
type ContainerPutInfo struct {
|
||||||
|
|
||||||
|
// attributes
|
||||||
|
Attributes []*Attribute `json:"attributes"`
|
||||||
|
|
||||||
|
// basic Acl
|
||||||
|
BasicACL string `json:"basicAcl,omitempty"`
|
||||||
|
|
||||||
|
// container name
|
||||||
|
ContainerName string `json:"containerName,omitempty"`
|
||||||
|
|
||||||
|
// placement policy
|
||||||
|
PlacementPolicy string `json:"placementPolicy,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates this container put info
|
||||||
|
func (m *ContainerPutInfo) Validate(formats strfmt.Registry) error {
|
||||||
|
var res []error
|
||||||
|
|
||||||
|
if err := m.validateAttributes(formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(res) > 0 {
|
||||||
|
return errors.CompositeValidationError(res...)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ContainerPutInfo) validateAttributes(formats strfmt.Registry) error {
|
||||||
|
if swag.IsZero(m.Attributes) { // not required
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(m.Attributes); i++ {
|
||||||
|
if swag.IsZero(m.Attributes[i]) { // not required
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Attributes[i] != nil {
|
||||||
|
if err := m.Attributes[i].Validate(formats); err != nil {
|
||||||
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
|
return ve.ValidateName("attributes" + "." + strconv.Itoa(i))
|
||||||
|
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||||
|
return ce.ValidateName("attributes" + "." + strconv.Itoa(i))
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContextValidate validate this container put info based on the context it is used
|
||||||
|
func (m *ContainerPutInfo) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||||
|
var res []error
|
||||||
|
|
||||||
|
if err := m.contextValidateAttributes(ctx, formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(res) > 0 {
|
||||||
|
return errors.CompositeValidationError(res...)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ContainerPutInfo) contextValidateAttributes(ctx context.Context, formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
for i := 0; i < len(m.Attributes); i++ {
|
||||||
|
|
||||||
|
if m.Attributes[i] != nil {
|
||||||
|
if err := m.Attributes[i].ContextValidate(ctx, formats); err != nil {
|
||||||
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
|
return ve.ValidateName("attributes" + "." + strconv.Itoa(i))
|
||||||
|
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||||
|
return ce.ValidateName("attributes" + "." + strconv.Itoa(i))
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary interface implementation
|
||||||
|
func (m *ContainerPutInfo) MarshalBinary() ([]byte, error) {
|
||||||
|
if m == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return swag.WriteJSON(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary interface implementation
|
||||||
|
func (m *ContainerPutInfo) UnmarshalBinary(b []byte) error {
|
||||||
|
var res ContainerPutInfo
|
||||||
|
if err := swag.ReadJSON(b, &res); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*m = res
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -159,23 +159,7 @@ func init() {
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "object",
|
"$ref": "#/definitions/ContainerPutInfo"
|
||||||
"properties": {
|
|
||||||
"basicAcl": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"containerName": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"placementPolicy": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"example": {
|
|
||||||
"basicAcl": "public-read-write",
|
|
||||||
"containerName": "container",
|
|
||||||
"placementPolicy": "REP 3"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -574,6 +558,7 @@ func init() {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"containerId",
|
"containerId",
|
||||||
|
"containerName",
|
||||||
"version",
|
"version",
|
||||||
"ownerId",
|
"ownerId",
|
||||||
"basicAcl",
|
"basicAcl",
|
||||||
|
@ -593,6 +578,9 @@ func init() {
|
||||||
"containerId": {
|
"containerId": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"containerName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"ownerId": {
|
"ownerId": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -639,6 +627,38 @@ func init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ContainerPutInfo": {
|
||||||
|
"description": "Represent request body to create container. To specify container name use appropriate property (name provided in attributes will be ignored).",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"attributes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/Attribute"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"basicAcl": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"containerName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"placementPolicy": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"example": {
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"key": "Custom-Attribute",
|
||||||
|
"value": "value"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"basicAcl": "public-read-write",
|
||||||
|
"containerName": "container",
|
||||||
|
"placementPolicy": "REP 3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Eacl": {
|
"Eacl": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
@ -1252,23 +1272,7 @@ func init() {
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "object",
|
"$ref": "#/definitions/ContainerPutInfo"
|
||||||
"properties": {
|
|
||||||
"basicAcl": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"containerName": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"placementPolicy": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"example": {
|
|
||||||
"basicAcl": "public-read-write",
|
|
||||||
"containerName": "container",
|
|
||||||
"placementPolicy": "REP 3"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -1750,6 +1754,7 @@ func init() {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"containerId",
|
"containerId",
|
||||||
|
"containerName",
|
||||||
"version",
|
"version",
|
||||||
"ownerId",
|
"ownerId",
|
||||||
"basicAcl",
|
"basicAcl",
|
||||||
|
@ -1769,6 +1774,9 @@ func init() {
|
||||||
"containerId": {
|
"containerId": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"containerName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"ownerId": {
|
"ownerId": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -1815,6 +1823,38 @@ func init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ContainerPutInfo": {
|
||||||
|
"description": "Represent request body to create container. To specify container name use appropriate property (name provided in attributes will be ignored).",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"attributes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/Attribute"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"basicAcl": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"containerName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"placementPolicy": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"example": {
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"key": "Custom-Attribute",
|
||||||
|
"value": "value"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"basicAcl": "public-read-write",
|
||||||
|
"containerName": "container",
|
||||||
|
"placementPolicy": "REP 3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Eacl": {
|
"Eacl": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
@ -75,50 +75,6 @@ func (o *PutContainer) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutContainerBody put container body
|
|
||||||
// Example: {"basicAcl":"public-read-write","containerName":"container","placementPolicy":"REP 3"}
|
|
||||||
//
|
|
||||||
// swagger:model PutContainerBody
|
|
||||||
type PutContainerBody struct {
|
|
||||||
|
|
||||||
// basic Acl
|
|
||||||
BasicACL string `json:"basicAcl,omitempty"`
|
|
||||||
|
|
||||||
// container name
|
|
||||||
ContainerName string `json:"containerName,omitempty"`
|
|
||||||
|
|
||||||
// placement policy
|
|
||||||
PlacementPolicy string `json:"placementPolicy,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate validates this put container body
|
|
||||||
func (o *PutContainerBody) Validate(formats strfmt.Registry) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContextValidate validates this put container body based on context it is used
|
|
||||||
func (o *PutContainerBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalBinary interface implementation
|
|
||||||
func (o *PutContainerBody) MarshalBinary() ([]byte, error) {
|
|
||||||
if o == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return swag.WriteJSON(o)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalBinary interface implementation
|
|
||||||
func (o *PutContainerBody) UnmarshalBinary(b []byte) error {
|
|
||||||
var res PutContainerBody
|
|
||||||
if err := swag.ReadJSON(b, &res); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*o = res
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PutContainerOKBody put container o k body
|
// PutContainerOKBody put container o k body
|
||||||
// Example: {"containerId":"5HZTn5qkRnmgSz9gSrw22CEdPPk6nQhkwf2Mgzyvkikv"}
|
// Example: {"containerId":"5HZTn5qkRnmgSz9gSrw22CEdPPk6nQhkwf2Mgzyvkikv"}
|
||||||
//
|
//
|
||||||
|
|
|
@ -16,6 +16,8 @@ import (
|
||||||
"github.com/go-openapi/strfmt"
|
"github.com/go-openapi/strfmt"
|
||||||
"github.com/go-openapi/swag"
|
"github.com/go-openapi/swag"
|
||||||
"github.com/go-openapi/validate"
|
"github.com/go-openapi/validate"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neofs-rest-gw/gen/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewPutContainerParams creates a new PutContainerParams object
|
// NewPutContainerParams creates a new PutContainerParams object
|
||||||
|
@ -59,7 +61,7 @@ type PutContainerParams struct {
|
||||||
Required: true
|
Required: true
|
||||||
In: body
|
In: body
|
||||||
*/
|
*/
|
||||||
Container PutContainerBody
|
Container *models.ContainerPutInfo
|
||||||
/*Provide this parameter to register container name in NNS service
|
/*Provide this parameter to register container name in NNS service
|
||||||
In: query
|
In: query
|
||||||
Default: false
|
Default: false
|
||||||
|
@ -93,7 +95,7 @@ func (o *PutContainerParams) BindRequest(r *http.Request, route *middleware.Matc
|
||||||
|
|
||||||
if runtime.HasBody(r) {
|
if runtime.HasBody(r) {
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
var body PutContainerBody
|
var body models.ContainerPutInfo
|
||||||
if err := route.Consumer.Consume(r.Body, &body); err != nil {
|
if err := route.Consumer.Consume(r.Body, &body); err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
res = append(res, errors.Required("container", "body", ""))
|
res = append(res, errors.Required("container", "body", ""))
|
||||||
|
@ -112,7 +114,7 @@ func (o *PutContainerParams) BindRequest(r *http.Request, route *middleware.Matc
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(res) == 0 {
|
if len(res) == 0 {
|
||||||
o.Container = body
|
o.Container = &body
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -6,12 +6,12 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-openapi/runtime/middleware"
|
"github.com/go-openapi/runtime/middleware"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
containerv2 "github.com/nspcc-dev/neofs-api-go/v2/container"
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
sessionv2 "github.com/nspcc-dev/neofs-api-go/v2/session"
|
sessionv2 "github.com/nspcc-dev/neofs-api-go/v2/session"
|
||||||
"github.com/nspcc-dev/neofs-rest-gw/gen/models"
|
"github.com/nspcc-dev/neofs-rest-gw/gen/models"
|
||||||
|
@ -50,9 +50,7 @@ func (a *API) PutContainers(params operations.PutContainerParams, principal *mod
|
||||||
return operations.NewPutContainerBadRequest().WithPayload(resp)
|
return operations.NewPutContainerBadRequest().WithPayload(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
userAttributes := prepareUserAttributes(params.HTTPRequest.Header)
|
cnrID, err := createContainer(params.HTTPRequest.Context(), a.pool, stoken, ¶ms)
|
||||||
|
|
||||||
cnrID, err := createContainer(params.HTTPRequest.Context(), a.pool, stoken, ¶ms, userAttributes)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp := a.logAndGetErrorResponse("create container", err)
|
resp := a.logAndGetErrorResponse("create container", err)
|
||||||
return operations.NewPutContainerBadRequest().WithPayload(resp)
|
return operations.NewPutContainerBadRequest().WithPayload(resp)
|
||||||
|
@ -237,6 +235,7 @@ func getContainerInfo(ctx context.Context, p *pool.Pool, cnrID cid.ID) (*models.
|
||||||
|
|
||||||
return &models.ContainerInfo{
|
return &models.ContainerInfo{
|
||||||
ContainerID: util.NewString(cnrID.String()),
|
ContainerID: util.NewString(cnrID.String()),
|
||||||
|
ContainerName: util.NewString(container.Name(*cnr)),
|
||||||
OwnerID: util.NewString(cnr.Owner().String()),
|
OwnerID: util.NewString(cnr.Owner().String()),
|
||||||
BasicACL: util.NewString(cnr.BasicACL().EncodeToString()),
|
BasicACL: util.NewString(cnr.BasicACL().EncodeToString()),
|
||||||
PlacementPolicy: util.NewString(sb.String()),
|
PlacementPolicy: util.NewString(sb.String()),
|
||||||
|
@ -244,13 +243,6 @@ func getContainerInfo(ctx context.Context, p *pool.Pool, cnrID cid.ID) (*models.
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareUserAttributes(header http.Header) map[string]string {
|
|
||||||
filtered := filterHeaders(header)
|
|
||||||
delete(filtered, attributeName)
|
|
||||||
delete(filtered, attributeTimestamp)
|
|
||||||
return filtered
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseContainerID(containerID string) (cid.ID, error) {
|
func parseContainerID(containerID string) (cid.ID, error) {
|
||||||
var cnrID cid.ID
|
var cnrID cid.ID
|
||||||
if err := cnrID.DecodeString(containerID); err != nil {
|
if err := cnrID.DecodeString(containerID); err != nil {
|
||||||
|
@ -300,7 +292,7 @@ func getContainerEACL(ctx context.Context, p *pool.Pool, cnrID cid.ID) (*models.
|
||||||
return tableResp, nil
|
return tableResp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createContainer(ctx context.Context, p *pool.Pool, stoken session.Container, params *operations.PutContainerParams, userAttrs map[string]string) (cid.ID, error) {
|
func createContainer(ctx context.Context, p *pool.Pool, stoken session.Container, params *operations.PutContainerParams) (cid.ID, error) {
|
||||||
request := params.Container
|
request := params.Container
|
||||||
|
|
||||||
if request.PlacementPolicy == "" {
|
if request.PlacementPolicy == "" {
|
||||||
|
@ -333,8 +325,13 @@ func createContainer(ctx context.Context, p *pool.Pool, stoken session.Container
|
||||||
container.SetName(&cnr, request.ContainerName)
|
container.SetName(&cnr, request.ContainerName)
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, val := range userAttrs {
|
for _, attr := range request.Attributes {
|
||||||
cnr.SetAttribute(key, val)
|
switch *attr.Key {
|
||||||
|
case attributeName, attributeTimestamp,
|
||||||
|
containerv2.SysAttributeName, containerv2.SysAttributeZone:
|
||||||
|
default:
|
||||||
|
cnr.SetAttribute(*attr.Key, *attr.Value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if *params.NameScopeGlobal { // we don't check for nil because there is default false value
|
if *params.NameScopeGlobal { // we don't check for nil because there is default false value
|
||||||
|
|
|
@ -3,9 +3,7 @@ package handlers
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
objectv2 "github.com/nspcc-dev/neofs-api-go/v2/object"
|
objectv2 "github.com/nspcc-dev/neofs-api-go/v2/object"
|
||||||
|
@ -27,7 +25,6 @@ type epochDurations struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
UserAttributeHeaderPrefix = "X-Attribute-"
|
|
||||||
SystemAttributePrefix = "__NEOFS__"
|
SystemAttributePrefix = "__NEOFS__"
|
||||||
|
|
||||||
ExpirationDurationAttr = SystemAttributePrefix + "EXPIRATION_DURATION"
|
ExpirationDurationAttr = SystemAttributePrefix + "EXPIRATION_DURATION"
|
||||||
|
@ -35,54 +32,6 @@ const (
|
||||||
ExpirationRFC3339Attr = SystemAttributePrefix + "EXPIRATION_RFC3339"
|
ExpirationRFC3339Attr = SystemAttributePrefix + "EXPIRATION_RFC3339"
|
||||||
)
|
)
|
||||||
|
|
||||||
var neofsAttributeHeaderPrefixes = [...]string{"Neofs-", "NEOFS-", "neofs-"}
|
|
||||||
|
|
||||||
func systemTranslator(key, prefix string) string {
|
|
||||||
// replace specified prefix with `__NEOFS__`
|
|
||||||
key = strings.Replace(key, prefix, SystemAttributePrefix, 1)
|
|
||||||
|
|
||||||
// replace `-` with `_`
|
|
||||||
key = strings.ReplaceAll(key, "-", "_")
|
|
||||||
|
|
||||||
// replace with uppercase
|
|
||||||
return strings.ToUpper(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func filterHeaders(header http.Header) map[string]string {
|
|
||||||
result := make(map[string]string)
|
|
||||||
prefix := UserAttributeHeaderPrefix
|
|
||||||
|
|
||||||
for key, vals := range header {
|
|
||||||
if len(key) == 0 || len(vals) == 0 || len(vals[0]) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// checks that key has attribute prefix
|
|
||||||
if !strings.HasPrefix(key, prefix) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// removing attribute prefix
|
|
||||||
key = strings.TrimPrefix(key, prefix)
|
|
||||||
|
|
||||||
// checks that it's a system NeoFS header
|
|
||||||
for _, system := range neofsAttributeHeaderPrefixes {
|
|
||||||
if strings.HasPrefix(key, system) {
|
|
||||||
key = systemTranslator(key, system)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// checks that attribute key not empty
|
|
||||||
if len(key) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
result[key] = vals[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetObjectAttributes forms object attributes from request headers.
|
// GetObjectAttributes forms object attributes from request headers.
|
||||||
func GetObjectAttributes(ctx context.Context, pool *pool.Pool, attrs []*models.Attribute, prm PrmAttributes) ([]object.Attribute, error) {
|
func GetObjectAttributes(ctx context.Context, pool *pool.Pool, attrs []*models.Attribute, prm PrmAttributes) ([]object.Attribute, error) {
|
||||||
headers := make(map[string]string, len(attrs))
|
headers := make(map[string]string, len(attrs))
|
||||||
|
|
|
@ -229,18 +229,7 @@ paths:
|
||||||
required: true
|
required: true
|
||||||
description: Container info
|
description: Container info
|
||||||
schema:
|
schema:
|
||||||
type: object
|
$ref: '#/definitions/ContainerPutInfo'
|
||||||
properties:
|
|
||||||
containerName:
|
|
||||||
type: string
|
|
||||||
placementPolicy:
|
|
||||||
type: string
|
|
||||||
basicAcl:
|
|
||||||
type: string
|
|
||||||
example:
|
|
||||||
containerName: container
|
|
||||||
placementPolicy: "REP 3"
|
|
||||||
basicAcl: public-read-write
|
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: Address of uploaded objects
|
description: Address of uploaded objects
|
||||||
|
@ -506,11 +495,34 @@ definitions:
|
||||||
enum:
|
enum:
|
||||||
- object
|
- object
|
||||||
- container
|
- container
|
||||||
|
ContainerPutInfo:
|
||||||
|
description: Represent request body to create container. To specify container name use appropriate property (name provided in attributes will be ignored).
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
containerName:
|
||||||
|
type: string
|
||||||
|
placementPolicy:
|
||||||
|
type: string
|
||||||
|
basicAcl:
|
||||||
|
type: string
|
||||||
|
attributes:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/Attribute'
|
||||||
|
example:
|
||||||
|
containerName: container
|
||||||
|
placementPolicy: "REP 3"
|
||||||
|
basicAcl: public-read-write
|
||||||
|
attributes:
|
||||||
|
- key: Custom-Attribute
|
||||||
|
value: value
|
||||||
ContainerInfo:
|
ContainerInfo:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
containerId:
|
containerId:
|
||||||
type: string
|
type: string
|
||||||
|
containerName:
|
||||||
|
type: string
|
||||||
version:
|
version:
|
||||||
type: string
|
type: string
|
||||||
ownerId:
|
ownerId:
|
||||||
|
@ -525,6 +537,7 @@ definitions:
|
||||||
$ref: '#/definitions/Attribute'
|
$ref: '#/definitions/Attribute'
|
||||||
required:
|
required:
|
||||||
- containerId
|
- containerId
|
||||||
|
- containerName
|
||||||
- version
|
- version
|
||||||
- ownerId
|
- ownerId
|
||||||
- basicAcl
|
- basicAcl
|
||||||
|
|
Reference in a new issue