diff --git a/gen/models/storage_group.go b/gen/models/storage_group.go index b20cae4..b1635e2 100644 --- a/gen/models/storage_group.go +++ b/gen/models/storage_group.go @@ -19,13 +19,17 @@ import ( // swagger:model StorageGroup type StorageGroup struct { - // Container id to which storage group is belong. Set by server. - // Read Only: true - ContainerID string `json:"containerId,omitempty"` - - // Lifetime in epochs for storage group. + // Address of storage group object. Set by server. // Required: true - Lifetime *int64 `json:"lifetime"` + // Read Only: true + Address *Address `json:"address"` + + // expiration epoch + // Required: true + ExpirationEpoch *string `json:"expirationEpoch"` + + // hash + Hash string `json:"hash,omitempty"` // Object identifiers to be placed into storage group. Must be unique. // Required: true @@ -34,16 +38,20 @@ type StorageGroup struct { // Name of storage group. It will be the value of the `FileName` attribute in storage group object. Name string `json:"name,omitempty"` - // Object id of storage group. Set by server. - // Read Only: true - ObjectID string `json:"objectId,omitempty"` + // size + // Required: true + Size *string `json:"size"` } // Validate validates this storage group func (m *StorageGroup) Validate(formats strfmt.Registry) error { var res []error - if err := m.validateLifetime(formats); err != nil { + if err := m.validateAddress(formats); err != nil { + res = append(res, err) + } + + if err := m.validateExpirationEpoch(formats); err != nil { res = append(res, err) } @@ -51,15 +59,39 @@ func (m *StorageGroup) Validate(formats strfmt.Registry) error { 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 *StorageGroup) validateLifetime(formats strfmt.Registry) error { +func (m *StorageGroup) validateAddress(formats strfmt.Registry) error { - if err := validate.Required("lifetime", "body", m.Lifetime); err != nil { + if err := validate.Required("address", "body", m.Address); err != nil { + return err + } + + if m.Address != nil { + if err := m.Address.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("address") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("address") + } + return err + } + } + + return nil +} + +func (m *StorageGroup) validateExpirationEpoch(formats strfmt.Registry) error { + + if err := validate.Required("expirationEpoch", "body", m.ExpirationEpoch); err != nil { return err } @@ -75,15 +107,20 @@ func (m *StorageGroup) validateMembers(formats strfmt.Registry) error { return nil } +func (m *StorageGroup) validateSize(formats strfmt.Registry) error { + + if err := validate.Required("size", "body", m.Size); err != nil { + return err + } + + return nil +} + // ContextValidate validate this storage group based on the context it is used func (m *StorageGroup) ContextValidate(ctx context.Context, formats strfmt.Registry) error { var res []error - if err := m.contextValidateContainerID(ctx, formats); err != nil { - res = append(res, err) - } - - if err := m.contextValidateObjectID(ctx, formats); err != nil { + if err := m.contextValidateAddress(ctx, formats); err != nil { res = append(res, err) } @@ -93,19 +130,17 @@ func (m *StorageGroup) ContextValidate(ctx context.Context, formats strfmt.Regis return nil } -func (m *StorageGroup) contextValidateContainerID(ctx context.Context, formats strfmt.Registry) error { +func (m *StorageGroup) contextValidateAddress(ctx context.Context, formats strfmt.Registry) error { - if err := validate.ReadOnly(ctx, "containerId", "body", string(m.ContainerID)); err != nil { - return err - } - - return nil -} - -func (m *StorageGroup) contextValidateObjectID(ctx context.Context, formats strfmt.Registry) error { - - if err := validate.ReadOnly(ctx, "objectId", "body", string(m.ObjectID)); err != nil { - return err + if m.Address != nil { + if err := m.Address.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("address") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("address") + } + return err + } } return nil diff --git a/gen/models/storage_group_put_body.go b/gen/models/storage_group_put_body.go new file mode 100644 index 0000000..955a147 --- /dev/null +++ b/gen/models/storage_group_put_body.go @@ -0,0 +1,91 @@ +// 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" +) + +// StorageGroupPutBody storage group put body +// +// swagger:model StorageGroupPutBody +type StorageGroupPutBody struct { + + // Lifetime in epochs for storage group. + // Required: true + Lifetime *int64 `json:"lifetime"` + + // Object identifiers to be placed into storage group. Must be unique. + // Required: true + Members []string `json:"members"` + + // Name of storage group. It will be the value of the `FileName` attribute in storage group object. + Name string `json:"name,omitempty"` +} + +// Validate validates this storage group put body +func (m *StorageGroupPutBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateLifetime(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMembers(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *StorageGroupPutBody) validateLifetime(formats strfmt.Registry) error { + + if err := validate.Required("lifetime", "body", m.Lifetime); err != nil { + return err + } + + return nil +} + +func (m *StorageGroupPutBody) validateMembers(formats strfmt.Registry) error { + + if err := validate.Required("members", "body", m.Members); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this storage group put body based on context it is used +func (m *StorageGroupPutBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *StorageGroupPutBody) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *StorageGroupPutBody) UnmarshalBinary(b []byte) error { + var res StorageGroupPutBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/gen/restapi/embedded_spec.go b/gen/restapi/embedded_spec.go index cea86d5..41d9b80 100644 --- a/gen/restapi/embedded_spec.go +++ b/gen/restapi/embedded_spec.go @@ -572,7 +572,7 @@ func init() { "in": "body", "required": true, "schema": { - "$ref": "#/definitions/StorageGroup" + "$ref": "#/definitions/StorageGroupPutBody" } } ], @@ -597,6 +597,74 @@ func init() { } ] }, + "/containers/{containerId}/storagegroups/{storageGroupId}": { + "get": { + "summary": "Get storage group info.", + "operationId": "getStorageGroup", + "parameters": [ + { + "$ref": "#/parameters/signatureParam" + }, + { + "$ref": "#/parameters/signatureKeyParam" + }, + { + "$ref": "#/parameters/signatureScheme" + } + ], + "responses": { + "200": { + "description": "Storage group information.", + "schema": { + "$ref": "#/definitions/StorageGroup" + } + }, + "400": { + "description": "Bad request.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + }, + "delete": { + "summary": "Delete storage group from container.", + "operationId": "deleteStorageGroup", + "parameters": [ + { + "$ref": "#/parameters/signatureParam" + }, + { + "$ref": "#/parameters/signatureKeyParam" + }, + { + "$ref": "#/parameters/signatureScheme" + } + ], + "responses": { + "200": { + "description": "Successful deletion.", + "schema": { + "$ref": "#/definitions/SuccessResponse" + } + }, + "400": { + "description": "Bad request.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + }, + "parameters": [ + { + "$ref": "#/parameters/containerId" + }, + { + "$ref": "#/parameters/storageGroupId" + } + ] + }, "/objects": { "put": { "consumes": [ @@ -1600,18 +1668,22 @@ func init() { "description": "Storage group keeps verification information for Data Audit sessions.", "type": "object", "required": [ - "lifetime", + "address", + "expirationEpoch", + "size", "members" ], "properties": { - "containerId": { - "description": "Container id to which storage group is belong. Set by server.", - "type": "string", + "address": { + "description": "Address of storage group object. Set by server.", + "$ref": "#/definitions/Address", "readOnly": true }, - "lifetime": { - "description": "Lifetime in epochs for storage group.", - "type": "integer" + "expirationEpoch": { + "type": "string" + }, + "hash": { + "type": "string" }, "members": { "description": "Object identifiers to be placed into storage group. Must be unique.", @@ -1624,10 +1696,8 @@ func init() { "description": "Name of storage group. It will be the value of the ` + "`" + `FileName` + "`" + ` attribute in storage group object.", "type": "string" }, - "objectId": { - "description": "Object id of storage group. Set by server.", - "type": "string", - "readOnly": true + "size": { + "type": "string" } } }, @@ -1669,6 +1739,30 @@ func init() { } } }, + "StorageGroupPutBody": { + "type": "object", + "required": [ + "lifetime", + "members" + ], + "properties": { + "lifetime": { + "description": "Lifetime in epochs for storage group.", + "type": "integer" + }, + "members": { + "description": "Object identifiers to be placed into storage group. Must be unique.", + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "description": "Name of storage group. It will be the value of the ` + "`" + `FileName` + "`" + ` attribute in storage group object.", + "type": "string" + } + } + }, "SuccessResponse": { "description": "Success response.", "type": "object", @@ -1796,6 +1890,13 @@ func init() { "description": "Use wallet connect signature scheme or native FrostFS signature.", "name": "walletConnect", "in": "query" + }, + "storageGroupId": { + "type": "string", + "description": "Base58 encoded storage group id.", + "name": "storageGroupId", + "in": "path", + "required": true } }, "securityDefinitions": { @@ -2440,7 +2541,7 @@ func init() { "in": "body", "required": true, "schema": { - "$ref": "#/definitions/StorageGroup" + "$ref": "#/definitions/StorageGroupPutBody" } } ], @@ -2469,6 +2570,106 @@ func init() { } ] }, + "/containers/{containerId}/storagegroups/{storageGroupId}": { + "get": { + "summary": "Get storage group info.", + "operationId": "getStorageGroup", + "parameters": [ + { + "type": "string", + "description": "Base64 encoded signature for bearer token.", + "name": "X-Bearer-Signature", + "in": "header", + "required": true + }, + { + "type": "string", + "description": "Hex encoded the public part of the key that signed the bearer token.", + "name": "X-Bearer-Signature-Key", + "in": "header", + "required": true + }, + { + "type": "boolean", + "default": false, + "description": "Use wallet connect signature scheme or native NeoFS signature.", + "name": "walletConnect", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Storage group information.", + "schema": { + "$ref": "#/definitions/StorageGroup" + } + }, + "400": { + "description": "Bad request.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + }, + "delete": { + "summary": "Delete storage group from container.", + "operationId": "deleteStorageGroup", + "parameters": [ + { + "type": "string", + "description": "Base64 encoded signature for bearer token.", + "name": "X-Bearer-Signature", + "in": "header", + "required": true + }, + { + "type": "string", + "description": "Hex encoded the public part of the key that signed the bearer token.", + "name": "X-Bearer-Signature-Key", + "in": "header", + "required": true + }, + { + "type": "boolean", + "default": false, + "description": "Use wallet connect signature scheme or native NeoFS signature.", + "name": "walletConnect", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successful deletion.", + "schema": { + "$ref": "#/definitions/SuccessResponse" + } + }, + "400": { + "description": "Bad request.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + }, + "parameters": [ + { + "type": "string", + "description": "Base58 encoded container id.", + "name": "containerId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Base58 encoded storage group id.", + "name": "storageGroupId", + "in": "path", + "required": true + } + ] + }, "/objects": { "put": { "consumes": [ @@ -3543,18 +3744,22 @@ func init() { "description": "Storage group keeps verification information for Data Audit sessions.", "type": "object", "required": [ - "lifetime", + "address", + "expirationEpoch", + "size", "members" ], "properties": { - "containerId": { - "description": "Container id to which storage group is belong. Set by server.", - "type": "string", + "address": { + "description": "Address of storage group object. Set by server.", + "$ref": "#/definitions/Address", "readOnly": true }, - "lifetime": { - "description": "Lifetime in epochs for storage group.", - "type": "integer" + "expirationEpoch": { + "type": "string" + }, + "hash": { + "type": "string" }, "members": { "description": "Object identifiers to be placed into storage group. Must be unique.", @@ -3567,10 +3772,8 @@ func init() { "description": "Name of storage group. It will be the value of the ` + "`" + `FileName` + "`" + ` attribute in storage group object.", "type": "string" }, - "objectId": { - "description": "Object id of storage group. Set by server.", - "type": "string", - "readOnly": true + "size": { + "type": "string" } } }, @@ -3612,6 +3815,30 @@ func init() { } } }, + "StorageGroupPutBody": { + "type": "object", + "required": [ + "lifetime", + "members" + ], + "properties": { + "lifetime": { + "description": "Lifetime in epochs for storage group.", + "type": "integer" + }, + "members": { + "description": "Object identifiers to be placed into storage group. Must be unique.", + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "description": "Name of storage group. It will be the value of the ` + "`" + `FileName` + "`" + ` attribute in storage group object.", + "type": "string" + } + } + }, "SuccessResponse": { "description": "Success response.", "type": "object", @@ -3739,6 +3966,13 @@ func init() { "description": "Use wallet connect signature scheme or native FrostFS signature.", "name": "walletConnect", "in": "query" + }, + "storageGroupId": { + "type": "string", + "description": "Base58 encoded storage group id.", + "name": "storageGroupId", + "in": "path", + "required": true } }, "securityDefinitions": { diff --git a/gen/restapi/operations/delete_storage_group.go b/gen/restapi/operations/delete_storage_group.go new file mode 100644 index 0000000..7c4a012 --- /dev/null +++ b/gen/restapi/operations/delete_storage_group.go @@ -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" +) + +// DeleteStorageGroupHandlerFunc turns a function with the right signature into a delete storage group handler +type DeleteStorageGroupHandlerFunc func(DeleteStorageGroupParams, *models.Principal) middleware.Responder + +// Handle executing the request and returning a response +func (fn DeleteStorageGroupHandlerFunc) Handle(params DeleteStorageGroupParams, principal *models.Principal) middleware.Responder { + return fn(params, principal) +} + +// DeleteStorageGroupHandler interface for that can handle valid delete storage group params +type DeleteStorageGroupHandler interface { + Handle(DeleteStorageGroupParams, *models.Principal) middleware.Responder +} + +// NewDeleteStorageGroup creates a new http.Handler for the delete storage group operation +func NewDeleteStorageGroup(ctx *middleware.Context, handler DeleteStorageGroupHandler) *DeleteStorageGroup { + return &DeleteStorageGroup{Context: ctx, Handler: handler} +} + +/* DeleteStorageGroup swagger:route DELETE /containers/{containerId}/storagegroups/{storageGroupId} deleteStorageGroup + +Delete storage group from container. + +*/ +type DeleteStorageGroup struct { + Context *middleware.Context + Handler DeleteStorageGroupHandler +} + +func (o *DeleteStorageGroup) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + route, rCtx, _ := o.Context.RouteInfo(r) + if rCtx != nil { + *r = *rCtx + } + var Params = NewDeleteStorageGroupParams() + 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) + +} diff --git a/gen/restapi/operations/delete_storage_group_parameters.go b/gen/restapi/operations/delete_storage_group_parameters.go new file mode 100644 index 0000000..118d378 --- /dev/null +++ b/gen/restapi/operations/delete_storage_group_parameters.go @@ -0,0 +1,199 @@ +// 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" +) + +// NewDeleteStorageGroupParams creates a new DeleteStorageGroupParams object +// with the default values initialized. +func NewDeleteStorageGroupParams() DeleteStorageGroupParams { + + var ( + // initialize parameters with default values + + walletConnectDefault = bool(false) + ) + + return DeleteStorageGroupParams{ + WalletConnect: &walletConnectDefault, + } +} + +// DeleteStorageGroupParams contains all the bound params for the delete storage group operation +// typically these are obtained from a http.Request +// +// swagger:parameters deleteStorageGroup +type DeleteStorageGroupParams struct { + + // HTTP Request Object + HTTPRequest *http.Request `json:"-"` + + /*Base64 encoded signature for bearer token. + Required: true + In: header + */ + XBearerSignature string + /*Hex encoded the public part of the key that signed the bearer token. + Required: true + In: header + */ + XBearerSignatureKey string + /*Base58 encoded container id. + Required: true + In: path + */ + ContainerID string + /*Base58 encoded storage group id. + Required: true + In: path + */ + StorageGroupID string + /*Use wallet connect signature scheme or native NeoFS signature. + In: query + Default: false + */ + WalletConnect *bool +} + +// 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 NewDeleteStorageGroupParams() beforehand. +func (o *DeleteStorageGroupParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { + var res []error + + o.HTTPRequest = r + + qs := runtime.Values(r.URL.Query()) + + if err := o.bindXBearerSignature(r.Header[http.CanonicalHeaderKey("X-Bearer-Signature")], true, route.Formats); err != nil { + res = append(res, err) + } + + if err := o.bindXBearerSignatureKey(r.Header[http.CanonicalHeaderKey("X-Bearer-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) + } + + rStorageGroupID, rhkStorageGroupID, _ := route.Params.GetOK("storageGroupId") + if err := o.bindStorageGroupID(rStorageGroupID, rhkStorageGroupID, route.Formats); err != nil { + res = append(res, err) + } + + qWalletConnect, qhkWalletConnect, _ := qs.GetOK("walletConnect") + if err := o.bindWalletConnect(qWalletConnect, qhkWalletConnect, route.Formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// bindXBearerSignature binds and validates parameter XBearerSignature from header. +func (o *DeleteStorageGroupParams) bindXBearerSignature(rawData []string, hasKey bool, formats strfmt.Registry) error { + if !hasKey { + return errors.Required("X-Bearer-Signature", "header", rawData) + } + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: true + + if err := validate.RequiredString("X-Bearer-Signature", "header", raw); err != nil { + return err + } + o.XBearerSignature = raw + + return nil +} + +// bindXBearerSignatureKey binds and validates parameter XBearerSignatureKey from header. +func (o *DeleteStorageGroupParams) bindXBearerSignatureKey(rawData []string, hasKey bool, formats strfmt.Registry) error { + if !hasKey { + return errors.Required("X-Bearer-Signature-Key", "header", rawData) + } + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: true + + if err := validate.RequiredString("X-Bearer-Signature-Key", "header", raw); err != nil { + return err + } + o.XBearerSignatureKey = raw + + return nil +} + +// bindContainerID binds and validates parameter ContainerID from path. +func (o *DeleteStorageGroupParams) 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 +} + +// bindStorageGroupID binds and validates parameter StorageGroupID from path. +func (o *DeleteStorageGroupParams) bindStorageGroupID(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.StorageGroupID = raw + + return nil +} + +// bindWalletConnect binds and validates parameter WalletConnect from query. +func (o *DeleteStorageGroupParams) bindWalletConnect(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 NewDeleteStorageGroupParams() + return nil + } + + value, err := swag.ConvertBool(raw) + if err != nil { + return errors.InvalidType("walletConnect", "query", "bool", raw) + } + o.WalletConnect = &value + + return nil +} diff --git a/gen/restapi/operations/delete_storage_group_responses.go b/gen/restapi/operations/delete_storage_group_responses.go new file mode 100644 index 0000000..caf4ce4 --- /dev/null +++ b/gen/restapi/operations/delete_storage_group_responses.go @@ -0,0 +1,102 @@ +// 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" +) + +// DeleteStorageGroupOKCode is the HTTP code returned for type DeleteStorageGroupOK +const DeleteStorageGroupOKCode int = 200 + +/*DeleteStorageGroupOK Successful deletion. + +swagger:response deleteStorageGroupOK +*/ +type DeleteStorageGroupOK struct { + + /* + In: Body + */ + Payload *models.SuccessResponse `json:"body,omitempty"` +} + +// NewDeleteStorageGroupOK creates DeleteStorageGroupOK with default headers values +func NewDeleteStorageGroupOK() *DeleteStorageGroupOK { + + return &DeleteStorageGroupOK{} +} + +// WithPayload adds the payload to the delete storage group o k response +func (o *DeleteStorageGroupOK) WithPayload(payload *models.SuccessResponse) *DeleteStorageGroupOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the delete storage group o k response +func (o *DeleteStorageGroupOK) SetPayload(payload *models.SuccessResponse) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DeleteStorageGroupOK) 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 + } + } +} + +// DeleteStorageGroupBadRequestCode is the HTTP code returned for type DeleteStorageGroupBadRequest +const DeleteStorageGroupBadRequestCode int = 400 + +/*DeleteStorageGroupBadRequest Bad request. + +swagger:response deleteStorageGroupBadRequest +*/ +type DeleteStorageGroupBadRequest struct { + + /* + In: Body + */ + Payload *models.ErrorResponse `json:"body,omitempty"` +} + +// NewDeleteStorageGroupBadRequest creates DeleteStorageGroupBadRequest with default headers values +func NewDeleteStorageGroupBadRequest() *DeleteStorageGroupBadRequest { + + return &DeleteStorageGroupBadRequest{} +} + +// WithPayload adds the payload to the delete storage group bad request response +func (o *DeleteStorageGroupBadRequest) WithPayload(payload *models.ErrorResponse) *DeleteStorageGroupBadRequest { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the delete storage group bad request response +func (o *DeleteStorageGroupBadRequest) SetPayload(payload *models.ErrorResponse) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DeleteStorageGroupBadRequest) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(400) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/gen/restapi/operations/frostfs_rest_gw_api.go b/gen/restapi/operations/frostfs_rest_gw_api.go index b5b5726..2ce52a5 100644 --- a/gen/restapi/operations/frostfs_rest_gw_api.go +++ b/gen/restapi/operations/frostfs_rest_gw_api.go @@ -53,6 +53,9 @@ func NewFrostfsRestGwAPI(spec *loads.Document) *FrostfsRestGwAPI { DeleteObjectHandler: DeleteObjectHandlerFunc(func(params DeleteObjectParams, principal *models.Principal) middleware.Responder { return middleware.NotImplemented("operation DeleteObject has not yet been implemented") }), + DeleteStorageGroupHandler: DeleteStorageGroupHandlerFunc(func(params DeleteStorageGroupParams, principal *models.Principal) middleware.Responder { + return middleware.NotImplemented("operation DeleteStorageGroup has not yet been implemented") + }), FormBinaryBearerHandler: FormBinaryBearerHandlerFunc(func(params FormBinaryBearerParams, principal *models.Principal) middleware.Responder { return middleware.NotImplemented("operation FormBinaryBearer has not yet been implemented") }), @@ -68,6 +71,9 @@ func NewFrostfsRestGwAPI(spec *loads.Document) *FrostfsRestGwAPI { GetObjectInfoHandler: GetObjectInfoHandlerFunc(func(params GetObjectInfoParams, principal *models.Principal) middleware.Responder { return middleware.NotImplemented("operation GetObjectInfo has not yet been implemented") }), + GetStorageGroupHandler: GetStorageGroupHandlerFunc(func(params GetStorageGroupParams, principal *models.Principal) middleware.Responder { + return middleware.NotImplemented("operation GetStorageGroup has not yet been implemented") + }), ListContainersHandler: ListContainersHandlerFunc(func(params ListContainersParams) middleware.Responder { return middleware.NotImplemented("operation ListContainers has not yet been implemented") }), @@ -169,6 +175,8 @@ type FrostfsRestGwAPI struct { DeleteContainerHandler DeleteContainerHandler // DeleteObjectHandler sets the operation handler for the delete object operation DeleteObjectHandler DeleteObjectHandler + // DeleteStorageGroupHandler sets the operation handler for the delete storage group operation + DeleteStorageGroupHandler DeleteStorageGroupHandler // FormBinaryBearerHandler sets the operation handler for the form binary bearer operation FormBinaryBearerHandler FormBinaryBearerHandler // GetBalanceHandler sets the operation handler for the get balance operation @@ -179,6 +187,8 @@ type FrostfsRestGwAPI struct { GetContainerEACLHandler GetContainerEACLHandler // GetObjectInfoHandler sets the operation handler for the get object info operation GetObjectInfoHandler GetObjectInfoHandler + // GetStorageGroupHandler sets the operation handler for the get storage group operation + GetStorageGroupHandler GetStorageGroupHandler // ListContainersHandler sets the operation handler for the list containers operation ListContainersHandler ListContainersHandler // ListStorageGroupsHandler sets the operation handler for the list storage groups operation @@ -299,6 +309,9 @@ func (o *FrostfsRestGwAPI) Validate() error { if o.DeleteObjectHandler == nil { unregistered = append(unregistered, "DeleteObjectHandler") } + if o.DeleteStorageGroupHandler == nil { + unregistered = append(unregistered, "DeleteStorageGroupHandler") + } if o.FormBinaryBearerHandler == nil { unregistered = append(unregistered, "FormBinaryBearerHandler") } @@ -314,6 +327,9 @@ func (o *FrostfsRestGwAPI) Validate() error { if o.GetObjectInfoHandler == nil { unregistered = append(unregistered, "GetObjectInfoHandler") } + if o.GetStorageGroupHandler == nil { + unregistered = append(unregistered, "GetStorageGroupHandler") + } if o.ListContainersHandler == nil { unregistered = append(unregistered, "ListContainersHandler") } @@ -470,6 +486,10 @@ func (o *FrostfsRestGwAPI) initHandlerCache() { o.handlers["DELETE"] = make(map[string]http.Handler) } o.handlers["DELETE"]["/objects/{containerId}/{objectId}"] = NewDeleteObject(o.context, o.DeleteObjectHandler) + if o.handlers["DELETE"] == nil { + o.handlers["DELETE"] = make(map[string]http.Handler) + } + o.handlers["DELETE"]["/containers/{containerId}/storagegroups/{storageGroupId}"] = NewDeleteStorageGroup(o.context, o.DeleteStorageGroupHandler) if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) } @@ -493,6 +513,10 @@ func (o *FrostfsRestGwAPI) initHandlerCache() { if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) } + o.handlers["GET"]["/containers/{containerId}/storagegroups/{storageGroupId}"] = NewGetStorageGroup(o.context, o.GetStorageGroupHandler) + 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["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) diff --git a/gen/restapi/operations/get_storage_group.go b/gen/restapi/operations/get_storage_group.go new file mode 100644 index 0000000..2a2752e --- /dev/null +++ b/gen/restapi/operations/get_storage_group.go @@ -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" +) + +// GetStorageGroupHandlerFunc turns a function with the right signature into a get storage group handler +type GetStorageGroupHandlerFunc func(GetStorageGroupParams, *models.Principal) middleware.Responder + +// Handle executing the request and returning a response +func (fn GetStorageGroupHandlerFunc) Handle(params GetStorageGroupParams, principal *models.Principal) middleware.Responder { + return fn(params, principal) +} + +// GetStorageGroupHandler interface for that can handle valid get storage group params +type GetStorageGroupHandler interface { + Handle(GetStorageGroupParams, *models.Principal) middleware.Responder +} + +// NewGetStorageGroup creates a new http.Handler for the get storage group operation +func NewGetStorageGroup(ctx *middleware.Context, handler GetStorageGroupHandler) *GetStorageGroup { + return &GetStorageGroup{Context: ctx, Handler: handler} +} + +/* GetStorageGroup swagger:route GET /containers/{containerId}/storagegroups/{storageGroupId} getStorageGroup + +Get storage group info. + +*/ +type GetStorageGroup struct { + Context *middleware.Context + Handler GetStorageGroupHandler +} + +func (o *GetStorageGroup) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + route, rCtx, _ := o.Context.RouteInfo(r) + if rCtx != nil { + *r = *rCtx + } + var Params = NewGetStorageGroupParams() + 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) + +} diff --git a/gen/restapi/operations/get_storage_group_parameters.go b/gen/restapi/operations/get_storage_group_parameters.go new file mode 100644 index 0000000..1a77e23 --- /dev/null +++ b/gen/restapi/operations/get_storage_group_parameters.go @@ -0,0 +1,199 @@ +// 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" +) + +// NewGetStorageGroupParams creates a new GetStorageGroupParams object +// with the default values initialized. +func NewGetStorageGroupParams() GetStorageGroupParams { + + var ( + // initialize parameters with default values + + walletConnectDefault = bool(false) + ) + + return GetStorageGroupParams{ + WalletConnect: &walletConnectDefault, + } +} + +// GetStorageGroupParams contains all the bound params for the get storage group operation +// typically these are obtained from a http.Request +// +// swagger:parameters getStorageGroup +type GetStorageGroupParams struct { + + // HTTP Request Object + HTTPRequest *http.Request `json:"-"` + + /*Base64 encoded signature for bearer token. + Required: true + In: header + */ + XBearerSignature string + /*Hex encoded the public part of the key that signed the bearer token. + Required: true + In: header + */ + XBearerSignatureKey string + /*Base58 encoded container id. + Required: true + In: path + */ + ContainerID string + /*Base58 encoded storage group id. + Required: true + In: path + */ + StorageGroupID string + /*Use wallet connect signature scheme or native NeoFS signature. + In: query + Default: false + */ + WalletConnect *bool +} + +// 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 NewGetStorageGroupParams() beforehand. +func (o *GetStorageGroupParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { + var res []error + + o.HTTPRequest = r + + qs := runtime.Values(r.URL.Query()) + + if err := o.bindXBearerSignature(r.Header[http.CanonicalHeaderKey("X-Bearer-Signature")], true, route.Formats); err != nil { + res = append(res, err) + } + + if err := o.bindXBearerSignatureKey(r.Header[http.CanonicalHeaderKey("X-Bearer-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) + } + + rStorageGroupID, rhkStorageGroupID, _ := route.Params.GetOK("storageGroupId") + if err := o.bindStorageGroupID(rStorageGroupID, rhkStorageGroupID, route.Formats); err != nil { + res = append(res, err) + } + + qWalletConnect, qhkWalletConnect, _ := qs.GetOK("walletConnect") + if err := o.bindWalletConnect(qWalletConnect, qhkWalletConnect, route.Formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// bindXBearerSignature binds and validates parameter XBearerSignature from header. +func (o *GetStorageGroupParams) bindXBearerSignature(rawData []string, hasKey bool, formats strfmt.Registry) error { + if !hasKey { + return errors.Required("X-Bearer-Signature", "header", rawData) + } + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: true + + if err := validate.RequiredString("X-Bearer-Signature", "header", raw); err != nil { + return err + } + o.XBearerSignature = raw + + return nil +} + +// bindXBearerSignatureKey binds and validates parameter XBearerSignatureKey from header. +func (o *GetStorageGroupParams) bindXBearerSignatureKey(rawData []string, hasKey bool, formats strfmt.Registry) error { + if !hasKey { + return errors.Required("X-Bearer-Signature-Key", "header", rawData) + } + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: true + + if err := validate.RequiredString("X-Bearer-Signature-Key", "header", raw); err != nil { + return err + } + o.XBearerSignatureKey = raw + + return nil +} + +// bindContainerID binds and validates parameter ContainerID from path. +func (o *GetStorageGroupParams) 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 +} + +// bindStorageGroupID binds and validates parameter StorageGroupID from path. +func (o *GetStorageGroupParams) bindStorageGroupID(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.StorageGroupID = raw + + return nil +} + +// bindWalletConnect binds and validates parameter WalletConnect from query. +func (o *GetStorageGroupParams) bindWalletConnect(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 NewGetStorageGroupParams() + return nil + } + + value, err := swag.ConvertBool(raw) + if err != nil { + return errors.InvalidType("walletConnect", "query", "bool", raw) + } + o.WalletConnect = &value + + return nil +} diff --git a/gen/restapi/operations/get_storage_group_responses.go b/gen/restapi/operations/get_storage_group_responses.go new file mode 100644 index 0000000..293269b --- /dev/null +++ b/gen/restapi/operations/get_storage_group_responses.go @@ -0,0 +1,102 @@ +// 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" +) + +// GetStorageGroupOKCode is the HTTP code returned for type GetStorageGroupOK +const GetStorageGroupOKCode int = 200 + +/*GetStorageGroupOK Storage group information. + +swagger:response getStorageGroupOK +*/ +type GetStorageGroupOK struct { + + /* + In: Body + */ + Payload *models.StorageGroup `json:"body,omitempty"` +} + +// NewGetStorageGroupOK creates GetStorageGroupOK with default headers values +func NewGetStorageGroupOK() *GetStorageGroupOK { + + return &GetStorageGroupOK{} +} + +// WithPayload adds the payload to the get storage group o k response +func (o *GetStorageGroupOK) WithPayload(payload *models.StorageGroup) *GetStorageGroupOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get storage group o k response +func (o *GetStorageGroupOK) SetPayload(payload *models.StorageGroup) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetStorageGroupOK) 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 + } + } +} + +// GetStorageGroupBadRequestCode is the HTTP code returned for type GetStorageGroupBadRequest +const GetStorageGroupBadRequestCode int = 400 + +/*GetStorageGroupBadRequest Bad request. + +swagger:response getStorageGroupBadRequest +*/ +type GetStorageGroupBadRequest struct { + + /* + In: Body + */ + Payload *models.ErrorResponse `json:"body,omitempty"` +} + +// NewGetStorageGroupBadRequest creates GetStorageGroupBadRequest with default headers values +func NewGetStorageGroupBadRequest() *GetStorageGroupBadRequest { + + return &GetStorageGroupBadRequest{} +} + +// WithPayload adds the payload to the get storage group bad request response +func (o *GetStorageGroupBadRequest) WithPayload(payload *models.ErrorResponse) *GetStorageGroupBadRequest { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get storage group bad request response +func (o *GetStorageGroupBadRequest) SetPayload(payload *models.ErrorResponse) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetStorageGroupBadRequest) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(400) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/gen/restapi/operations/put_storage_group_parameters.go b/gen/restapi/operations/put_storage_group_parameters.go index 299dfc7..5e0d1de 100644 --- a/gen/restapi/operations/put_storage_group_parameters.go +++ b/gen/restapi/operations/put_storage_group_parameters.go @@ -63,7 +63,7 @@ type PutStorageGroupParams struct { Required: true In: body */ - StorageGroup *models.StorageGroup + StorageGroup *models.StorageGroupPutBody /*Use wallet connect signature scheme or native NeoFS signature. In: query Default: false @@ -97,7 +97,7 @@ func (o *PutStorageGroupParams) BindRequest(r *http.Request, route *middleware.M if runtime.HasBody(r) { defer r.Body.Close() - var body models.StorageGroup + var body models.StorageGroupPutBody if err := route.Consumer.Consume(r.Body, &body); err != nil { if err == io.EOF { res = append(res, errors.Required("storageGroup", "body", "")) diff --git a/handlers/storagegroup.go b/handlers/storagegroup.go index 2fb90d1..232f51a 100644 --- a/handlers/storagegroup.go +++ b/handlers/storagegroup.go @@ -1,8 +1,11 @@ package handlers import ( + "bytes" "context" + "encoding/hex" "fmt" + "io" "strconv" "github.com/go-openapi/runtime/middleware" @@ -153,7 +156,120 @@ func headObjectStorageGroupBaseInfo(ctx context.Context, p *pool.Pool, cnrID cid return resp, nil } -func (a *API) formStorageGroup(ctx context.Context, cnrID cid.ID, btoken bearer.Token, storageGroup *models.StorageGroup) (*storagegroup.StorageGroup, error) { +// DeleteStorageGroup handler that removes storage group from NeoFS. +func (a *API) DeleteStorageGroup(params operations.DeleteStorageGroupParams, principal *models.Principal) middleware.Responder { + ctx := params.HTTPRequest.Context() + + addr, err := parseAddress(params.ContainerID, params.StorageGroupID) + if err != nil { + resp := a.logAndGetErrorResponse("invalid address", err) + return operations.NewDeleteStorageGroupBadRequest().WithPayload(resp) + } + + btoken, err := getBearerToken(principal, params.XBearerSignature, params.XBearerSignatureKey, *params.WalletConnect) + if err != nil { + resp := a.logAndGetErrorResponse("failed to get bearer token", err) + return operations.NewDeleteStorageGroupBadRequest().WithPayload(resp) + } + + var prm pool.PrmObjectDelete + prm.SetAddress(addr) + prm.UseBearer(btoken) + + if err = a.pool.DeleteObject(ctx, prm); err != nil { + resp := a.logAndGetErrorResponse("failed to delete storage group", err) + return operations.NewDeleteStorageGroupBadRequest().WithPayload(resp) + } + + return operations.NewDeleteStorageGroupOK().WithPayload(util.NewSuccessResponse()) +} + +// GetStorageGroup handler that get storage group info. +func (a *API) GetStorageGroup(params operations.GetStorageGroupParams, principal *models.Principal) middleware.Responder { + errorResponse := operations.NewGetObjectInfoBadRequest() + ctx := params.HTTPRequest.Context() + + addr, err := parseAddress(params.ContainerID, params.StorageGroupID) + if err != nil { + resp := a.logAndGetErrorResponse("invalid address", err) + return errorResponse.WithPayload(resp) + } + + btoken, err := getBearerToken(principal, params.XBearerSignature, params.XBearerSignatureKey, *params.WalletConnect) + if err != nil { + resp := a.logAndGetErrorResponse("get bearer token", err) + return errorResponse.WithPayload(resp) + } + + var prm pool.PrmObjectGet + prm.SetAddress(addr) + prm.UseBearer(btoken) + + objRes, err := a.pool.GetObject(ctx, prm) + if err != nil { + resp := a.logAndGetErrorResponse("get storage group object", err) + return errorResponse.WithPayload(resp) + } + + sb, err := a.readStorageGroup(objRes) + if err != nil { + resp := a.logAndGetErrorResponse("read storage group", err) + return errorResponse.WithPayload(resp) + } + + var sbHash string + cs, ok := sb.ValidationDataHash() + if ok { + sbHash = hex.EncodeToString(cs.Value()) + } + + members := make([]string, len(sb.Members())) + for i, objID := range sb.Members() { + members[i] = objID.EncodeToString() + } + + resp := &models.StorageGroup{ + Address: &models.Address{ + ContainerID: util.NewString(addr.Container().String()), + ObjectID: util.NewString(addr.Object().String()), + }, + ExpirationEpoch: util.NewString(strconv.FormatUint(sb.ExpirationEpoch(), 10)), + Size: util.NewString(strconv.FormatUint(sb.ValidationDataSize(), 10)), + Hash: sbHash, + Members: members, + Name: getStorageGroupName(objRes.Header), + } + + return operations.NewGetStorageGroupOK().WithPayload(resp) +} + +func getStorageGroupName(obj object.Object) string { + for _, attribute := range obj.Attributes() { + if attribute.Key() == object.AttributeFileName { + return attribute.Value() + } + } + return "" +} + +func (a *API) readStorageGroup(objRes *pool.ResGetObject) (*storagegroup.StorageGroup, error) { + buf := bytes.NewBuffer(nil) + if _, err := io.Copy(buf, objRes.Payload); err != nil { + return nil, fmt.Errorf("failed to copy storage group payload: %w", err) + } + + obj := objRes.Header + obj.SetPayload(buf.Bytes()) + + var sb storagegroup.StorageGroup + if err := storagegroup.ReadFromObject(&sb, obj); err != nil { + return nil, fmt.Errorf("read storage group from object: %w", err) + } + + return &sb, nil +} + +func (a *API) formStorageGroup(ctx context.Context, cnrID cid.ID, btoken bearer.Token, storageGroup *models.StorageGroupPutBody) (*storagegroup.StorageGroup, error) { members, err := a.parseStorageGroupMembers(storageGroup) if err != nil { return nil, fmt.Errorf("parse storage group members: %w", err) @@ -257,7 +373,7 @@ func (a *API) getStorageGroupSizeAndHash(ctx context.Context, cnrID cid.ID, btok return sgSize, nil, nil } -func (a *API) parseStorageGroupMembers(storageGroup *models.StorageGroup) ([]oid.ID, error) { +func (a *API) parseStorageGroupMembers(storageGroup *models.StorageGroupPutBody) ([]oid.ID, error) { var err error members := make([]oid.ID, len(storageGroup.Members)) diff --git a/spec/rest.yaml b/spec/rest.yaml index 1224813..9a398eb 100644 --- a/spec/rest.yaml +++ b/spec/rest.yaml @@ -56,6 +56,12 @@ parameters: type: string required: true description: Base58 encoded object id. + storageGroupId: + in: path + name: storageGroupId + type: string + required: true + description: Base58 encoded storage group id. paths: /auth: @@ -572,7 +578,7 @@ paths: required: true description: Storage group co create. schema: - $ref: '#/definitions/StorageGroup' + $ref: '#/definitions/StorageGroupPutBody' responses: 200: description: Address of uploaded storage group. @@ -599,6 +605,43 @@ paths: schema: $ref: '#/definitions/ErrorResponse' + /containers/{containerId}/storagegroups/{storageGroupId}: + parameters: + - $ref: '#/parameters/containerId' + - $ref: '#/parameters/storageGroupId' + get: + operationId: getStorageGroup + summary: Get storage group info. + parameters: + - $ref: '#/parameters/signatureParam' + - $ref: '#/parameters/signatureKeyParam' + - $ref: '#/parameters/signatureScheme' + responses: + 200: + description: Storage group information. + schema: + $ref: '#/definitions/StorageGroup' + 400: + description: Bad request. + schema: + $ref: '#/definitions/ErrorResponse' + delete: + operationId: deleteStorageGroup + summary: Delete storage group from container. + parameters: + - $ref: '#/parameters/signatureParam' + - $ref: '#/parameters/signatureKeyParam' + - $ref: '#/parameters/signatureScheme' + responses: + 200: + description: Successful deletion. + schema: + $ref: '#/definitions/SuccessResponse' + 400: + description: Bad request. + schema: + $ref: '#/definitions/ErrorResponse' + definitions: BinaryBearer: description: Bearer token for object operations that is represented in binary form. @@ -1072,21 +1115,12 @@ definitions: value: myfile targets: - role: OTHERS - StorageGroup: - description: Storage group keeps verification information for Data Audit sessions. + StorageGroupPutBody: type: object properties: name: description: Name of storage group. It will be the value of the `FileName` attribute in storage group object. type: string - containerId: - description: Container id to which storage group is belong. Set by server. - type: string - readOnly: true - objectId: - description: Object id of storage group. Set by server. - type: string - readOnly: true lifetime: description: Lifetime in epochs for storage group. type: integer @@ -1098,6 +1132,33 @@ definitions: required: - lifetime - members + StorageGroup: + description: Storage group keeps verification information for Data Audit sessions. + type: object + properties: + name: + description: Name of storage group. It will be the value of the `FileName` attribute in storage group object. + type: string + address: + description: Address of storage group object. Set by server. + readOnly: true + $ref: '#/definitions/Address' + expirationEpoch: + type: string + hash: + type: string + size: + type: string + members: + description: Object identifiers to be placed into storage group. Must be unique. + type: array + items: + type: string + required: + - address + - expirationEpoch + - size + - members StorageGroupBaseInfo: description: Storage group info for listing. type: object