@ -18,43 +18,41 @@ import (
"github.com/rs/zerolog/log"
"github.com/rs/zerolog/log"
)
)
type DeleteMultiplePayload struct {
type endpointDeleteRequest struct {
Endpoints [ ] struct {
ID int ` json:"id" `
ID int ` json:"id" `
DeleteCluster bool ` json:"deleteCluster" `
Name string ` json:"name" `
DeleteCluster bool ` json:"deleteCluster" `
} ` json:"environments" `
}
}
func ( payload * DeleteMultiplePayload ) Validate ( r * http . Request ) error {
type endpointDeleteBatchPayload struct {
Endpoints [ ] endpointDeleteRequest ` json:"endpoints" `
}
type endpointDeleteBatchPartialResponse struct {
Deleted [ ] int ` json:"deleted" `
Errors [ ] int ` json:"errors" `
}
func ( payload * endpointDeleteBatchPayload ) Validate ( r * http . Request ) error {
if payload == nil || len ( payload . Endpoints ) == 0 {
if payload == nil || len ( payload . Endpoints ) == 0 {
return fmt . Errorf ( "invalid request payload; you must provide a list of nodes to delete" )
return fmt . Errorf ( "invalid request payload . You must provide a list of environment s to delete")
}
}
return nil
return nil
}
}
type DeleteMultipleResp struct {
Name string ` json:"name" `
Err error ` json:"err" `
}
// @id EndpointDelete
// @id EndpointDelete
// @summary Remove an environment (endpoint)
// @summary Remove an environment
// @description Remove an environment(endpoint) .
// @description Remove the environment associated to the specified identifier and optionally clean-up associated resources.
// @description **Access policy**: administrator
// @description **Access policy**: Administrator only.
// @tags endpoints
// @tags endpoints
// @security ApiKeyAuth
// @security ApiKeyAuth || jwt
// @security jwt
// @param id path int true "Environment(Endpoint) identifier"
// @param id path int true "Environment(Endpoint) identifier"
// @success 204 " Success "
// @success 204 " Environment successfully deleted. "
// @failure 400 "Invalid request "
// @failure 400 "Invalid request payload, such as missing required fields or fields not meeting validation criteria. "
// @failure 403 " Permission denied "
// @failure 403 " Unauthorized access or operation not allowed. "
// @failure 404 " Environment(Endpoint) not found "
// @failure 404 " Unable to find the environment with the specified identifier inside the database. "
// @failure 500 "Server error "
// @failure 500 "Server error occurred while attempting to delete the environment. "
// @router /endpoints/{id} [delete]
// @router /endpoints/{id} [delete]
// @deprecated
// Deprecated: use endpointDeleteMultiple instead.
func ( handler * Handler ) endpointDelete ( w http . ResponseWriter , r * http . Request ) * httperror . HandlerError {
func ( handler * Handler ) endpointDelete ( w http . ResponseWriter , r * http . Request ) * httperror . HandlerError {
endpointID , err := request . RetrieveNumericRouteVariableValue ( r , "id" )
endpointID , err := request . RetrieveNumericRouteVariableValue ( r , "id" )
if err != nil {
if err != nil {
@ -86,58 +84,61 @@ func (handler *Handler) endpointDelete(w http.ResponseWriter, r *http.Request) *
return response . Empty ( w )
return response . Empty ( w )
}
}
// @id EndpointDelete Multiple
// @id EndpointDelete Batch
// @summary Remove multiple environment (endpoint) s
// @summary Remove multiple environment s
// @description Remove multiple environment (endpoint) s.
// @description Remove multiple environment s and optionally clean-up associated resource s.
// @description **Access policy**: administrator
// @description **Access policy**: Administrator only.
// @tags endpoints
// @tags endpoints
// @security ApiKeyAuth
// @security ApiKeyAuth || jwt
// @security jwt
// @accept json
// @accept json
// @produce json
// @produce json
// @param body body DeleteMultiplePayload true "List of endpoints to delete "
// @param body body endpointDeleteBatchPayload true "List of environments to delete, with optional deleteCluster flag to clean-up assocaited resources (cloud environments only) "
// @success 204 " Success "
// @success 204 " Environment(s) successfully deleted. "
// @failure 400 "Invalid request "
// @failure 207 {object} endpointDeleteBatchPartialResponse "Partial success. Some environments were deleted successfully, while others failed. "
// @failure 40 3 "Permission denied "
// @failure 40 0 "Invalid request payload, such as missing required fields or fields not meeting validation criteria. "
// @failure 40 4 "Environment(Endpoint) not found "
// @failure 40 3 "Unauthorized access or operation not allowed. "
// @failure 500 "Server error "
// @failure 500 "Server error occurred while attempting to delete the specified environments. "
// @router /endpoints /remove [post ]
// @router /endpoints [delete ]
func ( handler * Handler ) endpointDelete Multiple ( w http . ResponseWriter , r * http . Request ) * httperror . HandlerError {
func ( handler * Handler ) endpointDelete Batch ( w http . ResponseWriter , r * http . Request ) * httperror . HandlerError {
var p DeleteMultiple Payload
var p endpointDeleteBatch Payload
if err := request . DecodeAndValidateJSONPayload ( r , & p ) ; err != nil {
if err := request . DecodeAndValidateJSONPayload ( r , & p ) ; err != nil {
return httperror . BadRequest ( "Invalid request payload" , err )
return httperror . BadRequest ( "Invalid request payload" , err )
}
}
var resps [ ] DeleteMultipleResp
resp := endpointDeleteBatchPartialResponse {
Deleted : [ ] int { } ,
Errors : [ ] int { } ,
}
err := handler . DataStore . UpdateTx ( func ( tx dataservices . DataStoreTx ) error {
if err := handler . DataStore . UpdateTx ( func ( tx dataservices . DataStoreTx ) error {
for _ , e := range p . Endpoints {
for _ , e := range p . Endpoints {
// Demo endpoints cannot be deleted.
if handler . demoService . IsDemoEnvironment ( portainer . EndpointID ( e . ID ) ) {
if handler . demoService . IsDemoEnvironment ( portainer . EndpointID ( e . ID ) ) {
resps = append ( resps , DeleteMultipleResp {
resp . Errors = append ( resp . Errors , e . ID )
Name : e . Name ,
log . Warn ( ) . Err ( httperrors . ErrNotAvailableInDemo ) . Msgf ( "Unable to remove demo environment %d" , e . ID )
Err : httperrors . ErrNotAvailableInDemo ,
} )
continue
continue
}
}
// Attempt deletion.
if err := handler . deleteEndpoint ( tx , portainer . EndpointID ( e . ID ) , e . DeleteCluster ) ; err != nil {
err := handler . deleteEndpoint (
resp . Errors = append ( resp . Errors , e . ID )
tx ,
log . Warn ( ) . Err ( err ) . Int ( "environment_id" , e . ID ) . Msg ( "Unable to remove environment" )
portainer . EndpointID ( e . ID ) ,
e . DeleteCluster ,
)
resps = append ( resps , DeleteMultipleResp { Name : e . Name , Err : err } )
continue
}
resp . Deleted = append ( resp . Deleted , e . ID )
}
}
return nil
return nil
} )
} ) ; err != nil {
if err != nil {
return httperror . InternalServerError ( "Unable to delete environments" , err )
return httperror . InternalServerError ( "Unable to delete environments" , err )
}
}
return response . JSON ( w , resps )
if len ( resp . Errors ) > 0 {
return response . JSONWithStatus ( w , resp , http . StatusPartialContent )
}
return response . Empty ( w )
}
}
func ( handler * Handler ) deleteEndpoint ( tx dataservices . DataStoreTx , endpointID portainer . EndpointID , deleteCluster bool ) error {
func ( handler * Handler ) deleteEndpoint ( tx dataservices . DataStoreTx , endpointID portainer . EndpointID , deleteCluster bool ) error {