mirror of https://github.com/portainer/portainer
				
				
				
			fix(api): restore deleted apis [EE-6090] (#10267)
							parent
							
								
									14853f6da0
								
							
						
					
					
						commit
						af7834174a
					
				| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
package datastore
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	portaineree "github.com/portainer/portainer/api"
 | 
			
		||||
	portainer "github.com/portainer/portainer/api"
 | 
			
		||||
	"github.com/portainer/portainer/api/database/models"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -72,7 +72,7 @@ func dbVersionToSemanticVersion(dbVersion int) string {
 | 
			
		|||
func (store *Store) getOrMigrateLegacyVersion() (*models.Version, error) {
 | 
			
		||||
	// Very old versions of portainer did not have a version bucket, lets set some defaults
 | 
			
		||||
	dbVersion := 24
 | 
			
		||||
	edition := int(portaineree.PortainerCE)
 | 
			
		||||
	edition := int(portainer.PortainerCE)
 | 
			
		||||
	instanceId := ""
 | 
			
		||||
 | 
			
		||||
	// If we already have a version key, we don't need to migrate
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@ package customtemplates
 | 
			
		|||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
	"regexp"
 | 
			
		||||
| 
						 | 
				
			
			@ -473,3 +474,29 @@ func (handler *Handler) createCustomTemplateFromFileUpload(r *http.Request) (*po
 | 
			
		|||
 | 
			
		||||
	return customTemplate, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// @id CustomTemplateCreate
 | 
			
		||||
// @summary Create a custom template
 | 
			
		||||
// @description Create a custom template.
 | 
			
		||||
// @description **Access policy**: authenticated
 | 
			
		||||
// @tags custom_templates
 | 
			
		||||
// @security ApiKeyAuth
 | 
			
		||||
// @security jwt
 | 
			
		||||
// @accept json,multipart/form-data
 | 
			
		||||
// @produce json
 | 
			
		||||
// @param method query string true "method for creating template" Enums(string, file, repository)
 | 
			
		||||
// @param body body object true "for body documentation see the relevant /custom_templates/{method} endpoint"
 | 
			
		||||
// @success 200 {object} portainer.CustomTemplate
 | 
			
		||||
// @failure 400 "Invalid request"
 | 
			
		||||
// @failure 500 "Server error"
 | 
			
		||||
// @deprecated
 | 
			
		||||
// @router /custom_templates [post]
 | 
			
		||||
func deprecatedCustomTemplateCreateUrlParser(w http.ResponseWriter, r *http.Request) (string, *httperror.HandlerError) {
 | 
			
		||||
	method, err := request.RetrieveQueryParameter(r, "method", false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", httperror.BadRequest("Invalid query parameter: method", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	url := fmt.Sprintf("/custom_templates/create/%s", method)
 | 
			
		||||
	return url, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@ import (
 | 
			
		|||
	"github.com/gorilla/mux"
 | 
			
		||||
	portainer "github.com/portainer/portainer/api"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices"
 | 
			
		||||
	"github.com/portainer/portainer/api/http/middlewares"
 | 
			
		||||
	"github.com/portainer/portainer/api/http/security"
 | 
			
		||||
	httperror "github.com/portainer/portainer/pkg/libhttp/error"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -32,6 +33,7 @@ func NewHandler(bouncer security.BouncerService, dataStore dataservices.DataStor
 | 
			
		|||
 | 
			
		||||
	h.Handle("/custom_templates/create/{method}",
 | 
			
		||||
		bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.customTemplateCreate))).Methods(http.MethodPost)
 | 
			
		||||
	h.Handle("/custom_templates", middlewares.Deprecated(h, deprecatedCustomTemplateCreateUrlParser)).Methods(http.MethodPost) // Deprecated
 | 
			
		||||
	h.Handle("/custom_templates",
 | 
			
		||||
		bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.customTemplateList))).Methods(http.MethodGet)
 | 
			
		||||
	h.Handle("/custom_templates/{id}",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@ package edgejobs
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"maps"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strconv"
 | 
			
		||||
| 
						 | 
				
			
			@ -278,3 +279,26 @@ func (handler *Handler) addAndPersistEdgeJob(tx dataservices.DataStoreTx, edgeJo
 | 
			
		|||
 | 
			
		||||
	return tx.EdgeJob().CreateWithID(edgeJob.ID, edgeJob)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// @id EdgeJobCreate
 | 
			
		||||
// @summary Create an EdgeJob
 | 
			
		||||
// @description **Access policy**: administrator
 | 
			
		||||
// @tags edge_jobs
 | 
			
		||||
// @security ApiKeyAuth
 | 
			
		||||
// @security jwt
 | 
			
		||||
// @produce json
 | 
			
		||||
// @param method query string true "Creation Method" Enums(file, string)
 | 
			
		||||
// @param body body object true "for body documentation see the relevant /edge_jobs/create/{method} endpoint"
 | 
			
		||||
// @success 200 {object} portainer.EdgeGroup
 | 
			
		||||
// @failure 503 "Edge compute features are disabled"
 | 
			
		||||
// @failure 500
 | 
			
		||||
// @deprecated
 | 
			
		||||
// @router /edge_jobs [post]
 | 
			
		||||
func deprecatedEdgeJobCreateUrlParser(w http.ResponseWriter, r *http.Request) (string, *httperror.HandlerError) {
 | 
			
		||||
	method, err := request.RetrieveQueryParameter(r, "method", false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", httperror.BadRequest("Invalid query parameter: method. Valid values are: file or string", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return fmt.Sprintf("/edge_jobs/create/%s", method), nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@ import (
 | 
			
		|||
 | 
			
		||||
	portainer "github.com/portainer/portainer/api"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices"
 | 
			
		||||
	"github.com/portainer/portainer/api/http/middlewares"
 | 
			
		||||
	"github.com/portainer/portainer/api/http/security"
 | 
			
		||||
	httperror "github.com/portainer/portainer/pkg/libhttp/error"
 | 
			
		||||
	"github.com/portainer/portainer/pkg/libhttp/response"
 | 
			
		||||
| 
						 | 
				
			
			@ -29,6 +30,8 @@ func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		|||
 | 
			
		||||
	h.Handle("/edge_jobs",
 | 
			
		||||
		bouncer.AdminAccess(bouncer.EdgeComputeOperation(httperror.LoggerHandler(h.edgeJobList)))).Methods(http.MethodGet)
 | 
			
		||||
	h.Handle("/edge_jobs",
 | 
			
		||||
		bouncer.AdminAccess(bouncer.EdgeComputeOperation(middlewares.Deprecated(h, deprecatedEdgeJobCreateUrlParser)))).Methods(http.MethodPost)
 | 
			
		||||
	h.Handle("/edge_jobs/create/{method}",
 | 
			
		||||
		bouncer.AdminAccess(bouncer.EdgeComputeOperation(httperror.LoggerHandler(h.edgeJobCreate)))).Methods(http.MethodPost)
 | 
			
		||||
	h.Handle("/edge_jobs/{id}",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
package edgestacks
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	portainer "github.com/portainer/portainer/api"
 | 
			
		||||
| 
						 | 
				
			
			@ -17,6 +18,7 @@ func (handler *Handler) edgeStackCreate(w http.ResponseWriter, r *http.Request)
 | 
			
		|||
	if err != nil {
 | 
			
		||||
		return httperror.BadRequest("Invalid query parameter: method", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dryrun, _ := request.RetrieveBooleanQueryParameter(r, "dryrun", true)
 | 
			
		||||
 | 
			
		||||
	tokenData, err := security.RetrieveTokenData(r)
 | 
			
		||||
| 
						 | 
				
			
			@ -55,3 +57,26 @@ func (handler *Handler) createSwarmStack(tx dataservices.DataStoreTx, method str
 | 
			
		|||
 | 
			
		||||
	return nil, httperrors.NewInvalidPayloadError("Invalid value for query parameter: method. Value must be one of: string, repository or file")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// @id EdgeStackCreate
 | 
			
		||||
// @summary Create an EdgeStack
 | 
			
		||||
// @description **Access policy**: administrator
 | 
			
		||||
// @tags edge_stacks
 | 
			
		||||
// @security ApiKeyAuth
 | 
			
		||||
// @security jwt
 | 
			
		||||
// @produce json
 | 
			
		||||
// @param method query string true "Creation Method" Enums(file,string,repository)
 | 
			
		||||
// @param body body object true "for body documentation see the relevant /edge_stacks/create/{method} endpoint"
 | 
			
		||||
// @success 200 {object} portainer.EdgeStack
 | 
			
		||||
// @failure 500
 | 
			
		||||
// @failure 503 "Edge compute features are disabled"
 | 
			
		||||
// @deprecated
 | 
			
		||||
// @router /edge_stacks [post]
 | 
			
		||||
func deprecatedEdgeStackCreateUrlParser(w http.ResponseWriter, r *http.Request) (string, *httperror.HandlerError) {
 | 
			
		||||
	method, err := request.RetrieveQueryParameter(r, "method", false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", httperror.BadRequest("Invalid query parameter: method. Valid values are: file or string", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return fmt.Sprintf("/edge_stacks/create/%s", method), nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,6 +39,8 @@ func NewHandler(bouncer security.BouncerService, dataStore dataservices.DataStor
 | 
			
		|||
 | 
			
		||||
	h.Handle("/edge_stacks/create/{method}",
 | 
			
		||||
		bouncer.AdminAccess(bouncer.EdgeComputeOperation(httperror.LoggerHandler(h.edgeStackCreate)))).Methods(http.MethodPost)
 | 
			
		||||
	h.Handle("/edge_stacks",
 | 
			
		||||
		bouncer.AdminAccess(bouncer.EdgeComputeOperation(middlewares.Deprecated(h, deprecatedEdgeStackCreateUrlParser)))).Methods(http.MethodPost) // Deprecated
 | 
			
		||||
	h.Handle("/edge_stacks",
 | 
			
		||||
		bouncer.AdminAccess(bouncer.EdgeComputeOperation(httperror.LoggerHandler(h.edgeStackList)))).Methods(http.MethodGet)
 | 
			
		||||
	h.Handle("/edge_stacks/{id}",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,7 @@ import (
 | 
			
		|||
	portainer "github.com/portainer/portainer/api"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices"
 | 
			
		||||
	dockerclient "github.com/portainer/portainer/api/docker/client"
 | 
			
		||||
	"github.com/portainer/portainer/api/http/middlewares"
 | 
			
		||||
	"github.com/portainer/portainer/api/http/security"
 | 
			
		||||
	"github.com/portainer/portainer/api/internal/authorization"
 | 
			
		||||
	"github.com/portainer/portainer/api/internal/endpointutils"
 | 
			
		||||
| 
						 | 
				
			
			@ -59,6 +60,8 @@ func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		|||
 | 
			
		||||
	h.Handle("/stacks/create/{type}/{method}",
 | 
			
		||||
		bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.stackCreate))).Methods(http.MethodPost)
 | 
			
		||||
	h.Handle("/stacks",
 | 
			
		||||
		bouncer.AuthenticatedAccess(middlewares.Deprecated(h, deprecatedStackCreateUrlParser))).Methods(http.MethodPost) // Deprecated
 | 
			
		||||
	h.Handle("/stacks",
 | 
			
		||||
		bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.stackList))).Methods(http.MethodGet)
 | 
			
		||||
	h.Handle("/stacks/{id}",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
package stacks
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	portainer "github.com/portainer/portainer/api"
 | 
			
		||||
| 
						 | 
				
			
			@ -140,3 +141,53 @@ func (handler *Handler) decorateStackResponse(w http.ResponseWriter, stack *port
 | 
			
		|||
 | 
			
		||||
	return response.JSON(w, stack)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getStackTypeFromQueryParameter(r *http.Request) (string, error) {
 | 
			
		||||
	stackType, err := request.RetrieveNumericQueryParameter(r, "type", false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch stackType {
 | 
			
		||||
	case 1:
 | 
			
		||||
		return "swarm", nil
 | 
			
		||||
	case 2:
 | 
			
		||||
		return "standalone", nil
 | 
			
		||||
	case 3:
 | 
			
		||||
		return "kubernetes", nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return "", errors.New(request.ErrInvalidQueryParameter)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// @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 body object true "for body documentation see the relevant /stacks/create/{type}/{method} endpoint"
 | 
			
		||||
// @success 200 {object} portainer.Stack
 | 
			
		||||
// @failure 400 "Invalid request"
 | 
			
		||||
// @failure 500 "Server error"
 | 
			
		||||
// @deprecated
 | 
			
		||||
// @router /stacks [post]
 | 
			
		||||
func deprecatedStackCreateUrlParser(w http.ResponseWriter, r *http.Request) (string, *httperror.HandlerError) {
 | 
			
		||||
	method, err := request.RetrieveQueryParameter(r, "method", false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", httperror.BadRequest("Invalid query parameter: method. Valid values are: file or string", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	stackType, err := getStackTypeFromQueryParameter(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", httperror.BadRequest("Invalid query parameter: type", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return fmt.Sprintf("/stacks/create/%s/%s", stackType, method), nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
package middlewares
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	httperror "github.com/portainer/portainer/pkg/libhttp/error"
 | 
			
		||||
	"github.com/rs/zerolog/log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// deprecate api route
 | 
			
		||||
func Deprecated(router http.Handler, urlBuilder func(w http.ResponseWriter, r *http.Request) (string, *httperror.HandlerError)) http.Handler {
 | 
			
		||||
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		newUrl, err := urlBuilder(w, r)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			httperror.WriteError(w, err.StatusCode, err.Error(), err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		log.Warn().Msgf("This api is deprecated. Use %s instead", newUrl)
 | 
			
		||||
 | 
			
		||||
		redirectedRequest := r.Clone(r.Context())
 | 
			
		||||
		redirectedRequest.URL.Path = newUrl
 | 
			
		||||
		router.ServeHTTP(w, redirectedRequest)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue