1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-25 08:19:40 +02:00

refactor(stacks): break swagger docs by type [EE-5381] (#8820)

This commit is contained in:
Chaim Lev-Ari 2023-04-27 11:03:55 +07:00 committed by GitHub
parent bbea0bc8a5
commit 77f8b9333a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 347 additions and 144 deletions

View file

@ -24,7 +24,7 @@ type composeStackFromFileContentPayload struct {
Name string `example:"myStack" validate:"required"`
// Content of the Stack file
StackFileContent string `example:"version: 3\n services:\n web:\n image:nginx" validate:"required"`
// A list of environment(endpoint) variables used during stack deployment
// A list of environment variables used during stack deployment
Env []portainer.Pair
// Whether the stack is from a app template
FromAppTemplate bool `example:"false"`
@ -87,6 +87,21 @@ func (handler *Handler) checkAndCleanStackDupFromSwarm(w http.ResponseWriter, r
return nil
}
// @id StackCreateDockerStandaloneString
// @summary Deploy a new compose stack from a text
// @description Deploy a new stack into a Docker environment specified via the environment identifier.
// @description **Access policy**: authenticated
// @tags stacks
// @security ApiKeyAuth
// @security jwt
// @accept json
// @produce json
// @param body body composeStackFromFileContentPayload true "stack config"
// @param endpointId query int true "Identifier of the environment that will be used to deploy the stack"
// @success 200 {object} portainer.Stack
// @failure 400 "Invalid request"
// @failure 500 "Server error"
// @router /stacks/create/standalone/string [post]
func (handler *Handler) createComposeStackFromFileContent(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError {
var payload composeStackFromFileContentPayload
err := request.DecodeAndValidateJSONPayload(r, &payload)
@ -158,7 +173,7 @@ type composeStackFromGitRepositoryPayload struct {
AdditionalFiles []string `example:"[nz.compose.yml, uat.compose.yml]"`
// Optional auto update configuration
AutoUpdate *portainer.AutoUpdateSettings
// A list of environment(endpoint) variables used during stack deployment
// A list of environment variables used during stack deployment
Env []portainer.Pair
// Whether the stack is from a app template
FromAppTemplate bool `example:"false"`
@ -201,6 +216,21 @@ func (payload *composeStackFromGitRepositoryPayload) Validate(r *http.Request) e
return nil
}
// @id StackCreateDockerStandaloneRepository
// @summary Deploy a new compose stack from repository
// @description Deploy a new stack into a Docker environment specified via the environment identifier.
// @description **Access policy**: authenticated
// @tags stacks
// @security ApiKeyAuth
// @security jwt
// @produce json
// @accept json
// @param endpointId query int true "Identifier of the environment that will be used to deploy the stack"
// @param body body composeStackFromGitRepositoryPayload true "stack config"
// @success 200 {object} portainer.Stack
// @failure 400 "Invalid request"
// @failure 500 "Server error"
// @router /stacks/create/standalone/repository [post]
func (handler *Handler) createComposeStackFromGitRepository(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError {
var payload composeStackFromGitRepositoryPayload
err := request.DecodeAndValidateJSONPayload(r, &payload)
@ -318,6 +348,23 @@ func decodeRequestForm(r *http.Request) (*composeStackFromFileUploadPayload, err
return payload, nil
}
// @id StackCreateDockerStandaloneFile
// @summary Deploy a new compose stack from a file
// @description Deploy a new stack into a Docker environment specified via the environment identifier.
// @description **Access policy**: authenticated
// @tags stacks
// @security ApiKeyAuth
// @security jwt
// @accept multipart/form-data
// @produce json
// @param Name formData string true "Name of the stack"
// @param Env formData string false "Environment variables passed during deployment, represented as a JSON array [{'name': 'name', 'value': 'value'}]."
// @param file formData file false "Stack file"
// @param endpointId query int true "Identifier of the environment that will be used to deploy the stack"
// @success 200 {object} portainer.Stack
// @failure 400 "Invalid request"
// @failure 500 "Server error"
// @router /stacks/create/standalone/file [post]
func (handler *Handler) createComposeStackFromFileUpload(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError {
payload, err := decodeRequestForm(r)
if err != nil {

View file

@ -12,6 +12,7 @@ import (
"github.com/portainer/libhttp/response"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/git/update"
"github.com/portainer/portainer/api/internal/endpointutils"
k "github.com/portainer/portainer/api/kubernetes"
"github.com/portainer/portainer/api/stacks/deployments"
"github.com/portainer/portainer/api/stacks/stackbuilders"
@ -131,7 +132,25 @@ type createKubernetesStackResponse struct {
Output string `json:"Output"`
}
// @id StackCreateKubernetesFile
// @summary Deploy a new kubernetes stack from a file
// @description Deploy a new stack into a Docker environment specified via the environment identifier.
// @description **Access policy**: authenticated
// @tags stacks
// @security ApiKeyAuth
// @security jwt
// @produce json
// @param body body kubernetesStringDeploymentPayload true "stack config"
// @param endpointId query int true "Identifier of the environment that will be used to deploy the stack"
// @success 200 {object} portainer.Stack
// @failure 400 "Invalid request"
// @failure 500 "Server error"
// @router /stacks/create/kubernetes/string [post]
func (handler *Handler) createKubernetesStackFromFileContent(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError {
if !endpointutils.IsKubernetesEndpoint(endpoint) {
return httperror.BadRequest("Environment type does not match", errors.New("Environment type does not match"))
}
var payload kubernetesStringDeploymentPayload
if err := request.DecodeAndValidateJSONPayload(r, &payload); err != nil {
return httperror.BadRequest("Invalid request payload", err)
@ -170,7 +189,25 @@ func (handler *Handler) createKubernetesStackFromFileContent(w http.ResponseWrit
return response.JSON(w, resp)
}
// @id StackCreateKubernetesGit
// @summary Deploy a new kubernetes stack from a git repository
// @description Deploy a new stack into a Docker environment specified via the environment identifier.
// @description **Access policy**: authenticated
// @tags stacks
// @security ApiKeyAuth
// @security jwt
// @produce json
// @param body body kubernetesGitDeploymentPayload true "stack config"
// @param endpointId query int true "Identifier of the environment that will be used to deploy the stack"
// @success 200 {object} portainer.Stack
// @failure 400 "Invalid request"
// @failure 500 "Server error"
// @router /stacks/create/kubernetes/repository [post]
func (handler *Handler) createKubernetesStackFromGitRepository(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError {
if !endpointutils.IsKubernetesEndpoint(endpoint) {
return httperror.BadRequest("Environment type does not match", errors.New("Environment type does not match"))
}
var payload kubernetesGitDeploymentPayload
if err := request.DecodeAndValidateJSONPayload(r, &payload); err != nil {
return httperror.BadRequest("Invalid request payload", err)
@ -234,6 +271,20 @@ func (handler *Handler) createKubernetesStackFromGitRepository(w http.ResponseWr
return response.JSON(w, resp)
}
// @id StackCreateKubernetesUrl
// @summary Deploy a new kubernetes stack from a url
// @description Deploy a new stack into a Docker environment specified via the environment identifier.
// @description **Access policy**: authenticated
// @tags stacks
// @security ApiKeyAuth
// @security jwt
// @produce json
// @param body body kubernetesManifestURLDeploymentPayload true "stack config"
// @param endpointId query int true "Identifier of the environment that will be used to deploy the stack"
// @success 200 {object} portainer.Stack
// @failure 400 "Invalid request"
// @failure 500 "Server error"
// @router /stacks/create/kubernetes/url [post]
func (handler *Handler) createKubernetesStackFromManifestURL(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError {
var payload kubernetesManifestURLDeploymentPayload
if err := request.DecodeAndValidateJSONPayload(r, &payload); err != nil {

View file

@ -23,7 +23,7 @@ type swarmStackFromFileContentPayload struct {
SwarmID string `example:"jpofkc0i9uo9wtx1zesuk649w" validate:"required"`
// Content of the Stack file
StackFileContent string `example:"version: 3\n services:\n web:\n image:nginx" validate:"required"`
// A list of environment(endpoint) variables used during stack deployment
// A list of environment variables used during stack deployment
Env []portainer.Pair
// Whether the stack is from a app template
FromAppTemplate bool `example:"false"`
@ -52,6 +52,21 @@ func createStackPayloadFromSwarmFileContentPayload(name string, swarmID string,
}
}
// @id StackCreateDockerSwarmString
// @summary Deploy a new swarm stack from a text
// @description Deploy a new stack into a Docker environment specified via the environment identifier.
// @description **Access policy**: authenticated
// @tags stacks
// @security ApiKeyAuth
// @security jwt
// @accept json
// @produce json
// @param body body swarmStackFromFileContentPayload true "stack config"
// @param endpointId query int true "Identifier of the environment that will be used to deploy the stack"
// @success 200 {object} portainer.Stack
// @failure 400 "Invalid request"
// @failure 500 "Server error"
// @router /stacks/create/swarm/string [post]
func (handler *Handler) createSwarmStackFromFileContent(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError {
var payload swarmStackFromFileContentPayload
err := request.DecodeAndValidateJSONPayload(r, &payload)
@ -96,7 +111,7 @@ type swarmStackFromGitRepositoryPayload struct {
Name string `example:"myStack" validate:"required"`
// Swarm cluster identifier
SwarmID string `example:"jpofkc0i9uo9wtx1zesuk649w" validate:"required"`
// A list of environment(endpoint) variables used during stack deployment
// A list of environment variables used during stack deployment
Env []portainer.Pair
// URL of a Git repository hosting the Stack file
@ -159,6 +174,21 @@ func createStackPayloadFromSwarmGitPayload(name, swarmID, repoUrl, repoReference
}
}
// @id StackCreateDockerSwarmRepository
// @summary Deploy a new swarm stack from a git repository
// @description Deploy a new stack into a Docker environment specified via the environment identifier.
// @description **Access policy**: authenticated
// @tags stacks
// @security ApiKeyAuth
// @security jwt
// @produce json
// @accept json
// @param endpointId query int true "Identifier of the environment that will be used to deploy the stack"
// @param body body swarmStackFromGitRepositoryPayload true "stack config"
// @success 200 {object} portainer.Stack
// @failure 400 "Invalid request"
// @failure 500 "Server error"
// @router /stacks/create/swarm/repository [post]
func (handler *Handler) createSwarmStackFromGitRepository(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError {
var payload swarmStackFromGitRepositoryPayload
err := request.DecodeAndValidateJSONPayload(r, &payload)
@ -267,8 +297,26 @@ func (payload *swarmStackFromFileUploadPayload) Validate(r *http.Request) error
return nil
}
// @id StackCreateDockerSwarmFile
// @summary Deploy a new swarm stack from a file
// @description Deploy a new stack into a Docker environment specified via the environment identifier.
// @description **Access policy**: authenticated
// @tags stacks
// @security ApiKeyAuth
// @security jwt
// @accept multipart/form-data
// @produce json
// @param Name formData string false "Name of the stack"
// @param SwarmID formData string false "Swarm cluster identifier."
// @param Env formData string false "Environment variables passed during deployment, represented as a JSON array [{'name': 'name', 'value': 'value'}]. Optional"
// @param file formData file false "Stack file"
// @param endpointId query int true "Identifier of the environment that will be used to deploy the stack"
// @success 200 {object} portainer.Stack
// @failure 400 "Invalid request"
// @failure 500 "Server error"
// @router /stacks/create/swarm/file [post]
func (handler *Handler) createSwarmStackFromFileUpload(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError {
payload := &swarmStackFromFileUploadPayload{}
var payload swarmStackFromFileUploadPayload
err := payload.Validate(r)
if err != nil {
return httperror.BadRequest("Invalid request payload", err)

View file

@ -55,7 +55,8 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
stackDeletionMutex: &sync.Mutex{},
requestBouncer: bouncer,
}
h.Handle("/stacks",
h.Handle("/stacks/create/{type}/{method}",
bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.stackCreate))).Methods(http.MethodPost)
h.Handle("/stacks",
bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.stackList))).Methods(http.MethodGet)

View file

@ -13,42 +13,15 @@ import (
"github.com/portainer/portainer/api/stacks/stackutils"
)
// @id StackCreate
// @summary Deploy a new stack
// @description Deploy a new stack into a Docker environment(endpoint) specified via the environment(endpoint) identifier.
// @description **Access policy**: authenticated
// @tags stacks
// @security ApiKeyAuth
// @security jwt
// @accept json,multipart/form-data
// @produce json
// @param type query int true "Stack deployment type. Possible values: 1 (Swarm stack), 2 (Compose stack) or 3 (Kubernetes stack)." Enums(1,2,3)
// @param method query string true "Stack deployment method. Possible values: file, string, repository or url." Enums(string, file, repository, url)
// @param endpointId query int true "Identifier of the environment(endpoint) that will be used to deploy the stack"
// @param body_swarm_string body swarmStackFromFileContentPayload false "Required when using method=string and type=1"
// @param body_swarm_repository body swarmStackFromGitRepositoryPayload false "Required when using method=repository and type=1"
// @param body_compose_string body composeStackFromFileContentPayload false "Required when using method=string and type=2"
// @param body_compose_repository body composeStackFromGitRepositoryPayload false "Required when using method=repository and type=2"
// @param body_kubernetes_string body kubernetesStringDeploymentPayload false "Required when using method=string and type=3"
// @param body_kubernetes_repository body kubernetesGitDeploymentPayload false "Required when using method=repository and type=3"
// @param body_kubernetes_url body kubernetesManifestURLDeploymentPayload false "Required when using method=url and type=3"
// @param Name formData string false "Name of the stack. required when method is file"
// @param SwarmID formData string false "Swarm cluster identifier. Required when method equals file and type equals 1. required when method is file"
// @param Env formData string false "Environment(Endpoint) variables passed during deployment, represented as a JSON array [{'name': 'name', 'value': 'value'}]. Optional, used when method equals file and type equals 1."
// @param file formData file false "Stack file. required when method is file"
// @success 200 {object} portainer.CustomTemplate
// @failure 400 "Invalid request"
// @failure 500 "Server error"
// @router /stacks [post]
func (handler *Handler) stackCreate(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
stackType, err := request.RetrieveNumericQueryParameter(r, "type", false)
stackType, err := request.RetrieveRouteVariableValue(r, "type")
if err != nil {
return httperror.BadRequest("Invalid query parameter: type", err)
return httperror.BadRequest("Invalid path parameter: type", err)
}
method, err := request.RetrieveQueryParameter(r, "method", false)
method, err := request.RetrieveRouteVariableValue(r, "method")
if err != nil {
return httperror.BadRequest("Invalid query parameter: method", err)
return httperror.BadRequest("Invalid path parameter: method", err)
}
endpointID, err := request.RetrieveNumericQueryParameter(r, "endpointId", false)
@ -87,12 +60,12 @@ func (handler *Handler) stackCreate(w http.ResponseWriter, r *http.Request) *htt
return httperror.InternalServerError("Unable to retrieve user details from authentication token", err)
}
switch portainer.StackType(stackType) {
case portainer.DockerSwarmStack:
switch stackType {
case "swarm":
return handler.createSwarmStack(w, r, method, endpoint, tokenData.ID)
case portainer.DockerComposeStack:
case "standalone":
return handler.createComposeStack(w, r, method, endpoint, tokenData.ID)
case portainer.KubernetesStack:
case "kubernetes":
return handler.createKubernetesStack(w, r, method, endpoint, tokenData.ID)
}