2021-06-10 02:52:33 +00:00
package stacks
import (
"fmt"
2021-08-17 01:12:07 +00:00
"net/http"
"time"
2021-06-10 02:52:33 +00:00
httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request"
"github.com/portainer/libhttp/response"
portainer "github.com/portainer/portainer/api"
bolterrors "github.com/portainer/portainer/api/bolt/errors"
"github.com/portainer/portainer/api/http/security"
"github.com/portainer/portainer/api/internal/stackutils"
)
2021-10-11 23:12:08 +00:00
// @id StackAssociate
// @summary Associate an orphaned stack to a new environment(endpoint)
// @description **Access policy**: administrator
// @tags stacks
2021-11-30 02:31:16 +00:00
// @security ApiKeyAuth
2021-10-11 23:12:08 +00:00
// @security jwt
// @produce json
// @param id path int true "Stack identifier"
// @param endpointId query int true "Stacks created before version 1.18.0 might not have an associated environment(endpoint) identifier. Use this optional parameter to set the environment(endpoint) identifier used by the stack."
// @param swarmId query int true "Swarm identifier"
// @param orphanedRunning query boolean true "Indicates whether the stack is orphaned"
// @success 200 {object} portainer.Stack "Success"
// @failure 400 "Invalid request"
// @failure 403 "Permission denied"
// @failure 404 "Stack not found"
// @failure 500 "Server error"
// @router /stacks/{id}/associate [put]
2021-06-10 02:52:33 +00:00
func ( handler * Handler ) stackAssociate ( w http . ResponseWriter , r * http . Request ) * httperror . HandlerError {
stackID , err := request . RetrieveNumericRouteVariableValue ( r , "id" )
if err != nil {
return & httperror . HandlerError { http . StatusBadRequest , "Invalid stack identifier route variable" , err }
}
endpointID , err := request . RetrieveNumericQueryParameter ( r , "endpointId" , false )
if err != nil {
return & httperror . HandlerError { http . StatusBadRequest , "Invalid query parameter: endpointId" , err }
}
swarmId , err := request . RetrieveQueryParameter ( r , "swarmId" , true )
if err != nil {
return & httperror . HandlerError { http . StatusBadRequest , "Invalid query parameter: swarmId" , err }
}
orphanedRunning , err := request . RetrieveBooleanQueryParameter ( r , "orphanedRunning" , false )
if err != nil {
return & httperror . HandlerError { http . StatusBadRequest , "Invalid query parameter: orphanedRunning" , err }
}
securityContext , err := security . RetrieveRestrictedRequestContext ( r )
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to retrieve info from request context" , err }
}
user , err := handler . DataStore . User ( ) . User ( securityContext . UserID )
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to load user information from the database" , err }
}
stack , err := handler . DataStore . Stack ( ) . Stack ( portainer . StackID ( stackID ) )
if err == bolterrors . ErrObjectNotFound {
return & httperror . HandlerError { http . StatusNotFound , "Unable to find a stack with the specified identifier inside the database" , err }
} else if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to find a stack with the specified identifier inside the database" , err }
}
resourceControl , err := handler . DataStore . ResourceControl ( ) . ResourceControlByResourceIDAndType ( stackutils . ResourceControlID ( stack . EndpointID , stack . Name ) , portainer . StackResourceControl )
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to retrieve a resource control associated to the stack" , err }
}
if resourceControl != nil {
resourceControl . ResourceID = fmt . Sprintf ( "%d_%s" , endpointID , stack . Name )
err = handler . DataStore . ResourceControl ( ) . UpdateResourceControl ( resourceControl . ID , resourceControl )
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to persist resource control changes inside the database" , err }
}
}
stack . EndpointID = portainer . EndpointID ( endpointID )
stack . SwarmID = swarmId
if orphanedRunning {
stack . Status = portainer . StackStatusActive
} else {
stack . Status = portainer . StackStatusInactive
}
stack . CreationDate = time . Now ( ) . Unix ( )
stack . CreatedBy = user . Username
stack . UpdateDate = 0
stack . UpdatedBy = ""
err = handler . DataStore . Stack ( ) . UpdateStack ( stack . ID , stack )
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to persist the stack changes inside the database" , err }
}
stack . ResourceControl = resourceControl
2021-08-17 01:12:07 +00:00
if stack . GitConfig != nil && stack . GitConfig . Authentication != nil && stack . GitConfig . Authentication . Password != "" {
// sanitize password in the http response to minimise possible security leaks
stack . GitConfig . Authentication . Password = ""
}
2021-06-10 02:52:33 +00:00
return response . JSON ( w , stack )
}