#2732 feat(stacks): extracting string stack payload validation

pull/12341/head
Cesar Munoz 2024-10-20 14:46:50 +02:00
parent f9b7d05df7
commit 35834c65ea
No known key found for this signature in database
GPG Key ID: 1211B71005DDB995
1 changed files with 36 additions and 28 deletions

View File

@ -104,34 +104,9 @@ func (handler *Handler) checkAndCleanStackDupFromSwarm(w http.ResponseWriter, r
// @failure 500 "Server error" // @failure 500 "Server error"
// @router /stacks/create/standalone/string [post] // @router /stacks/create/standalone/string [post]
func (handler *Handler) createComposeStackFromFileContent(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError { func (handler *Handler) createComposeStackFromFileContent(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError {
var payload composeStackFromFileContentPayload payload, handlerError := handler.getValidatedPayload(w, r, endpoint, userID)
err := request.DecodeAndValidateJSONPayload(r, &payload) if handlerError != nil {
if err != nil { return handlerError
return httperror.BadRequest("Invalid request payload", err)
}
payload.Name = handler.ComposeStackManager.NormalizeStackName(payload.Name)
isUnique, err := handler.checkUniqueStackNameInDocker(endpoint, payload.Name, 0, false)
if err != nil {
return httperror.InternalServerError("Unable to check for name collision", err)
}
if !isUnique {
stacks, err := handler.DataStore.Stack().StacksByName(payload.Name)
if err != nil {
return stackExistsError(payload.Name)
}
for _, stack := range stacks {
if stack.Type != portainer.DockerComposeStack && stack.EndpointID == endpoint.ID {
err := handler.checkAndCleanStackDupFromSwarm(w, r, endpoint, userID, &stack)
if err != nil {
return httperror.BadRequest("Invalid request payload", err)
}
} else {
return stackExistsError(payload.Name)
}
}
} }
securityContext, err := security.RetrieveRestrictedRequestContext(r) securityContext, err := security.RetrieveRestrictedRequestContext(r)
@ -155,6 +130,39 @@ func (handler *Handler) createComposeStackFromFileContent(w http.ResponseWriter,
return handler.decorateStackResponse(w, stack, userID) return handler.decorateStackResponse(w, stack, userID)
} }
func (handler *Handler) getValidatedPayload(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) (*composeStackFromFileContentPayload, *httperror.HandlerError) {
var payload composeStackFromFileContentPayload
err := request.DecodeAndValidateJSONPayload(r, &payload)
if err != nil {
return nil, httperror.BadRequest("Invalid request payload", err)
}
payload.Name = handler.ComposeStackManager.NormalizeStackName(payload.Name)
isUnique, err := handler.checkUniqueStackNameInDocker(endpoint, payload.Name, 0, false)
if err != nil {
return nil, httperror.InternalServerError("Unable to check for name collision", err)
}
if !isUnique {
stacks, err := handler.DataStore.Stack().StacksByName(payload.Name)
if err != nil {
return nil, stackExistsError(payload.Name)
}
for _, stack := range stacks {
if stack.Type != portainer.DockerComposeStack && stack.EndpointID == endpoint.ID {
err := handler.checkAndCleanStackDupFromSwarm(w, r, endpoint, userID, &stack)
if err != nil {
return nil, httperror.BadRequest("Invalid request payload", err)
}
} else {
return nil, stackExistsError(payload.Name)
}
}
}
return &payload, nil
}
type composeStackFromGitRepositoryPayload struct { type composeStackFromGitRepositoryPayload struct {
// Name of the stack // Name of the stack
Name string `example:"myStack" validate:"required"` Name string `example:"myStack" validate:"required"`