1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-24 15:59:41 +02:00

refactor(docker/services): convert services table to react [EE-4675] (#10289)

This commit is contained in:
Chaim Lev-Ari 2023-10-22 11:32:05 +02:00 committed by GitHub
parent 6b5c24faff
commit 0dc1805881
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 969 additions and 850 deletions

View file

@ -0,0 +1,108 @@
package endpoints
import (
"context"
"net/http"
"strings"
portaineree "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/docker/consts"
"github.com/portainer/portainer/api/docker/images"
httperror "github.com/portainer/portainer/pkg/libhttp/error"
"github.com/portainer/portainer/pkg/libhttp/request"
"github.com/portainer/portainer/pkg/libhttp/response"
"github.com/docker/docker/api/types"
dockertypes "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
)
type forceUpdateServicePayload struct {
// ServiceId to update
ServiceID string
// PullImage if true will pull the image
PullImage bool
}
func (payload *forceUpdateServicePayload) Validate(r *http.Request) error {
return nil
}
// @id endpointForceUpdateService
// @summary force update a docker service
// @description force update a docker service
// @description **Access policy**: authenticated
// @tags endpoints
// @security ApiKeyAuth
// @security jwt
// @accept json
// @produce json
// @param id path int true "endpoint identifier"
// @param body body forceUpdateServicePayload true "details"
// @success 200 {object} dockertypes.ServiceUpdateResponse "Success"
// @failure 400 "Invalid request"
// @failure 403 "Permission denied"
// @failure 404 "endpoint not found"
// @failure 500 "Server error"
// @router /endpoints/{id}/forceupdateservice [put]
func (handler *Handler) endpointForceUpdateService(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
endpointID, err := request.RetrieveNumericRouteVariableValue(r, "id")
if err != nil {
return httperror.BadRequest("Invalid environment identifier route variable", err)
}
var payload forceUpdateServicePayload
err = request.DecodeAndValidateJSONPayload(r, &payload)
if err != nil {
return httperror.BadRequest("Invalid request payload", err)
}
endpoint, err := handler.DataStore.Endpoint().Endpoint(portaineree.EndpointID(endpointID))
if handler.DataStore.IsErrObjectNotFound(err) {
return httperror.NotFound("Unable to find an environment with the specified identifier inside the database", err)
} else if err != nil {
return httperror.InternalServerError("Unable to find an environment with the specified identifier inside the database", err)
}
err = handler.requestBouncer.AuthorizedEndpointOperation(r, endpoint)
if err != nil {
return httperror.Forbidden("Permission denied to force update service", err)
}
dockerClient, err := handler.DockerClientFactory.CreateClient(endpoint, "", nil)
if err != nil {
return httperror.InternalServerError("Error creating docker client", err)
}
defer dockerClient.Close()
service, _, err := dockerClient.ServiceInspectWithRaw(context.Background(), payload.ServiceID, dockertypes.ServiceInspectOptions{InsertDefaults: true})
if err != nil {
return httperror.InternalServerError("Error looking up service", err)
}
service.Spec.TaskTemplate.ForceUpdate++
if payload.PullImage {
service.Spec.TaskTemplate.ContainerSpec.Image = strings.Split(service.Spec.TaskTemplate.ContainerSpec.Image, "@sha")[0]
}
newService, err := dockerClient.ServiceUpdate(context.Background(), payload.ServiceID, service.Version, service.Spec, dockertypes.ServiceUpdateOptions{QueryRegistry: true})
if err != nil {
return httperror.InternalServerError("Error force update service", err)
}
go func() {
images.EvictImageStatus(payload.ServiceID)
images.EvictImageStatus(service.Spec.Labels[consts.SwarmStackNameLabel])
containers, _ := dockerClient.ContainerList(context.TODO(), types.ContainerListOptions{
All: true,
Filters: filters.NewArgs(filters.Arg("label", consts.SwarmServiceIdLabel+"="+payload.ServiceID)),
})
for _, container := range containers {
images.EvictImageStatus(container.ID)
}
}()
return response.JSON(w, newService)
}

View file

@ -6,6 +6,7 @@ import (
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/api/demo"
dockerclient "github.com/portainer/portainer/api/docker/client"
"github.com/portainer/portainer/api/http/proxy"
"github.com/portainer/portainer/api/http/security"
"github.com/portainer/portainer/api/internal/authorization"
@ -36,6 +37,7 @@ type Handler struct {
K8sClientFactory *cli.ClientFactory
ComposeStackManager portainer.ComposeStackManager
AuthorizationService *authorization.Service
DockerClientFactory *dockerclient.ClientFactory
BindAddress string
BindAddressHTTPS string
PendingActionsService *pendingactions.PendingActionsService
@ -79,6 +81,8 @@ func NewHandler(bouncer security.BouncerService, demoService *demo.Service) *Han
bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.endpointRegistryAccess))).Methods(http.MethodPut)
h.Handle("/endpoints/global-key", bouncer.PublicAccess(httperror.LoggerHandler(h.endpointCreateGlobalKey))).Methods(http.MethodPost)
h.Handle("/endpoints/{id}/forceupdateservice",
bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.endpointForceUpdateService))).Methods(http.MethodPut)
// DEPRECATED
h.Handle("/endpoints/{id}/status", bouncer.PublicAccess(httperror.LoggerHandler(h.endpointStatusInspect))).Methods(http.MethodGet)

View file

@ -175,6 +175,7 @@ func (server *Server) Start() error {
endpointHandler.ProxyManager = server.ProxyManager
endpointHandler.SnapshotService = server.SnapshotService
endpointHandler.K8sClientFactory = server.KubernetesClientFactory
endpointHandler.DockerClientFactory = server.DockerClientFactory
endpointHandler.ReverseTunnelService = server.ReverseTunnelService
endpointHandler.ComposeStackManager = server.ComposeStackManager
endpointHandler.AuthorizationService = server.AuthorizationService