Skip to content

Commit

Permalink
fix(api): restore deleted apis [EE-6090] (#10266)
Browse files Browse the repository at this point in the history
  • Loading branch information
chiptus committed Sep 19, 2023
1 parent 4694950 commit 6f81fcc
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 2 deletions.
4 changes: 2 additions & 2 deletions api/datastore/migrate_legacyversion.go
Original file line number Diff line number Diff line change
@@ -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"
)
Expand Down Expand Up @@ -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
Expand Down
27 changes: 27 additions & 0 deletions api/http/handler/customtemplates/customtemplate_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package customtemplates
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"os"
"regexp"
Expand Down Expand Up @@ -472,3 +473,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
}
2 changes: 2 additions & 0 deletions api/http/handler/customtemplates/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
httperror "github.com/portainer/libhttp/error"
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"
)

Expand All @@ -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}",
Expand Down
24 changes: 24 additions & 0 deletions api/http/handler/edgejobs/edgejob_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package edgejobs

import (
"errors"
"fmt"
"net/http"
"strconv"
"strings"
Expand Down Expand Up @@ -287,3 +288,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
}
3 changes: 3 additions & 0 deletions api/http/handler/edgejobs/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/portainer/libhttp/response"
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"

"github.com/gorilla/mux"
Expand All @@ -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}",
Expand Down
25 changes: 25 additions & 0 deletions api/http/handler/edgestacks/edgestack_create.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package edgestacks

import (
"fmt"
"net/http"

httperror "github.com/portainer/libhttp/error"
Expand All @@ -18,6 +19,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)
Expand Down Expand Up @@ -60,3 +62,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
}
2 changes: 2 additions & 0 deletions api/http/handler/edgestacks/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,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}",
Expand Down
3 changes: 3 additions & 0 deletions api/http/handler/stacks/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,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"
Expand Down Expand Up @@ -58,6 +59,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}",
Expand Down
51 changes: 51 additions & 0 deletions api/http/handler/stacks/stack_create.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package stacks

import (
"fmt"
"net/http"

"github.com/pkg/errors"
Expand Down Expand Up @@ -139,3 +140,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
}
25 changes: 25 additions & 0 deletions api/http/middlewares/deprecated.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package middlewares

import (
"net/http"

httperror "github.com/portainer/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)
})
}

0 comments on commit 6f81fcc

Please sign in to comment.