forked from TrueCloudLab/frostfs-rest-gw
[#1] Add route to delete container
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
066656ac48
commit
63fdb08f14
12 changed files with 637 additions and 96 deletions
|
@ -13,6 +13,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -55,7 +56,13 @@ const (
|
||||||
func TestIntegration(t *testing.T) {
|
func TestIntegration(t *testing.T) {
|
||||||
rootCtx := context.Background()
|
rootCtx := context.Background()
|
||||||
aioImage := "nspccdev/neofs-aio-testcontainer:"
|
aioImage := "nspccdev/neofs-aio-testcontainer:"
|
||||||
versions := []string{"0.24.0", "0.25.1", "0.27.5", "latest"}
|
versions := []string{
|
||||||
|
"0.24.0",
|
||||||
|
"0.25.1",
|
||||||
|
"0.26.1",
|
||||||
|
"0.27.5",
|
||||||
|
"latest",
|
||||||
|
}
|
||||||
key, err := keys.NewPrivateKeyFromHex(devenvPrivateKey)
|
key, err := keys.NewPrivateKeyFromHex(devenvPrivateKey)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
@ -65,12 +72,13 @@ func TestIntegration(t *testing.T) {
|
||||||
aioContainer := createDockerContainer(ctx, t, aioImage+version)
|
aioContainer := createDockerContainer(ctx, t, aioImage+version)
|
||||||
cancel := runServer(ctx, t)
|
cancel := runServer(ctx, t)
|
||||||
clientPool := getPool(ctx, t, key)
|
clientPool := getPool(ctx, t, key)
|
||||||
CID, err := createContainer(ctx, t, clientPool)
|
cnrID := createContainer(ctx, t, clientPool, "test-container")
|
||||||
require.NoError(t, err, version)
|
|
||||||
|
t.Run("rest put object "+version, func(t *testing.T) { restObjectPut(ctx, t, clientPool, cnrID) })
|
||||||
|
|
||||||
t.Run("rest put object "+version, func(t *testing.T) { restObjectPut(ctx, t, clientPool, CID) })
|
|
||||||
t.Run("rest put container"+version, func(t *testing.T) { restContainerPut(ctx, t, clientPool) })
|
t.Run("rest put container"+version, func(t *testing.T) { restContainerPut(ctx, t, clientPool) })
|
||||||
t.Run("rest get container"+version, func(t *testing.T) { restContainerGet(ctx, t, clientPool, CID) })
|
t.Run("rest get container"+version, func(t *testing.T) { restContainerGet(ctx, t, clientPool, cnrID) })
|
||||||
|
t.Run("rest delete container"+version, func(t *testing.T) { restContainerDelete(ctx, t, clientPool) })
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
err = aioContainer.Terminate(ctx)
|
err = aioContainer.Terminate(ctx)
|
||||||
|
@ -132,6 +140,7 @@ func getDefaultConfig() *viper.Viper {
|
||||||
v.SetDefault(cfgPeers+".0.weight", 1)
|
v.SetDefault(cfgPeers+".0.weight", 1)
|
||||||
v.SetDefault(cfgPeers+".0.priority", 1)
|
v.SetDefault(cfgPeers+".0.priority", 1)
|
||||||
v.SetDefault(restapi.FlagListenAddress, testListenAddress)
|
v.SetDefault(restapi.FlagListenAddress, testListenAddress)
|
||||||
|
v.SetDefault(restapi.FlagWriteTimeout, 60*time.Second)
|
||||||
|
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
@ -292,8 +301,98 @@ func restContainerGet(ctx context.Context, t *testing.T, clientPool *pool.Pool,
|
||||||
err = json.NewDecoder(resp.Body).Decode(cnrInfo)
|
err = json.NewDecoder(resp.Body).Decode(cnrInfo)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Equal(t, cnrID.String(), cnrInfo.ContainerID)
|
require.Equal(t, cnrID.String(), *cnrInfo.ContainerID)
|
||||||
require.Equal(t, clientPool.OwnerID().String(), cnrInfo.OwnerID)
|
require.Equal(t, clientPool.OwnerID().String(), *cnrInfo.OwnerID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func restContainerDelete(ctx context.Context, t *testing.T, clientPool *pool.Pool) {
|
||||||
|
cnrID := createContainer(ctx, t, clientPool, "for-delete")
|
||||||
|
|
||||||
|
bearer := &models.Bearer{
|
||||||
|
Container: &models.Rule{
|
||||||
|
Verb: models.NewVerb(models.VerbDELETE),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
httpClient := &http.Client{Timeout: 60 * time.Second}
|
||||||
|
|
||||||
|
bearerToken := makeAuthContainerTokenRequest(ctx, t, bearer, httpClient)
|
||||||
|
|
||||||
|
request, err := http.NewRequest(http.MethodDelete, testHost+"/v1/containers/"+cnrID.String(), nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
request = request.WithContext(ctx)
|
||||||
|
prepareBearerHeaders(request.Header, bearerToken)
|
||||||
|
|
||||||
|
resp, err := httpClient.Do(request)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer func() {
|
||||||
|
err := resp.Body.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
|
}()
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
fmt.Println("resp")
|
||||||
|
}
|
||||||
|
require.Equal(t, http.StatusNoContent, resp.StatusCode)
|
||||||
|
|
||||||
|
var prm pool.PrmContainerGet
|
||||||
|
prm.SetContainerID(*cnrID)
|
||||||
|
|
||||||
|
_, err = clientPool.GetContainer(ctx, prm)
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Contains(t, err.Error(), "not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeAuthContainerTokenRequest(ctx context.Context, t *testing.T, bearer *models.Bearer, httpClient *http.Client) *handlers.BearerToken {
|
||||||
|
key, err := keys.NewPrivateKeyFromHex(devenvPrivateKey)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
hexPubKey := hex.EncodeToString(key.PublicKey().Bytes())
|
||||||
|
|
||||||
|
data, err := json.Marshal(bearer)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
request, err := http.NewRequest(http.MethodPost, testHost+"/v1/auth", bytes.NewReader(data))
|
||||||
|
require.NoError(t, err)
|
||||||
|
request = request.WithContext(ctx)
|
||||||
|
request.Header.Add("Content-Type", "application/json")
|
||||||
|
request.Header.Add(XNeofsTokenScope, string(models.TokenTypeContainer))
|
||||||
|
request.Header.Add(XNeofsTokenSignatureKey, hexPubKey)
|
||||||
|
|
||||||
|
resp, err := httpClient.Do(request)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer func() {
|
||||||
|
err := resp.Body.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
|
}()
|
||||||
|
|
||||||
|
rr, err := io.ReadAll(resp.Body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
fmt.Println("auth response", string(rr))
|
||||||
|
}
|
||||||
|
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
|
|
||||||
|
stokenResp := &models.TokenResponse{}
|
||||||
|
err = json.Unmarshal(rr, stokenResp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, *stokenResp.Type, models.TokenTypeContainer)
|
||||||
|
|
||||||
|
binaryData, err := base64.StdEncoding.DecodeString(*stokenResp.Token)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
signatureData := signData(t, key, binaryData)
|
||||||
|
signature := base64.StdEncoding.EncodeToString(signatureData)
|
||||||
|
|
||||||
|
bt := handlers.BearerToken{
|
||||||
|
Token: *stokenResp.Token,
|
||||||
|
Signature: signature,
|
||||||
|
Key: hexPubKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("container token:\n%+v\n", bt)
|
||||||
|
return &bt
|
||||||
}
|
}
|
||||||
|
|
||||||
func signData(t *testing.T, key *keys.PrivateKey, data []byte) []byte {
|
func signData(t *testing.T, key *keys.PrivateKey, data []byte) []byte {
|
||||||
|
@ -304,48 +403,15 @@ func signData(t *testing.T, key *keys.PrivateKey, data []byte) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func restContainerPut(ctx context.Context, t *testing.T, clientPool *pool.Pool) {
|
func restContainerPut(ctx context.Context, t *testing.T, clientPool *pool.Pool) {
|
||||||
key, err := keys.NewPrivateKeyFromHex(devenvPrivateKey)
|
bearer := &models.Bearer{
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
b := models.Bearer{
|
|
||||||
Container: &models.Rule{
|
Container: &models.Rule{
|
||||||
Verb: models.NewVerb(models.VerbPUT),
|
Verb: models.NewVerb(models.VerbPUT),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := json.Marshal(&b)
|
httpClient := &http.Client{Timeout: 30 * time.Second}
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
request0, err := http.NewRequest(http.MethodPost, testHost+"/v1/auth", bytes.NewReader(data))
|
bearerToken := makeAuthContainerTokenRequest(ctx, t, bearer, httpClient)
|
||||||
require.NoError(t, err)
|
|
||||||
request0.Header.Add("Content-Type", "application/json")
|
|
||||||
request0.Header.Add(XNeofsTokenScope, "container")
|
|
||||||
request0.Header.Add(XNeofsTokenSignatureKey, hex.EncodeToString(key.PublicKey().Bytes()))
|
|
||||||
|
|
||||||
httpClient := http.Client{
|
|
||||||
Timeout: 30 * time.Second,
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := httpClient.Do(request0)
|
|
||||||
require.NoError(t, err)
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
rr, err := io.ReadAll(resp.Body)
|
|
||||||
require.NoError(t, err)
|
|
||||||
fmt.Println(string(rr))
|
|
||||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
|
||||||
|
|
||||||
stokenResp := &models.TokenResponse{}
|
|
||||||
err = json.Unmarshal(rr, stokenResp)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
require.Equal(t, *stokenResp.Type, models.TokenTypeContainer)
|
|
||||||
|
|
||||||
bearerBase64 := stokenResp.Token
|
|
||||||
binaryData, err := base64.StdEncoding.DecodeString(*bearerBase64)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
signatureData := signData(t, key, binaryData)
|
|
||||||
|
|
||||||
attrKey, attrValue := "User-Attribute", "user value"
|
attrKey, attrValue := "User-Attribute", "user value"
|
||||||
|
|
||||||
|
@ -360,15 +426,18 @@ func restContainerPut(ctx context.Context, t *testing.T, clientPool *pool.Pool)
|
||||||
body, err := json.Marshal(&req)
|
body, err := json.Marshal(&req)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
fmt.Println(base64.StdEncoding.EncodeToString(signatureData))
|
reqURL, err := url.Parse(testHost + "/v1/containers")
|
||||||
fmt.Println(hex.EncodeToString(key.PublicKey().Bytes()))
|
require.NoError(t, err)
|
||||||
|
|
||||||
request, err := http.NewRequest(http.MethodPut, testHost+"/v1/containers", bytes.NewReader(body))
|
query := reqURL.Query()
|
||||||
|
query.Add("skip-native-name", "true")
|
||||||
|
|
||||||
|
reqURL.RawQuery = query.Encode()
|
||||||
|
|
||||||
|
request, err := http.NewRequest(http.MethodPut, reqURL.String(), bytes.NewReader(body))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
request.Header.Add("Content-Type", "application/json")
|
request.Header.Add("Content-Type", "application/json")
|
||||||
request.Header.Add(XNeofsTokenSignature, base64.StdEncoding.EncodeToString(signatureData))
|
prepareBearerHeaders(request.Header, bearerToken)
|
||||||
request.Header.Add("Authorization", "Bearer "+*bearerBase64)
|
|
||||||
request.Header.Add(XNeofsTokenSignatureKey, hex.EncodeToString(key.PublicKey().Bytes()))
|
|
||||||
request.Header.Add("X-Attribute-"+attrKey, attrValue)
|
request.Header.Add("X-Attribute-"+attrKey, attrValue)
|
||||||
|
|
||||||
resp2, err := httpClient.Do(request)
|
resp2, err := httpClient.Do(request)
|
||||||
|
@ -406,14 +475,20 @@ func restContainerPut(ctx context.Context, t *testing.T, clientPool *pool.Pool)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createContainer(ctx context.Context, t *testing.T, clientPool *pool.Pool) (*cid.ID, error) {
|
func prepareBearerHeaders(header http.Header, bearerToken *handlers.BearerToken) {
|
||||||
|
header.Add(XNeofsTokenSignature, bearerToken.Signature)
|
||||||
|
header.Add("Authorization", "Bearer "+bearerToken.Token)
|
||||||
|
header.Add(XNeofsTokenSignatureKey, bearerToken.Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createContainer(ctx context.Context, t *testing.T, clientPool *pool.Pool, name string) *cid.ID {
|
||||||
pp, err := policy.Parse("REP 1")
|
pp, err := policy.Parse("REP 1")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
cnr := container.New(
|
cnr := container.New(
|
||||||
container.WithPolicy(pp),
|
container.WithPolicy(pp),
|
||||||
container.WithCustomBasicACL(0x0FFFFFFF),
|
container.WithCustomBasicACL(0x0FFFFFFF),
|
||||||
container.WithAttribute(container.AttributeName, "friendlyName"),
|
container.WithAttribute(container.AttributeName, name),
|
||||||
container.WithAttribute(container.AttributeTimestamp, strconv.FormatInt(time.Now().Unix(), 10)))
|
container.WithAttribute(container.AttributeTimestamp, strconv.FormatInt(time.Now().Unix(), 10)))
|
||||||
cnr.SetOwnerID(clientPool.OwnerID())
|
cnr.SetOwnerID(clientPool.OwnerID())
|
||||||
|
|
||||||
|
@ -426,12 +501,9 @@ func createContainer(ctx context.Context, t *testing.T, clientPool *pool.Pool) (
|
||||||
prm.SetWaitParams(waitPrm)
|
prm.SetWaitParams(waitPrm)
|
||||||
|
|
||||||
CID, err := clientPool.PutContainer(ctx, prm)
|
CID, err := clientPool.PutContainer(ctx, prm)
|
||||||
if err != nil {
|
require.NoError(t, err)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
fmt.Println(CID.String())
|
|
||||||
|
|
||||||
return CID, err
|
return CID
|
||||||
}
|
}
|
||||||
|
|
||||||
func restrictByEACL(ctx context.Context, t *testing.T, clientPool *pool.Pool, cnrID *cid.ID) {
|
func restrictByEACL(ctx context.Context, t *testing.T, clientPool *pool.Pool, cnrID *cid.ID) {
|
||||||
|
|
|
@ -98,6 +98,13 @@ func init() {
|
||||||
"summary": "Create new container in NeoFS",
|
"summary": "Create new container in NeoFS",
|
||||||
"operationId": "putContainer",
|
"operationId": "putContainer",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Provide this parameter to skip registration container name in NNS service",
|
||||||
|
"name": "skip-native-name",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Container info",
|
"description": "Container info",
|
||||||
"name": "container",
|
"name": "container",
|
||||||
|
@ -167,15 +174,6 @@ func init() {
|
||||||
"security": [],
|
"security": [],
|
||||||
"summary": "Get container by id",
|
"summary": "Get container by id",
|
||||||
"operationId": "getContainer",
|
"operationId": "getContainer",
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Base58 encoded container id",
|
|
||||||
"name": "containerId",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "Container info",
|
"description": "Container info",
|
||||||
|
@ -190,7 +188,39 @@ func init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"delete": {
|
||||||
|
"summary": "Delete container by id",
|
||||||
|
"operationId": "deleteContainer",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"$ref": "#/parameters/signatureParam"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/parameters/signatureKeyParam"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "Successul deletion"
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Base58 encoded container id",
|
||||||
|
"name": "containerId",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"/objects": {
|
"/objects": {
|
||||||
"put": {
|
"put": {
|
||||||
|
@ -745,6 +775,13 @@ func init() {
|
||||||
"summary": "Create new container in NeoFS",
|
"summary": "Create new container in NeoFS",
|
||||||
"operationId": "putContainer",
|
"operationId": "putContainer",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Provide this parameter to skip registration container name in NNS service",
|
||||||
|
"name": "skip-native-name",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Container info",
|
"description": "Container info",
|
||||||
"name": "container",
|
"name": "container",
|
||||||
|
@ -822,15 +859,6 @@ func init() {
|
||||||
"security": [],
|
"security": [],
|
||||||
"summary": "Get container by id",
|
"summary": "Get container by id",
|
||||||
"operationId": "getContainer",
|
"operationId": "getContainer",
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Base58 encoded container id",
|
|
||||||
"name": "containerId",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "Container info",
|
"description": "Container info",
|
||||||
|
@ -845,7 +873,47 @@ func init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"delete": {
|
||||||
|
"summary": "Delete container by id",
|
||||||
|
"operationId": "deleteContainer",
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "Successul deletion"
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Base58 encoded container id",
|
||||||
|
"name": "containerId",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"/objects": {
|
"/objects": {
|
||||||
"put": {
|
"put": {
|
||||||
|
|
71
gen/restapi/operations/delete_container.go
Normal file
71
gen/restapi/operations/delete_container.go
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
// 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"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neofs-rest-gw/gen/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeleteContainerHandlerFunc turns a function with the right signature into a delete container handler
|
||||||
|
type DeleteContainerHandlerFunc func(DeleteContainerParams, *models.Principal) middleware.Responder
|
||||||
|
|
||||||
|
// Handle executing the request and returning a response
|
||||||
|
func (fn DeleteContainerHandlerFunc) Handle(params DeleteContainerParams, principal *models.Principal) middleware.Responder {
|
||||||
|
return fn(params, principal)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteContainerHandler interface for that can handle valid delete container params
|
||||||
|
type DeleteContainerHandler interface {
|
||||||
|
Handle(DeleteContainerParams, *models.Principal) middleware.Responder
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDeleteContainer creates a new http.Handler for the delete container operation
|
||||||
|
func NewDeleteContainer(ctx *middleware.Context, handler DeleteContainerHandler) *DeleteContainer {
|
||||||
|
return &DeleteContainer{Context: ctx, Handler: handler}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DeleteContainer swagger:route DELETE /containers/{containerId} deleteContainer
|
||||||
|
|
||||||
|
Delete container by id
|
||||||
|
|
||||||
|
*/
|
||||||
|
type DeleteContainer struct {
|
||||||
|
Context *middleware.Context
|
||||||
|
Handler DeleteContainerHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *DeleteContainer) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
route, rCtx, _ := o.Context.RouteInfo(r)
|
||||||
|
if rCtx != nil {
|
||||||
|
*r = *rCtx
|
||||||
|
}
|
||||||
|
var Params = NewDeleteContainerParams()
|
||||||
|
uprinc, aCtx, err := o.Context.Authorize(r, route)
|
||||||
|
if err != nil {
|
||||||
|
o.Context.Respond(rw, r, route.Produces, route, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if aCtx != nil {
|
||||||
|
*r = *aCtx
|
||||||
|
}
|
||||||
|
var principal *models.Principal
|
||||||
|
if uprinc != nil {
|
||||||
|
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
|
||||||
|
}
|
||||||
|
|
||||||
|
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, principal) // actually handle the request
|
||||||
|
o.Context.Respond(rw, r, route.Produces, route, res)
|
||||||
|
|
||||||
|
}
|
130
gen/restapi/operations/delete_container_parameters.go
Normal file
130
gen/restapi/operations/delete_container_parameters.go
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
// 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/middleware"
|
||||||
|
"github.com/go-openapi/strfmt"
|
||||||
|
"github.com/go-openapi/validate"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewDeleteContainerParams creates a new DeleteContainerParams object
|
||||||
|
//
|
||||||
|
// There are no default values defined in the spec.
|
||||||
|
func NewDeleteContainerParams() DeleteContainerParams {
|
||||||
|
|
||||||
|
return DeleteContainerParams{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteContainerParams contains all the bound params for the delete container operation
|
||||||
|
// typically these are obtained from a http.Request
|
||||||
|
//
|
||||||
|
// swagger:parameters deleteContainer
|
||||||
|
type DeleteContainerParams struct {
|
||||||
|
|
||||||
|
// HTTP Request Object
|
||||||
|
HTTPRequest *http.Request `json:"-"`
|
||||||
|
|
||||||
|
/*Base64 encoded signature for bearer token
|
||||||
|
Required: true
|
||||||
|
In: header
|
||||||
|
*/
|
||||||
|
XNeofsTokenSignature string
|
||||||
|
/*Hex encoded the public part of the key that signed the bearer token
|
||||||
|
Required: true
|
||||||
|
In: header
|
||||||
|
*/
|
||||||
|
XNeofsTokenSignatureKey string
|
||||||
|
/*Base58 encoded container id
|
||||||
|
Required: true
|
||||||
|
In: path
|
||||||
|
*/
|
||||||
|
ContainerID 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 NewDeleteContainerParams() beforehand.
|
||||||
|
func (o *DeleteContainerParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
|
||||||
|
var res []error
|
||||||
|
|
||||||
|
o.HTTPRequest = r
|
||||||
|
|
||||||
|
if err := o.bindXNeofsTokenSignature(r.Header[http.CanonicalHeaderKey("X-Neofs-Token-Signature")], true, route.Formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := o.bindXNeofsTokenSignatureKey(r.Header[http.CanonicalHeaderKey("X-Neofs-Token-Signature-Key")], true, route.Formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rContainerID, rhkContainerID, _ := route.Params.GetOK("containerId")
|
||||||
|
if err := o.bindContainerID(rContainerID, rhkContainerID, route.Formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
if len(res) > 0 {
|
||||||
|
return errors.CompositeValidationError(res...)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// bindXNeofsTokenSignature binds and validates parameter XNeofsTokenSignature from header.
|
||||||
|
func (o *DeleteContainerParams) bindXNeofsTokenSignature(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||||
|
if !hasKey {
|
||||||
|
return errors.Required("X-Neofs-Token-Signature", "header", rawData)
|
||||||
|
}
|
||||||
|
var raw string
|
||||||
|
if len(rawData) > 0 {
|
||||||
|
raw = rawData[len(rawData)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required: true
|
||||||
|
|
||||||
|
if err := validate.RequiredString("X-Neofs-Token-Signature", "header", raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
o.XNeofsTokenSignature = raw
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// bindXNeofsTokenSignatureKey binds and validates parameter XNeofsTokenSignatureKey from header.
|
||||||
|
func (o *DeleteContainerParams) bindXNeofsTokenSignatureKey(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||||
|
if !hasKey {
|
||||||
|
return errors.Required("X-Neofs-Token-Signature-Key", "header", rawData)
|
||||||
|
}
|
||||||
|
var raw string
|
||||||
|
if len(rawData) > 0 {
|
||||||
|
raw = rawData[len(rawData)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required: true
|
||||||
|
|
||||||
|
if err := validate.RequiredString("X-Neofs-Token-Signature-Key", "header", raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
o.XNeofsTokenSignatureKey = raw
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// bindContainerID binds and validates parameter ContainerID from path.
|
||||||
|
func (o *DeleteContainerParams) bindContainerID(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||||
|
var raw string
|
||||||
|
if len(rawData) > 0 {
|
||||||
|
raw = rawData[len(rawData)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required: true
|
||||||
|
// Parameter is provided by construction from the route
|
||||||
|
o.ContainerID = raw
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
80
gen/restapi/operations/delete_container_responses.go
Normal file
80
gen/restapi/operations/delete_container_responses.go
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
// 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeleteContainerNoContentCode is the HTTP code returned for type DeleteContainerNoContent
|
||||||
|
const DeleteContainerNoContentCode int = 204
|
||||||
|
|
||||||
|
/*DeleteContainerNoContent Successul deletion
|
||||||
|
|
||||||
|
swagger:response deleteContainerNoContent
|
||||||
|
*/
|
||||||
|
type DeleteContainerNoContent struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDeleteContainerNoContent creates DeleteContainerNoContent with default headers values
|
||||||
|
func NewDeleteContainerNoContent() *DeleteContainerNoContent {
|
||||||
|
|
||||||
|
return &DeleteContainerNoContent{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteResponse to the client
|
||||||
|
func (o *DeleteContainerNoContent) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||||
|
|
||||||
|
rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses
|
||||||
|
|
||||||
|
rw.WriteHeader(204)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteContainerBadRequestCode is the HTTP code returned for type DeleteContainerBadRequest
|
||||||
|
const DeleteContainerBadRequestCode int = 400
|
||||||
|
|
||||||
|
/*DeleteContainerBadRequest Bad request
|
||||||
|
|
||||||
|
swagger:response deleteContainerBadRequest
|
||||||
|
*/
|
||||||
|
type DeleteContainerBadRequest struct {
|
||||||
|
|
||||||
|
/*
|
||||||
|
In: Body
|
||||||
|
*/
|
||||||
|
Payload models.Error `json:"body,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDeleteContainerBadRequest creates DeleteContainerBadRequest with default headers values
|
||||||
|
func NewDeleteContainerBadRequest() *DeleteContainerBadRequest {
|
||||||
|
|
||||||
|
return &DeleteContainerBadRequest{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPayload adds the payload to the delete container bad request response
|
||||||
|
func (o *DeleteContainerBadRequest) WithPayload(payload models.Error) *DeleteContainerBadRequest {
|
||||||
|
o.Payload = payload
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPayload sets the payload to the delete container bad request response
|
||||||
|
func (o *DeleteContainerBadRequest) SetPayload(payload models.Error) {
|
||||||
|
o.Payload = payload
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteResponse to the client
|
||||||
|
func (o *DeleteContainerBadRequest) 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,6 +47,9 @@ func NewNeofsRestGwAPI(spec *loads.Document) *NeofsRestGwAPI {
|
||||||
AuthHandler: AuthHandlerFunc(func(params AuthParams) middleware.Responder {
|
AuthHandler: AuthHandlerFunc(func(params AuthParams) middleware.Responder {
|
||||||
return middleware.NotImplemented("operation Auth has not yet been implemented")
|
return middleware.NotImplemented("operation Auth has not yet been implemented")
|
||||||
}),
|
}),
|
||||||
|
DeleteContainerHandler: DeleteContainerHandlerFunc(func(params DeleteContainerParams, principal *models.Principal) middleware.Responder {
|
||||||
|
return middleware.NotImplemented("operation DeleteContainer has not yet been implemented")
|
||||||
|
}),
|
||||||
GetContainerHandler: GetContainerHandlerFunc(func(params GetContainerParams) middleware.Responder {
|
GetContainerHandler: GetContainerHandlerFunc(func(params GetContainerParams) middleware.Responder {
|
||||||
return middleware.NotImplemented("operation GetContainer has not yet been implemented")
|
return middleware.NotImplemented("operation GetContainer has not yet been implemented")
|
||||||
}),
|
}),
|
||||||
|
@ -111,6 +114,8 @@ type NeofsRestGwAPI struct {
|
||||||
|
|
||||||
// AuthHandler sets the operation handler for the auth operation
|
// AuthHandler sets the operation handler for the auth operation
|
||||||
AuthHandler AuthHandler
|
AuthHandler AuthHandler
|
||||||
|
// DeleteContainerHandler sets the operation handler for the delete container operation
|
||||||
|
DeleteContainerHandler DeleteContainerHandler
|
||||||
// GetContainerHandler sets the operation handler for the get container operation
|
// GetContainerHandler sets the operation handler for the get container operation
|
||||||
GetContainerHandler GetContainerHandler
|
GetContainerHandler GetContainerHandler
|
||||||
// GetObjectInfoHandler sets the operation handler for the get object info operation
|
// GetObjectInfoHandler sets the operation handler for the get object info operation
|
||||||
|
@ -203,6 +208,9 @@ func (o *NeofsRestGwAPI) Validate() error {
|
||||||
if o.AuthHandler == nil {
|
if o.AuthHandler == nil {
|
||||||
unregistered = append(unregistered, "AuthHandler")
|
unregistered = append(unregistered, "AuthHandler")
|
||||||
}
|
}
|
||||||
|
if o.DeleteContainerHandler == nil {
|
||||||
|
unregistered = append(unregistered, "DeleteContainerHandler")
|
||||||
|
}
|
||||||
if o.GetContainerHandler == nil {
|
if o.GetContainerHandler == nil {
|
||||||
unregistered = append(unregistered, "GetContainerHandler")
|
unregistered = append(unregistered, "GetContainerHandler")
|
||||||
}
|
}
|
||||||
|
@ -318,6 +326,10 @@ func (o *NeofsRestGwAPI) initHandlerCache() {
|
||||||
o.handlers["POST"] = make(map[string]http.Handler)
|
o.handlers["POST"] = make(map[string]http.Handler)
|
||||||
}
|
}
|
||||||
o.handlers["POST"]["/auth"] = NewAuth(o.context, o.AuthHandler)
|
o.handlers["POST"]["/auth"] = NewAuth(o.context, o.AuthHandler)
|
||||||
|
if o.handlers["DELETE"] == nil {
|
||||||
|
o.handlers["DELETE"] = make(map[string]http.Handler)
|
||||||
|
}
|
||||||
|
o.handlers["DELETE"]["/containers/{containerId}"] = NewDeleteContainer(o.context, o.DeleteContainerHandler)
|
||||||
if o.handlers["GET"] == nil {
|
if o.handlers["GET"] == nil {
|
||||||
o.handlers["GET"] = make(map[string]http.Handler)
|
o.handlers["GET"] = make(map[string]http.Handler)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,15 +14,23 @@ import (
|
||||||
"github.com/go-openapi/runtime"
|
"github.com/go-openapi/runtime"
|
||||||
"github.com/go-openapi/runtime/middleware"
|
"github.com/go-openapi/runtime/middleware"
|
||||||
"github.com/go-openapi/strfmt"
|
"github.com/go-openapi/strfmt"
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
"github.com/go-openapi/validate"
|
"github.com/go-openapi/validate"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewPutContainerParams creates a new PutContainerParams object
|
// NewPutContainerParams creates a new PutContainerParams object
|
||||||
//
|
// with the default values initialized.
|
||||||
// There are no default values defined in the spec.
|
|
||||||
func NewPutContainerParams() PutContainerParams {
|
func NewPutContainerParams() PutContainerParams {
|
||||||
|
|
||||||
return PutContainerParams{}
|
var (
|
||||||
|
// initialize parameters with default values
|
||||||
|
|
||||||
|
skipNativeNameDefault = bool(false)
|
||||||
|
)
|
||||||
|
|
||||||
|
return PutContainerParams{
|
||||||
|
SkipNativeName: &skipNativeNameDefault,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutContainerParams contains all the bound params for the put container operation
|
// PutContainerParams contains all the bound params for the put container operation
|
||||||
|
@ -49,6 +57,11 @@ type PutContainerParams struct {
|
||||||
In: body
|
In: body
|
||||||
*/
|
*/
|
||||||
Container PutContainerBody
|
Container PutContainerBody
|
||||||
|
/*Provide this parameter to skip registration container name in NNS service
|
||||||
|
In: query
|
||||||
|
Default: false
|
||||||
|
*/
|
||||||
|
SkipNativeName *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
|
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
|
||||||
|
@ -60,6 +73,8 @@ func (o *PutContainerParams) BindRequest(r *http.Request, route *middleware.Matc
|
||||||
|
|
||||||
o.HTTPRequest = r
|
o.HTTPRequest = r
|
||||||
|
|
||||||
|
qs := runtime.Values(r.URL.Query())
|
||||||
|
|
||||||
if err := o.bindXNeofsTokenSignature(r.Header[http.CanonicalHeaderKey("X-Neofs-Token-Signature")], true, route.Formats); err != nil {
|
if err := o.bindXNeofsTokenSignature(r.Header[http.CanonicalHeaderKey("X-Neofs-Token-Signature")], true, route.Formats); err != nil {
|
||||||
res = append(res, err)
|
res = append(res, err)
|
||||||
}
|
}
|
||||||
|
@ -95,6 +110,11 @@ func (o *PutContainerParams) BindRequest(r *http.Request, route *middleware.Matc
|
||||||
} else {
|
} else {
|
||||||
res = append(res, errors.Required("container", "body", ""))
|
res = append(res, errors.Required("container", "body", ""))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qSkipNativeName, qhkSkipNativeName, _ := qs.GetOK("skip-native-name")
|
||||||
|
if err := o.bindSkipNativeName(qSkipNativeName, qhkSkipNativeName, route.Formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
if len(res) > 0 {
|
if len(res) > 0 {
|
||||||
return errors.CompositeValidationError(res...)
|
return errors.CompositeValidationError(res...)
|
||||||
}
|
}
|
||||||
|
@ -140,3 +160,27 @@ func (o *PutContainerParams) bindXNeofsTokenSignatureKey(rawData []string, hasKe
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bindSkipNativeName binds and validates parameter SkipNativeName from query.
|
||||||
|
func (o *PutContainerParams) bindSkipNativeName(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 NewPutContainerParams()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
value, err := swag.ConvertBool(raw)
|
||||||
|
if err != nil {
|
||||||
|
return errors.InvalidType("skip-native-name", "query", "bool", raw)
|
||||||
|
}
|
||||||
|
o.SkipNativeName = &value
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -13,7 +13,7 @@ require (
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/nspcc-dev/neo-go v0.98.2
|
github.com/nspcc-dev/neo-go v0.98.2
|
||||||
github.com/nspcc-dev/neofs-api-go/v2 v2.12.1
|
github.com/nspcc-dev/neofs-api-go/v2 v2.12.1
|
||||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.3.0.20220407103316-e50e6d28280d
|
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.3.0.20220412151250-3e75660802ae
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/testcontainers/testcontainers-go v0.13.0
|
github.com/testcontainers/testcontainers-go v0.13.0
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -750,8 +750,8 @@ github.com/nspcc-dev/neofs-crypto v0.3.0 h1:zlr3pgoxuzrmGCxc5W8dGVfA9Rro8diFvVnB
|
||||||
github.com/nspcc-dev/neofs-crypto v0.3.0/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw=
|
github.com/nspcc-dev/neofs-crypto v0.3.0/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw=
|
||||||
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20211201182451-a5b61c4f6477/go.mod h1:dfMtQWmBHYpl9Dez23TGtIUKiFvCIxUZq/CkSIhEpz4=
|
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20211201182451-a5b61c4f6477/go.mod h1:dfMtQWmBHYpl9Dez23TGtIUKiFvCIxUZq/CkSIhEpz4=
|
||||||
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659/go.mod h1:/jay1lr3w7NQd/VDBkEhkJmDmyPNsu4W+QV2obsUV40=
|
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659/go.mod h1:/jay1lr3w7NQd/VDBkEhkJmDmyPNsu4W+QV2obsUV40=
|
||||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.3.0.20220407103316-e50e6d28280d h1:OHyq8+zyQtARFWj3quRPabcfQWJZEiU7HYp6QGCSjaM=
|
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.3.0.20220412151250-3e75660802ae h1:xcoEwEwZXu784Re1PPE35vm1A4+sUCVgMuGFqQPnN1Q=
|
||||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.3.0.20220407103316-e50e6d28280d/go.mod h1:Hl7a1l0ntZ4b1ZABpGX6fuAuFS3c6+hyMCUNVvZv/w4=
|
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.3.0.20220412151250-3e75660802ae/go.mod h1:Hl7a1l0ntZ4b1ZABpGX6fuAuFS3c6+hyMCUNVvZv/w4=
|
||||||
github.com/nspcc-dev/rfc6979 v0.1.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
|
github.com/nspcc-dev/rfc6979 v0.1.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
|
||||||
github.com/nspcc-dev/rfc6979 v0.2.0 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE=
|
github.com/nspcc-dev/rfc6979 v0.2.0 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE=
|
||||||
github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
|
github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
|
||||||
|
|
|
@ -68,6 +68,7 @@ func (a *API) Configure(api *operations.NeofsRestGwAPI) http.Handler {
|
||||||
|
|
||||||
api.PutContainerHandler = operations.PutContainerHandlerFunc(a.PutContainers)
|
api.PutContainerHandler = operations.PutContainerHandlerFunc(a.PutContainers)
|
||||||
api.GetContainerHandler = operations.GetContainerHandlerFunc(a.GetContainer)
|
api.GetContainerHandler = operations.GetContainerHandlerFunc(a.GetContainer)
|
||||||
|
api.DeleteContainerHandler = operations.DeleteContainerHandlerFunc(a.DeleteContainer)
|
||||||
|
|
||||||
api.BearerAuthAuth = func(s string) (*models.Principal, error) {
|
api.BearerAuthAuth = func(s string) (*models.Principal, error) {
|
||||||
if !strings.HasPrefix(s, BearerPrefix) {
|
if !strings.HasPrefix(s, BearerPrefix) {
|
||||||
|
@ -99,7 +100,7 @@ func (a *API) setupGlobalMiddleware(handler http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
requestID := uuid.NewString()
|
requestID := uuid.NewString()
|
||||||
a.log.Info("request", zap.String("remote", r.RemoteAddr),
|
a.log.Info("request", zap.String("remote", r.RemoteAddr),
|
||||||
zap.String("method", r.Method), zap.String("uri", r.RequestURI),
|
zap.String("method", r.Method), zap.String("url", r.URL.String()),
|
||||||
zap.String("id", requestID))
|
zap.String("id", requestID))
|
||||||
|
|
||||||
ctx := context.WithValue(r.Context(), ContextKeyRequestID, requestID)
|
ctx := context.WithValue(r.Context(), ContextKeyRequestID, requestID)
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/policy"
|
"github.com/nspcc-dev/neofs-sdk-go/policy"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/pool"
|
"github.com/nspcc-dev/neofs-sdk-go/pool"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/session"
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -42,7 +43,7 @@ func (a *API) PutContainers(params operations.PutContainerParams, principal *mod
|
||||||
|
|
||||||
userAttributes := prepareUserAttributes(params.HTTPRequest.Header)
|
userAttributes := prepareUserAttributes(params.HTTPRequest.Header)
|
||||||
|
|
||||||
cnrID, err := createContainer(params.HTTPRequest.Context(), a.pool, stoken, ¶ms.Container, userAttributes)
|
cnrID, err := createContainer(params.HTTPRequest.Context(), a.pool, stoken, ¶ms, userAttributes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return wrapError(err)
|
return wrapError(err)
|
||||||
}
|
}
|
||||||
|
@ -80,6 +81,37 @@ func (a *API) GetContainer(params operations.GetContainerParams) middleware.Resp
|
||||||
return operations.NewGetContainerOK().WithPayload(resp)
|
return operations.NewGetContainerOK().WithPayload(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteContainer handler that returns container info.
|
||||||
|
func (a *API) DeleteContainer(params operations.DeleteContainerParams, principal *models.Principal) middleware.Responder {
|
||||||
|
bt := &BearerToken{
|
||||||
|
Token: string(*principal),
|
||||||
|
Signature: params.XNeofsTokenSignature,
|
||||||
|
Key: params.XNeofsTokenSignatureKey,
|
||||||
|
}
|
||||||
|
stoken, err := prepareSessionToken(bt)
|
||||||
|
if err != nil {
|
||||||
|
a.log.Error("failed parse session token", zap.Error(err))
|
||||||
|
return operations.NewDeleteContainerBadRequest().WithPayload(NewError(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
cnrID, err := parseContainerID(params.ContainerID)
|
||||||
|
if err != nil {
|
||||||
|
a.log.Error("failed get container id", zap.Error(err))
|
||||||
|
return operations.NewDeleteContainerBadRequest().WithPayload(NewError(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
var prm pool.PrmContainerDelete
|
||||||
|
prm.SetContainerID(*cnrID)
|
||||||
|
prm.SetSessionToken(*stoken)
|
||||||
|
|
||||||
|
if err = a.pool.DeleteContainer(params.HTTPRequest.Context(), prm); err != nil {
|
||||||
|
a.log.Error("failed delete container", zap.String("container", params.ContainerID), zap.Error(err))
|
||||||
|
return operations.NewDeleteContainerBadRequest().WithPayload(NewError(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return operations.NewDeleteContainerNoContent()
|
||||||
|
}
|
||||||
|
|
||||||
func prepareUserAttributes(header http.Header) map[string]string {
|
func prepareUserAttributes(header http.Header) map[string]string {
|
||||||
filtered := filterHeaders(header)
|
filtered := filterHeaders(header)
|
||||||
delete(filtered, container.AttributeName)
|
delete(filtered, container.AttributeName)
|
||||||
|
@ -88,18 +120,29 @@ func prepareUserAttributes(header http.Header) map[string]string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getContainer(ctx context.Context, p *pool.Pool, containerID string) (*container.Container, error) {
|
func getContainer(ctx context.Context, p *pool.Pool, containerID string) (*container.Container, error) {
|
||||||
|
cnrID, err := parseContainerID(containerID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var prm pool.PrmContainerGet
|
||||||
|
prm.SetContainerID(*cnrID)
|
||||||
|
|
||||||
|
return p.GetContainer(ctx, prm)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseContainerID(containerID string) (*cid.ID, error) {
|
||||||
var cnrID cid.ID
|
var cnrID cid.ID
|
||||||
if err := cnrID.Parse(containerID); err != nil {
|
if err := cnrID.Parse(containerID); err != nil {
|
||||||
return nil, fmt.Errorf("parse container id '%s': %w", containerID, err)
|
return nil, fmt.Errorf("parse container id '%s': %w", containerID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var prm pool.PrmContainerGet
|
return &cnrID, nil
|
||||||
prm.SetContainerID(cnrID)
|
|
||||||
|
|
||||||
return p.GetContainer(ctx, prm)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func createContainer(ctx context.Context, p *pool.Pool, stoken *session.Token, request *operations.PutContainerBody, userAttrs map[string]string) (*cid.ID, error) {
|
func createContainer(ctx context.Context, p *pool.Pool, stoken *session.Token, params *operations.PutContainerParams, userAttrs map[string]string) (*cid.ID, error) {
|
||||||
|
request := params.Container
|
||||||
|
|
||||||
if request.PlacementPolicy == "" {
|
if request.PlacementPolicy == "" {
|
||||||
request.PlacementPolicy = defaultPlacementPolicy
|
request.PlacementPolicy = defaultPlacementPolicy
|
||||||
}
|
}
|
||||||
|
@ -131,7 +174,9 @@ func createContainer(ctx context.Context, p *pool.Pool, stoken *session.Token, r
|
||||||
cnr.SetOwnerID(stoken.OwnerID())
|
cnr.SetOwnerID(stoken.OwnerID())
|
||||||
cnr.SetSessionToken(stoken)
|
cnr.SetSessionToken(stoken)
|
||||||
|
|
||||||
container.SetNativeName(cnr, *request.ContainerName)
|
if !*params.SkipNativeName { // we don't check for nil because there is default false value
|
||||||
|
container.SetNativeName(cnr, *request.ContainerName)
|
||||||
|
}
|
||||||
|
|
||||||
var prm pool.PrmContainerPut
|
var prm pool.PrmContainerPut
|
||||||
prm.SetContainer(*cnr)
|
prm.SetContainer(*cnr)
|
||||||
|
|
|
@ -167,6 +167,11 @@ paths:
|
||||||
operationId: putContainer
|
operationId: putContainer
|
||||||
summary: Create new container in NeoFS
|
summary: Create new container in NeoFS
|
||||||
parameters:
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: skip-native-name
|
||||||
|
description: Provide this parameter to skip registration container name in NNS service
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
- in: body
|
- in: body
|
||||||
name: container
|
name: container
|
||||||
required: true
|
required: true
|
||||||
|
@ -204,16 +209,16 @@ paths:
|
||||||
$ref: '#/definitions/Error'
|
$ref: '#/definitions/Error'
|
||||||
|
|
||||||
/containers/{containerId}:
|
/containers/{containerId}:
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: containerId
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
description: Base58 encoded container id
|
||||||
get:
|
get:
|
||||||
operationId: getContainer
|
operationId: getContainer
|
||||||
summary: Get container by id
|
summary: Get container by id
|
||||||
security: [ ]
|
security: [ ]
|
||||||
parameters:
|
|
||||||
- in: path
|
|
||||||
name: containerId
|
|
||||||
type: string
|
|
||||||
required: true
|
|
||||||
description: Base58 encoded container id
|
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: Container info
|
description: Container info
|
||||||
|
@ -223,6 +228,19 @@ paths:
|
||||||
description: Bad request
|
description: Bad request
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/Error'
|
$ref: '#/definitions/Error'
|
||||||
|
delete:
|
||||||
|
operationId: deleteContainer
|
||||||
|
summary: Delete container by id
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/parameters/signatureParam'
|
||||||
|
- $ref: '#/parameters/signatureKeyParam'
|
||||||
|
responses:
|
||||||
|
204:
|
||||||
|
description: Successul deletion
|
||||||
|
400:
|
||||||
|
description: Bad request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Error'
|
||||||
|
|
||||||
definitions:
|
definitions:
|
||||||
Bearer:
|
Bearer:
|
||||||
|
|
Loading…
Reference in a new issue