fix(errors): improve error handling EE-4430 (#11987)

pull/11990/head
andres-portainer 5 months ago committed by GitHub
parent dc62604ed8
commit 4adce14485
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -6,6 +6,8 @@ import (
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
"github.com/rs/zerolog/log"
)
// BucketName represents the name of the bucket where this service stores data.
@ -157,6 +159,7 @@ func (service *Service) EndpointsByTeamID(teamID portainer.TeamID) ([]portainer.
return true
}
}
return false
}),
)
@ -166,11 +169,13 @@ func (service *Service) EndpointsByTeamID(teamID portainer.TeamID) ([]portainer.
func (service *Service) GetNextIdentifier() int {
var identifier int
service.connection.UpdateTx(func(tx portainer.Transaction) error {
if err := service.connection.UpdateTx(func(tx portainer.Transaction) error {
identifier = service.Tx(tx).GetNextIdentifier()
return nil
})
}); err != nil {
log.Error().Err(err).Str("bucket", BucketName).Msg("could not get the next identifier")
}
return identifier
}

@ -32,8 +32,7 @@ func (service *Service) RegisterUpdateStackFunction(
// NewService creates a new instance of a service.
func NewService(connection portainer.Connection) (*Service, error) {
err := connection.SetServiceName(BucketName)
if err != nil {
if err := connection.SetServiceName(BucketName); err != nil {
return nil, err
}
@ -65,8 +64,7 @@ func (service *Service) EndpointRelation(endpointID portainer.EndpointID) (*port
var endpointRelation portainer.EndpointRelation
identifier := service.connection.ConvertToKey(int(endpointID))
err := service.connection.GetObject(BucketName, identifier, &endpointRelation)
if err != nil {
if err := service.connection.GetObject(BucketName, identifier, &endpointRelation); err != nil {
return nil, err
}
@ -161,19 +159,24 @@ func (service *Service) updateEdgeStacksAfterRelationChange(previousRelationStat
// list how many time this stack is referenced in all relations
// in order to update the stack deployments count
for refStackId, refStackEnabled := range stacksToUpdate {
if refStackEnabled {
numDeployments := 0
for _, r := range relations {
for sId, enabled := range r.EdgeStacks {
if enabled && sId == refStackId {
numDeployments += 1
}
if !refStackEnabled {
continue
}
numDeployments := 0
for _, r := range relations {
for sId, enabled := range r.EdgeStacks {
if enabled && sId == refStackId {
numDeployments += 1
}
}
}
service.updateStackFn(refStackId, func(edgeStack *portainer.EdgeStack) {
edgeStack.NumDeployments = numDeployments
})
if err := service.updateStackFn(refStackId, func(edgeStack *portainer.EdgeStack) {
edgeStack.NumDeployments = numDeployments
}); err != nil {
log.Error().Err(err).Msg("could not update the number of deployments")
}
}
}

@ -33,8 +33,7 @@ func (service ServiceTx) EndpointRelation(endpointID portainer.EndpointID) (*por
var endpointRelation portainer.EndpointRelation
identifier := service.service.connection.ConvertToKey(int(endpointID))
err := service.tx.GetObject(BucketName, identifier, &endpointRelation)
if err != nil {
if err := service.tx.GetObject(BucketName, identifier, &endpointRelation); err != nil {
return nil, err
}
@ -129,19 +128,23 @@ func (service ServiceTx) updateEdgeStacksAfterRelationChange(previousRelationSta
// list how many time this stack is referenced in all relations
// in order to update the stack deployments count
for refStackId, refStackEnabled := range stacksToUpdate {
if refStackEnabled {
numDeployments := 0
for _, r := range relations {
for sId, enabled := range r.EdgeStacks {
if enabled && sId == refStackId {
numDeployments += 1
}
if !refStackEnabled {
continue
}
numDeployments := 0
for _, r := range relations {
for sId, enabled := range r.EdgeStacks {
if enabled && sId == refStackId {
numDeployments += 1
}
}
}
service.service.updateStackFnTx(service.tx, refStackId, func(edgeStack *portainer.EdgeStack) {
edgeStack.NumDeployments = numDeployments
})
if err := service.service.updateStackFnTx(service.tx, refStackId, func(edgeStack *portainer.EdgeStack) {
edgeStack.NumDeployments = numDeployments
}); err != nil {
log.Error().Err(err).Msg("could not update the number of deployments")
}
}
}

@ -4,14 +4,14 @@ import (
"context"
"strings"
"github.com/docker/docker/api/types"
dockercontainer "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
dockerclient "github.com/portainer/portainer/api/docker/client"
"github.com/portainer/portainer/api/docker/images"
"github.com/docker/docker/api/types"
dockercontainer "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
)
@ -54,8 +54,7 @@ func (c *ContainerService) Recreate(ctx context.Context, endpoint *portainer.End
}
if imageTag != "" {
err = img.WithTag(imageTag)
if err != nil {
if err := img.WithTag(imageTag); err != nil {
return nil, errors.Wrapf(err, "set image tag error %s", imageTag)
}
@ -67,23 +66,20 @@ func (c *ContainerService) Recreate(ctx context.Context, endpoint *portainer.End
// 1. pull image if you need force pull
if forcePullImage {
puller := images.NewPuller(cli, images.NewRegistryClient(c.dataStore), c.dataStore)
err = puller.Pull(ctx, img)
if err != nil {
if err := puller.Pull(ctx, img); err != nil {
return nil, errors.Wrapf(err, "pull image error %s", img.FullName())
}
}
// 2. stop the current container
log.Debug().Str("container_id", containerId).Msg("starting to stop the container")
err = cli.ContainerStop(ctx, containerId, dockercontainer.StopOptions{})
if err != nil {
if err := cli.ContainerStop(ctx, containerId, dockercontainer.StopOptions{}); err != nil {
return nil, errors.Wrap(err, "stop container error")
}
// 3. rename the current container
log.Debug().Str("container_id", containerId).Msg("starting to rename the container")
err = cli.ContainerRename(ctx, containerId, container.Name+"-old")
if err != nil {
if err := cli.ContainerRename(ctx, containerId, container.Name+"-old"); err != nil {
return nil, errors.Wrap(err, "rename container error")
}
@ -94,8 +90,7 @@ func (c *ContainerService) Recreate(ctx context.Context, endpoint *portainer.End
// 4. disconnect all networks from the current container
for name, network := range container.NetworkSettings.Networks {
// This allows new container to use the same IP address if specified
err = cli.NetworkDisconnect(ctx, network.NetworkID, containerId, true)
if err != nil {
if err := cli.NetworkDisconnect(ctx, network.NetworkID, containerId, true); err != nil {
return nil, errors.Wrap(err, "disconnect network from old container error")
}
@ -113,9 +108,11 @@ func (c *ContainerService) Recreate(ctx context.Context, endpoint *portainer.End
c.sr.push(func() {
log.Debug().Str("container_id", containerId).Str("container", container.Name).Msg("restoring the container")
cli.ContainerRename(ctx, containerId, container.Name)
for _, network := range container.NetworkSettings.Networks {
cli.NetworkConnect(ctx, network.NetworkID, containerId, network)
}
cli.ContainerStart(ctx, containerId, dockercontainer.StartOptions{})
})
@ -147,22 +144,19 @@ func (c *ContainerService) Recreate(ctx context.Context, endpoint *portainer.End
log.Debug().Str("container_id", newContainerId).Msg("connecting networks to container")
networks := container.NetworkSettings.Networks
for key, network := range networks {
_, ok := networkWithCreation.EndpointsConfig[key]
if ok {
if _, ok := networkWithCreation.EndpointsConfig[key]; ok {
// skip the network that is used during container creation
continue
}
err = cli.NetworkConnect(ctx, network.NetworkID, newContainerId, network)
if err != nil {
if err := cli.NetworkConnect(ctx, network.NetworkID, newContainerId, network); err != nil {
return nil, errors.Wrap(err, "connect container network error")
}
}
// 8. start the new container
log.Debug().Str("container_id", newContainerId).Msg("starting the new container")
err = cli.ContainerStart(ctx, newContainerId, dockercontainer.StartOptions{})
if err != nil {
if err := cli.ContainerStart(ctx, newContainerId, dockercontainer.StartOptions{}); err != nil {
return nil, errors.Wrap(err, "start container error")
}

@ -135,7 +135,7 @@ func (handler *Handler) inspectStatus(tx dataservices.DataStoreTx, r *http.Reque
// Take an initial snapshot
if endpoint.LastCheckInDate == 0 {
handler.ReverseTunnelService.Open(endpoint)
_ = handler.ReverseTunnelService.Open(endpoint)
}
agentPlatform, agentPlatformErr := parseAgentPlatform(r)

@ -9,10 +9,12 @@ import (
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/api/http/client"
"github.com/portainer/portainer/api/internal/endpointutils"
"github.com/portainer/portainer/api/pendingactions/handlers"
httperror "github.com/portainer/portainer/pkg/libhttp/error"
"github.com/portainer/portainer/pkg/libhttp/request"
"github.com/portainer/portainer/pkg/libhttp/response"
"github.com/rs/zerolog/log"
)
@ -80,8 +82,7 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) *
}
var payload endpointUpdatePayload
err = request.DecodeAndValidateJSONPayload(r, &payload)
if err != nil {
if err := request.DecodeAndValidateJSONPayload(r, &payload); err != nil {
return httperror.BadRequest("Invalid request payload", err)
}
@ -106,7 +107,6 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) *
}
endpoint.Name = name
}
if payload.URL != nil && *payload.URL != endpoint.URL {
@ -136,8 +136,7 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) *
}
if payload.TagIDs != nil {
err := handler.DataStore.UpdateTx(func(tx dataservices.DataStoreTx) error {
if err := handler.DataStore.UpdateTx(func(tx dataservices.DataStoreTx) error {
tagsChanged, err := updateEnvironmentTags(tx, payload.TagIDs, endpoint.TagIDs, endpoint.ID)
if err != nil {
return err
@ -147,10 +146,8 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) *
updateRelations = updateRelations || tagsChanged
return nil
})
if err != nil {
httperror.InternalServerError("Unable to update environment tags", err)
}); err != nil {
return httperror.InternalServerError("Unable to update environment tags", err)
}
}
@ -191,17 +188,18 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) *
if payload.AzureApplicationID != nil {
credentials.ApplicationID = *payload.AzureApplicationID
}
if payload.AzureTenantID != nil {
credentials.TenantID = *payload.AzureTenantID
}
if payload.AzureAuthenticationKey != nil {
credentials.AuthenticationKey = *payload.AzureAuthenticationKey
}
httpClient := client.NewHTTPClient()
_, authErr := httpClient.ExecuteAzureAuthenticationRequest(&credentials)
if authErr != nil {
return httperror.InternalServerError("Unable to authenticate against Azure", authErr)
if _, err := httpClient.ExecuteAzureAuthenticationRequest(&credentials); err != nil {
return httperror.InternalServerError("Unable to authenticate against Azure", err)
}
endpoint.AzureCredentials = credentials
}
@ -236,20 +234,19 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) *
handler.FileService.DeleteTLSFile(folder, portainer.TLSFileKey)
}
}
} else {
endpoint.TLSConfig.TLS = false
endpoint.TLSConfig.TLSSkipVerify = false
endpoint.TLSConfig.TLSCACertPath = ""
endpoint.TLSConfig.TLSCertPath = ""
endpoint.TLSConfig.TLSKeyPath = ""
err = handler.FileService.DeleteTLSFiles(folder)
if err != nil {
if err := handler.FileService.DeleteTLSFiles(folder); err != nil {
return httperror.InternalServerError("Unable to remove TLS files from disk", err)
}
}
if endpoint.Type == portainer.AgentOnKubernetesEnvironment || endpoint.Type == portainer.EdgeAgentOnKubernetesEnvironment {
if !endpointutils.IsLocalEndpoint(endpoint) && endpointutils.IsKubernetesEndpoint(endpoint) {
endpoint.TLSConfig.TLS = true
endpoint.TLSConfig.TLSSkipVerify = true
}
@ -257,39 +254,32 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) *
if updateEndpointProxy {
handler.ProxyManager.DeleteEndpointProxy(endpoint.ID)
_, err = handler.ProxyManager.CreateAndRegisterEndpointProxy(endpoint)
if err != nil {
if _, err := handler.ProxyManager.CreateAndRegisterEndpointProxy(endpoint); err != nil {
return httperror.InternalServerError("Unable to register HTTP proxy for the environment", err)
}
}
if updateAuthorizations {
if endpoint.Type == portainer.KubernetesLocalEnvironment || endpoint.Type == portainer.AgentOnKubernetesEnvironment || endpoint.Type == portainer.EdgeAgentOnKubernetesEnvironment {
err = handler.AuthorizationService.CleanNAPWithOverridePolicies(handler.DataStore, endpoint, nil)
if err != nil {
handler.PendingActionsService.Create(handlers.NewCleanNAPWithOverridePolicies(endpoint.ID, nil))
log.Warn().Err(err).Msgf("Unable to clean NAP with override policies for endpoint (%d). Will try to update when endpoint is online.", endpoint.ID)
}
if updateAuthorizations && endpointutils.IsKubernetesEndpoint(endpoint) {
if err := handler.AuthorizationService.CleanNAPWithOverridePolicies(handler.DataStore, endpoint, nil); err != nil {
handler.PendingActionsService.Create(handlers.NewCleanNAPWithOverridePolicies(endpoint.ID, nil))
log.Warn().Err(err).Msgf("Unable to clean NAP with override policies for endpoint (%d). Will try to update when endpoint is online.", endpoint.ID)
}
}
err = handler.DataStore.Endpoint().UpdateEndpoint(endpoint.ID, endpoint)
if err != nil {
if err := handler.DataStore.Endpoint().UpdateEndpoint(endpoint.ID, endpoint); err != nil {
return httperror.InternalServerError("Unable to persist environment changes inside the database", err)
}
if updateRelations {
err := handler.DataStore.UpdateTx(func(tx dataservices.DataStoreTx) error {
if err := handler.DataStore.UpdateTx(func(tx dataservices.DataStoreTx) error {
return handler.updateEdgeRelations(tx, endpoint)
})
if err != nil {
}); err != nil {
return httperror.InternalServerError("Unable to update environment relations", err)
}
}
err = handler.SnapshotService.FillSnapshotData(endpoint)
if err != nil {
if err := handler.SnapshotService.FillSnapshotData(endpoint); err != nil {
return httperror.InternalServerError("Unable to add snapshot data", err)
}
@ -297,7 +287,6 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) *
}
func shouldReloadTLSConfiguration(endpoint *portainer.Endpoint, payload *endpointUpdatePayload) bool {
// If we change anything in the tls config then we need to reload the proxy
if payload.TLS != nil && endpoint.TLSConfig.TLS != *payload.TLS {
return true
@ -318,5 +307,6 @@ func shouldReloadTLSConfiguration(endpoint *portainer.Endpoint, payload *endpoin
if payload.TLSSkipClientVerify != nil && !*payload.TLSSkipClientVerify {
return true
}
return false
}

@ -95,8 +95,7 @@ func GetLatestVersion() string {
TagName string `json:"tag_name"`
}
err = json.Unmarshal(motd, &data)
if err != nil {
if err := json.Unmarshal(motd, &data); err != nil {
log.Debug().Err(err).Msg("couldn't parse latest Portainer version")
return ""

@ -11,9 +11,9 @@ import (
"github.com/portainer/portainer/api/dataservices"
httperrors "github.com/portainer/portainer/api/http/errors"
httperror "github.com/portainer/portainer/pkg/libhttp/error"
"github.com/rs/zerolog/log"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
)
type (
@ -376,7 +376,7 @@ func (bouncer *RequestBouncer) apiKeyLookup(r *http.Request) (*portainer.TokenDa
if now := time.Now().UTC().Unix(); now-apiKey.LastUsed > 60 { // [seconds]
// update the last used time of the key
apiKey.LastUsed = now
bouncer.apiKeyService.UpdateAPIKey(&apiKey)
_ = bouncer.apiKeyService.UpdateAPIKey(&apiKey)
}
return tokenData, nil

@ -71,7 +71,7 @@ func NewBackgroundSnapshotter(dataStore dataservices.DataStore, tunnelService po
s, err := tx.Snapshot().Read(e.ID)
if dataservices.IsErrObjectNotFound(err) ||
(err == nil && s.Docker == nil && s.Kubernetes == nil) {
tunnelService.Open(&e)
_ = tunnelService.Open(&e)
}
}

@ -56,7 +56,7 @@ func writeErrorResponse(rw http.ResponseWriter, err *HandlerError) {
enc.SetSortMapKeys(false)
enc.SetAppendNewline(false)
enc.Encode(&errorResponse{Message: err.Message, Details: capitalize(err.Err.Error())})
_ = enc.Encode(&errorResponse{Message: err.Message, Details: capitalize(err.Err.Error())})
}
// WriteError is a convenience function that creates a new HandlerError before calling writeErrorResponse.

Loading…
Cancel
Save