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

fix(pending-actions): further refactoring [EE-7011] (#11806)
Some checks failed
Test / test-server (map[arch:arm64 platform:linux]) (push) Has been cancelled
ci / build_images (map[arch:amd64 platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Has been cancelled
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Has been cancelled
ci / build_images (map[arch:arm platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:arm64 platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:ppc64le platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:s390x platform:linux version:]) (push) Has been cancelled
/ triage (push) Has been cancelled
Lint / Run linters (push) Has been cancelled
Test / test-client (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:linux]) (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Has been cancelled
ci / build_manifests (push) Has been cancelled

This commit is contained in:
Matt Hook 2024-05-10 11:59:58 +12:00 committed by GitHub
parent b4e829e8c6
commit 6a51b6b41e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 56 additions and 62 deletions

View file

@ -2,6 +2,7 @@ package pendingactions
import (
"fmt"
"reflect"
"sync"
portainer "github.com/portainer/portainer/api"
@ -34,72 +35,87 @@ func (service *PendingActionsService) RegisterHandler(name string, handler porta
handlers[name] = handler
}
func (service *PendingActionsService) Create(r portainer.PendingAction) error {
return service.dataStore.PendingActions().Create(&r)
func (service *PendingActionsService) Create(action portainer.PendingAction) error {
// Check if this pendingAction already exists
pendingActions, err := service.dataStore.PendingActions().ReadAll()
if err != nil {
return fmt.Errorf("failed to retrieve pending actions: %w", err)
}
for _, dba := range pendingActions {
// Same endpoint, same action and data, don't create a repeat
if dba.EndpointID == action.EndpointID && dba.Action == action.Action &&
reflect.DeepEqual(dba.ActionData, action.ActionData) {
log.Debug().Msgf("pending action %s already exists for environment %d, skipping...", action.Action, action.EndpointID)
return nil
}
}
return service.dataStore.PendingActions().Create(&action)
}
func (service *PendingActionsService) Execute(id portainer.EndpointID) error {
func (service *PendingActionsService) Execute(id portainer.EndpointID) {
service.mu.Lock()
defer service.mu.Unlock()
endpoint, err := service.dataStore.Endpoint().Endpoint(id)
if err != nil {
return fmt.Errorf("failed to retrieve environment %d: %w", id, err)
log.Debug().Msgf("failed to retrieve environment %d: %v", id, err)
return
}
isKubernetesEndpoint := endpointutils.IsKubernetesEndpoint(endpoint) && !endpointutils.IsEdgeEndpoint(endpoint)
// EndpointStatusUp is only relevant for non-Kubernetes endpoints
// Sometimes the endpoint is UP but the status is not updated in the database
if !isKubernetesEndpoint && endpoint.Status != portainer.EndpointStatusUp {
log.Debug().Msgf("Environment %q (id: %d) is not up", endpoint.Name, id)
return fmt.Errorf("environment %q (id: %d) is not up", endpoint.Name, id)
}
// For Kubernetes endpoints, we need to check if the endpoint is up by creating a kube client
if isKubernetesEndpoint {
_, err := service.kubeFactory.GetKubeClient(endpoint)
if err != nil {
log.Debug().Err(err).Msgf("Environment %q (id: %d) is not up", endpoint.Name, id)
return fmt.Errorf("environment %q (id: %d) is not up", endpoint.Name, id)
if !isKubernetesEndpoint {
if endpoint.Status != portainer.EndpointStatusUp {
return
}
} else {
// For Kubernetes endpoints, we need to check if the client can be created
if _, err := service.kubeFactory.GetKubeClient(endpoint); err != nil {
return
}
}
pendingActions, err := service.dataStore.PendingActions().ReadAll()
if err != nil {
log.Error().Err(err).Msgf("failed to retrieve pending actions")
return fmt.Errorf("failed to retrieve pending actions for environment %d: %w", id, err)
log.Warn().Msgf("failed to read pending actions: %v", err)
return
}
for _, endpointPendingAction := range pendingActions {
if endpointPendingAction.EndpointID == id {
err := service.executePendingAction(endpointPendingAction, endpoint)
log.Debug().Msgf("Executing pending actions for environment %d", id)
for _, pendingAction := range pendingActions {
if pendingAction.EndpointID == id {
log.Debug().Msgf("executing pending action id=%d, action=%s", pendingAction.ID, pendingAction.Action)
err := service.executePendingAction(pendingAction, endpoint)
if err != nil {
log.Warn().Err(err).Msgf("failed to execute pending action")
return fmt.Errorf("failed to execute pending action: %w", err)
log.Warn().Msgf("failed to execute pending action: %v", err)
return
}
err = service.dataStore.PendingActions().Delete(endpointPendingAction.ID)
err = service.dataStore.PendingActions().Delete(pendingAction.ID)
if err != nil {
log.Error().Err(err).Msgf("failed to delete pending action")
return fmt.Errorf("failed to delete pending action: %w", err)
log.Warn().Msgf("failed to delete pending action: %v", err)
return
}
log.Debug().Msgf("pending action %d finished", pendingAction.ID)
}
}
return nil
}
func (service *PendingActionsService) executePendingAction(pendingAction portainer.PendingAction, endpoint *portainer.Endpoint) error {
log.Debug().Msgf("Executing pending action %s for environment %d", pendingAction.Action, pendingAction.EndpointID)
defer func() {
log.Debug().Msgf("End executing pending action %s for environment %d", pendingAction.Action, pendingAction.EndpointID)
if r := recover(); r != nil {
log.Error().Msgf("recovered from panic while executing pending action %s for environment %d: %v", pendingAction.Action, pendingAction.EndpointID, r)
}
}()
handler, ok := handlers[pendingAction.Action]
if !ok {
log.Warn().Msgf("No handler found for pending action %s", pendingAction.Action)
log.Warn().Msgf("no handler found for pending action %s", pendingAction.Action)
return nil
}