2018-09-03 10:08:03 +00:00
package webhooks
import (
"context"
2020-07-07 21:57:52 +00:00
"errors"
2018-09-03 10:08:03 +00:00
"net/http"
"strings"
dockertypes "github.com/docker/docker/api/types"
2018-09-10 10:01:38 +00:00
httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request"
"github.com/portainer/libhttp/response"
2021-02-23 03:21:39 +00:00
portainer "github.com/portainer/portainer/api"
2020-07-07 21:57:52 +00:00
bolterrors "github.com/portainer/portainer/api/bolt/errors"
2018-09-03 10:08:03 +00:00
)
2021-02-23 03:21:39 +00:00
// @summary Execute a webhook
// @description Acts on a passed in token UUID to restart the docker service
// @tags webhooks
// @accept json
// @produce json
// @param token path string true "Webhook token"
// @success 202 "Webhook executed"
// @failure 400
// @failure 500
// @router /webhooks/{token} [post]
2018-09-03 10:08:03 +00:00
func ( handler * Handler ) webhookExecute ( w http . ResponseWriter , r * http . Request ) * httperror . HandlerError {
webhookToken , err := request . RetrieveRouteVariableValue ( r , "token" )
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Invalid service id parameter" , err }
}
2020-05-20 05:23:15 +00:00
webhook , err := handler . DataStore . Webhook ( ) . WebhookByToken ( webhookToken )
2018-09-03 10:08:03 +00:00
2020-07-07 21:57:52 +00:00
if err == bolterrors . ErrObjectNotFound {
2018-09-03 10:08:03 +00:00
return & httperror . HandlerError { http . StatusNotFound , "Unable to find a webhook with this token" , err }
} else if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to retrieve webhook from the database" , err }
}
resourceID := webhook . ResourceID
endpointID := webhook . EndpointID
webhookType := webhook . WebhookType
2020-05-20 05:23:15 +00:00
endpoint , err := handler . DataStore . Endpoint ( ) . Endpoint ( portainer . EndpointID ( endpointID ) )
2020-07-07 21:57:52 +00:00
if err == bolterrors . ErrObjectNotFound {
2018-09-03 10:08:03 +00:00
return & httperror . HandlerError { http . StatusNotFound , "Unable to find an endpoint with the specified identifier inside the database" , err }
} else if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to find an endpoint with the specified identifier inside the database" , err }
}
2019-05-07 22:41:31 +00:00
imageTag , _ := request . RetrieveQueryParameter ( r , "tag" , true )
2018-09-03 10:08:03 +00:00
switch webhookType {
case portainer . ServiceWebhook :
2019-05-07 22:41:31 +00:00
return handler . executeServiceWebhook ( w , endpoint , resourceID , imageTag )
2018-09-03 10:08:03 +00:00
default :
2020-07-07 21:57:52 +00:00
return & httperror . HandlerError { http . StatusInternalServerError , "Unsupported webhook type" , errors . New ( "Webhooks for this resource are not currently supported" ) }
2018-09-03 10:08:03 +00:00
}
}
2019-05-07 22:41:31 +00:00
func ( handler * Handler ) executeServiceWebhook ( w http . ResponseWriter , endpoint * portainer . Endpoint , resourceID string , imageTag string ) * httperror . HandlerError {
2018-10-28 06:06:50 +00:00
dockerClient , err := handler . DockerClientFactory . CreateClient ( endpoint , "" )
2018-09-03 10:08:03 +00:00
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Error creating docker client" , err }
}
defer dockerClient . Close ( )
service , _ , err := dockerClient . ServiceInspectWithRaw ( context . Background ( ) , resourceID , dockertypes . ServiceInspectOptions { InsertDefaults : true } )
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Error looking up service" , err }
}
service . Spec . TaskTemplate . ForceUpdate ++
2019-05-07 22:41:31 +00:00
if imageTag != "" {
service . Spec . TaskTemplate . ContainerSpec . Image = strings . Split ( service . Spec . TaskTemplate . ContainerSpec . Image , ":" ) [ 0 ] + ":" + imageTag
} else {
service . Spec . TaskTemplate . ContainerSpec . Image = strings . Split ( service . Spec . TaskTemplate . ContainerSpec . Image , "@sha" ) [ 0 ]
}
2018-09-03 10:08:03 +00:00
_ , err = dockerClient . ServiceUpdate ( context . Background ( ) , resourceID , service . Version , service . Spec , dockertypes . ServiceUpdateOptions { QueryRegistry : true } )
2019-05-07 22:41:31 +00:00
2018-09-03 10:08:03 +00:00
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Error updating service" , err }
}
return response . Empty ( w )
}