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

feat(edge/stacks): increase status transparency [EE-5554] (#9094)

This commit is contained in:
Chaim Lev-Ari 2023-07-13 23:55:52 +03:00 committed by GitHub
parent db61fb149b
commit 0bcb57568c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
45 changed files with 1305 additions and 316 deletions

View file

@ -3,21 +3,24 @@ package edgestacks
import (
"errors"
"net/http"
"time"
httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request"
"github.com/portainer/libhttp/response"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/pkg/featureflags"
"github.com/rs/zerolog/log"
"github.com/asaskevich/govalidator"
httperror "github.com/portainer/libhttp/error"
)
type updateStatusPayload struct {
Error string
Status *portainer.EdgeStackStatusType
EndpointID portainer.EndpointID
Time int64
}
func (payload *updateStatusPayload) Validate(r *http.Request) error {
@ -33,6 +36,10 @@ func (payload *updateStatusPayload) Validate(r *http.Request) error {
return errors.New("error message is mandatory when status is error")
}
if payload.Time == 0 {
payload.Time = time.Now().Unix()
}
return nil
}
@ -43,6 +50,7 @@ func (payload *updateStatusPayload) Validate(r *http.Request) error {
// @accept json
// @produce json
// @param id path int true "EdgeStack Id"
// @param body body updateStatusPayload true "EdgeStack status payload"
// @success 200 {object} portainer.EdgeStack
// @failure 500
// @failure 400
@ -84,6 +92,21 @@ func (handler *Handler) edgeStackStatusUpdate(w http.ResponseWriter, r *http.Req
}
func (handler *Handler) updateEdgeStackStatus(tx dataservices.DataStoreTx, r *http.Request, stackID portainer.EdgeStackID, payload updateStatusPayload) (*portainer.EdgeStack, error) {
stack, err := tx.EdgeStack().EdgeStack(stackID)
if err != nil {
if dataservices.IsErrObjectNotFound(err) {
// skip error because agent tries to report on deleted stack
log.Warn().
Err(err).
Int("stackID", int(stackID)).
Int("status", int(*payload.Status)).
Msg("Unable to find a stack inside the database, skipping error")
return nil, nil
}
return nil, err
}
endpoint, err := tx.Endpoint().Endpoint(payload.EndpointID)
if err != nil {
return nil, handler.handlerDBErr(err, "Unable to find an environment with the specified identifier inside the database")
@ -94,67 +117,50 @@ func (handler *Handler) updateEdgeStackStatus(tx dataservices.DataStoreTx, r *ht
return nil, httperror.Forbidden("Permission denied to access environment", err)
}
var stack *portainer.EdgeStack
status := *payload.Status
log.Debug().
Int("stackID", int(stackID)).
Int("status", int(status)).
Msg("Updating stack status")
deploymentStatus := portainer.EdgeStackDeploymentStatus{
Type: status,
Error: payload.Error,
Time: payload.Time,
}
if featureflags.IsEnabled(portainer.FeatureNoTx) {
err = tx.EdgeStack().UpdateEdgeStackFunc(portainer.EdgeStackID(stackID), func(edgeStack *portainer.EdgeStack) {
details := edgeStack.Status[payload.EndpointID].Details
details.Pending = false
switch *payload.Status {
case portainer.EdgeStackStatusOk:
details.Ok = true
case portainer.EdgeStackStatusError:
details.Error = true
case portainer.EdgeStackStatusAcknowledged:
details.Acknowledged = true
case portainer.EdgeStackStatusRemove:
details.Remove = true
case portainer.EdgeStackStatusImagesPulled:
details.ImagesPulled = true
}
edgeStack.Status[payload.EndpointID] = portainer.EdgeStackStatus{
Details: details,
Error: payload.Error,
EndpointID: payload.EndpointID,
}
err = tx.EdgeStack().UpdateEdgeStackFunc(stackID, func(edgeStack *portainer.EdgeStack) {
updateEnvStatus(payload.EndpointID, edgeStack, deploymentStatus)
stack = edgeStack
})
} else {
stack, err = tx.EdgeStack().EdgeStack(stackID)
if err != nil {
return nil, err
}
details := stack.Status[payload.EndpointID].Details
details.Pending = false
switch *payload.Status {
case portainer.EdgeStackStatusOk:
details.Ok = true
case portainer.EdgeStackStatusError:
details.Error = true
case portainer.EdgeStackStatusAcknowledged:
details.Acknowledged = true
case portainer.EdgeStackStatusRemove:
details.Remove = true
case portainer.EdgeStackStatusImagesPulled:
details.ImagesPulled = true
}
stack.Status[payload.EndpointID] = portainer.EdgeStackStatus{
Details: details,
Error: payload.Error,
EndpointID: payload.EndpointID,
return nil, handler.handlerDBErr(err, "Unable to persist the stack changes inside the database")
}
} else {
updateEnvStatus(payload.EndpointID, stack, deploymentStatus)
err = tx.EdgeStack().UpdateEdgeStack(stackID, stack)
}
if err != nil {
return nil, handler.handlerDBErr(err, "Unable to persist the stack changes inside the database")
if err != nil {
return nil, handler.handlerDBErr(err, "Unable to persist the stack changes inside the database")
}
}
return stack, nil
}
func updateEnvStatus(environmentId portainer.EndpointID, stack *portainer.EdgeStack, deploymentStatus portainer.EdgeStackDeploymentStatus) {
environmentStatus, ok := stack.Status[environmentId]
if !ok {
environmentStatus = portainer.EdgeStackStatus{
EndpointID: environmentId,
Status: []portainer.EdgeStackDeploymentStatus{},
}
}
environmentStatus.Status = append(environmentStatus.Status, deploymentStatus)
stack.Status[environmentId] = environmentStatus
}