From 04af5ac0d80768b8956569e42df3c48f7da440cf Mon Sep 17 00:00:00 2001 From: oscarzhou Date: Thu, 13 Jun 2024 17:11:18 +1200 Subject: [PATCH 1/8] fix(edge): parse response body with failed request --- edge/client/portainer_edge_client.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/edge/client/portainer_edge_client.go b/edge/client/portainer_edge_client.go index 6219dfae..945da2b7 100644 --- a/edge/client/portainer_edge_client.go +++ b/edge/client/portainer_edge_client.go @@ -13,6 +13,7 @@ import ( "github.com/portainer/agent" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/edge" + httperror "github.com/portainer/portainer/pkg/libhttp/error" lru "github.com/hashicorp/golang-lru" "github.com/pkg/errors" @@ -208,7 +209,14 @@ func (client *PortainerEdgeClient) GetEdgeStackConfig(edgeStackID int, version * defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - log.Error().Int("response_code", resp.StatusCode).Msg("GetEdgeStackConfig operation failed") + var respErr httperror.HandlerError + if err := json.NewDecoder(resp.Body).Decode(&respErr); err != nil { + log.Error().Err(err).Int("response_code", resp.StatusCode).Msg("failed to parse response error") + } + log.Error().Err(respErr.Err). + Str("response message", respErr.Message). + Int("status code", respErr.StatusCode). + Msg("GetEdgeStackConfig operation failed") return nil, errors.New("GetEdgeStackConfig operation failed") } From ef4569b1ca313daf88afbd20d6334b8afdc3dd45 Mon Sep 17 00:00:00 2001 From: oscarzhou Date: Fri, 14 Jun 2024 19:57:13 +1200 Subject: [PATCH 2/8] fix(edge): add parsed response body error log --- edge/client/error_response.go | 14 +++++++++ edge/client/portainer_edge_client.go | 43 ++++++---------------------- 2 files changed, 22 insertions(+), 35 deletions(-) diff --git a/edge/client/error_response.go b/edge/client/error_response.go index c7e57c65..34911b64 100644 --- a/edge/client/error_response.go +++ b/edge/client/error_response.go @@ -4,6 +4,8 @@ import ( "encoding/json" "net/http" + "github.com/pkg/errors" + httperror "github.com/portainer/portainer/pkg/libhttp/error" "github.com/rs/zerolog/log" ) @@ -39,3 +41,15 @@ func logError(resp *http.Response, errorData *errorData) { Int("status_code", resp.StatusCode). Msg("poll request failure") } + +func logPollingError(resp *http.Response, errMsg string) error { + var respErr httperror.HandlerError + if err := json.NewDecoder(resp.Body).Decode(&respErr); err != nil { + log.Error().Err(err).Int("response_code", resp.StatusCode).Msg("failed to parse response error") + } + log.Error().Err(respErr.Err). + Str("response message", respErr.Message). + Int("status code", respErr.StatusCode). + Msg(errMsg) + return errors.New(errMsg) +} diff --git a/edge/client/portainer_edge_client.go b/edge/client/portainer_edge_client.go index 945da2b7..27097d6d 100644 --- a/edge/client/portainer_edge_client.go +++ b/edge/client/portainer_edge_client.go @@ -13,7 +13,6 @@ import ( "github.com/portainer/agent" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/edge" - httperror "github.com/portainer/portainer/pkg/libhttp/error" lru "github.com/hashicorp/golang-lru" "github.com/pkg/errors" @@ -122,9 +121,7 @@ func (client *PortainerEdgeClient) GetEnvironmentID() (portainer.EndpointID, err defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - log.Debug().Int("response_code", resp.StatusCode).Msg("global key request failure") - - return 0, errors.New("global key request failed") + return 0, logPollingError(resp, "global key request failed") } var responseData globalKeyResponse @@ -167,14 +164,7 @@ func (client *PortainerEdgeClient) GetEnvironmentStatus(flags ...string) (*PollS } if resp.StatusCode != http.StatusOK { - errorData := parseError(resp) - logError(resp, errorData) - - if errorData != nil { - return nil, newNonOkResponseError(errorData.Message + ": " + errorData.Details) - } - - return nil, newNonOkResponseError("short poll request failed") + return nil, logPollingError(resp, "short poll request failed") } var responseData PollStatusResponse @@ -209,16 +199,7 @@ func (client *PortainerEdgeClient) GetEdgeStackConfig(edgeStackID int, version * defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - var respErr httperror.HandlerError - if err := json.NewDecoder(resp.Body).Decode(&respErr); err != nil { - log.Error().Err(err).Int("response_code", resp.StatusCode).Msg("failed to parse response error") - } - log.Error().Err(respErr.Err). - Str("response message", respErr.Message). - Int("status code", respErr.StatusCode). - Msg("GetEdgeStackConfig operation failed") - - return nil, errors.New("GetEdgeStackConfig operation failed") + return nil, logPollingError(resp, "GetEdgeStackConfig operation failed") } var data edge.StackPayload @@ -273,9 +254,7 @@ func (client *PortainerEdgeClient) SetEdgeStackStatus( resp.Body.Close() if resp.StatusCode != http.StatusOK { - log.Error().Int("response_code", resp.StatusCode).Msg("SetEdgeStackStatus operation failed") - - return errors.New("SetEdgeStackStatus operation failed") + return logPollingError(resp, "SetEdgeStackStatus operation failed") } return nil @@ -310,9 +289,7 @@ func (client *PortainerEdgeClient) SetEdgeJobStatus(edgeJobStatus agent.EdgeJobS resp.Body.Close() if resp.StatusCode != http.StatusOK { - log.Error().Int("response_code", resp.StatusCode).Msg("SetEdgeJobStatus operation failed") - - return errors.New("SetEdgeJobStatus operation failed") + return logPollingError(resp, "SetEdgeJobStatus operation failed") } return nil @@ -334,13 +311,11 @@ func (client *PortainerEdgeClient) GetEdgeConfig(id EdgeConfigID) (*EdgeConfig, } if resp.StatusCode != http.StatusOK { - log.Error().Int("response_code", resp.StatusCode).Msg("GetEdgeConfig operation failed") - if resp.StatusCode == http.StatusForbidden { - return nil, errors.New("GetEdgeConfig operation forbidden") + return nil, logPollingError(resp, "GetEdgeConfig operation forbidden") } - return nil, errors.New("GetEdgeConfig operation failed") + return nil, logPollingError(resp, "GetEdgeConfig operation failed") } var data EdgeConfig @@ -370,9 +345,7 @@ func (client *PortainerEdgeClient) SetEdgeConfigState(id EdgeConfigID, state Edg resp.Body.Close() if resp.StatusCode != http.StatusOK { - log.Error().Int("edge_config_id", int(id)).Stringer("state", state).Int("response_code", resp.StatusCode).Msg("SetEdgeConfigState operation failed") - - return errors.New("SetEdgeConfigState operation failed") + return logPollingError(resp, fmt.Sprintf("edge_config_id: %d, state: %s, error: %s", id, state, "SetEdgeConfigState operation failed")) } return nil From 6ac038f44d94f83a8fdcd885dfb25a5f0a1efd03 Mon Sep 17 00:00:00 2001 From: oscarzhou Date: Mon, 17 Jun 2024 17:52:34 +1200 Subject: [PATCH 3/8] fix(edge): update error log for async polling --- edge/client/error_response.go | 33 ---------------------- edge/client/portainer_edge_async_client.go | 9 +----- 2 files changed, 1 insertion(+), 41 deletions(-) diff --git a/edge/client/error_response.go b/edge/client/error_response.go index 34911b64..57c46062 100644 --- a/edge/client/error_response.go +++ b/edge/client/error_response.go @@ -9,39 +9,6 @@ import ( "github.com/rs/zerolog/log" ) -type errorData struct { - Details string - Message string -} - -func parseError(resp *http.Response) *errorData { - errorData := &errorData{} - - err := json.NewDecoder(resp.Body).Decode(&errorData) - if err != nil { - log.Debug().CallerSkipFrame(1). - Err(err). - Int("status_code", resp.StatusCode). - Msg("failed to decode error response") - - return nil - } - - return errorData -} - -func logError(resp *http.Response, errorData *errorData) { - if errorData == nil { - return - } - - log.Debug().CallerSkipFrame(1). - Str("error_response_message", errorData.Message). - Str("error_response_details", errorData.Details). - Int("status_code", resp.StatusCode). - Msg("poll request failure") -} - func logPollingError(resp *http.Response, errMsg string) error { var respErr httperror.HandlerError if err := json.NewDecoder(resp.Body).Decode(&respErr); err != nil { diff --git a/edge/client/portainer_edge_async_client.go b/edge/client/portainer_edge_async_client.go index 96592bf0..ae4d9515 100644 --- a/edge/client/portainer_edge_async_client.go +++ b/edge/client/portainer_edge_async_client.go @@ -415,14 +415,7 @@ func (client *PortainerAsyncClient) executeAsyncRequest(payload AsyncRequest, po defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - errorData := parseError(resp) - logError(resp, errorData) - - if errorData != nil { - return nil, errors.New(errorData.Message + ": " + errorData.Details) - } - - return nil, errors.New("short poll request failed") + return nil, logPollingError(resp, "short async poll request failed") } var asyncResponse AsyncResponse From 385914abd99c14611c29b2ae279b461924092974 Mon Sep 17 00:00:00 2001 From: oscarzhou Date: Mon, 17 Jun 2024 17:56:52 +1200 Subject: [PATCH 4/8] fix(edge): update error package --- edge/client/error_response.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/edge/client/error_response.go b/edge/client/error_response.go index 57c46062..732fa526 100644 --- a/edge/client/error_response.go +++ b/edge/client/error_response.go @@ -2,9 +2,9 @@ package client import ( "encoding/json" + "errors" "net/http" - "github.com/pkg/errors" httperror "github.com/portainer/portainer/pkg/libhttp/error" "github.com/rs/zerolog/log" ) From a9c97e8c9c73fcb08f51df579343bdeb91c199b5 Mon Sep 17 00:00:00 2001 From: oscarzhou Date: Mon, 17 Jun 2024 18:01:04 +1200 Subject: [PATCH 5/8] chore: update portainer package --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 9a7724ae..1e65b5f9 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 github.com/opencontainers/image-spec v1.1.0-rc5 github.com/pkg/errors v0.9.1 - github.com/portainer/portainer v0.6.1-0.20240430014408-a9ead542b3aa + github.com/portainer/portainer v0.6.1-0.20240616212454-be9d3285e178 github.com/rs/zerolog v1.29.0 github.com/stretchr/testify v1.9.0 github.com/wI2L/jsondiff v0.2.0 diff --git a/go.sum b/go.sum index a5feaaf8..9ee1f1d2 100644 --- a/go.sum +++ b/go.sum @@ -281,8 +281,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/portainer/portainer v0.6.1-0.20240430014408-a9ead542b3aa h1:gfKGsoMclwChTqxX4eCfIFo7b4ncHUdHdY7yQwi7HO8= -github.com/portainer/portainer v0.6.1-0.20240430014408-a9ead542b3aa/go.mod h1:AeF9ey0EZ44IK7+kuwCFwcmfY12PfCwmJs57r9STj6s= +github.com/portainer/portainer v0.6.1-0.20240616212454-be9d3285e178 h1:U/Wg0rjTySv2Sa2u8TVPXNyLE+9Ypx/fGRJSiqGrNac= +github.com/portainer/portainer v0.6.1-0.20240616212454-be9d3285e178/go.mod h1:AeF9ey0EZ44IK7+kuwCFwcmfY12PfCwmJs57r9STj6s= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= From 46c81c1953956175e0f53ca2a19a3931ca191c1b Mon Sep 17 00:00:00 2001 From: oscarzhou Date: Mon, 17 Jun 2024 18:42:49 +1200 Subject: [PATCH 6/8] chore: fix lint error --- edge/client/portainer_edge_client.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/edge/client/portainer_edge_client.go b/edge/client/portainer_edge_client.go index 27097d6d..87629bf3 100644 --- a/edge/client/portainer_edge_client.go +++ b/edge/client/portainer_edge_client.go @@ -51,10 +51,6 @@ type NonOkResponseError struct { msg string } -func newNonOkResponseError(msg string) *NonOkResponseError { - return &NonOkResponseError{msg: msg} -} - func (e *NonOkResponseError) Error() string { return e.msg } From 942675525b89b5f3fbd91a316f81c19020b41b18 Mon Sep 17 00:00:00 2001 From: oscarzhou Date: Mon, 8 Jul 2024 17:03:32 +1200 Subject: [PATCH 7/8] fix(edge/poll): update logging format --- edge/client/error_response.go | 13 ++++++++++--- edge/client/portainer_edge_async_client.go | 2 +- edge/client/portainer_edge_client.go | 16 ++++++++-------- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/edge/client/error_response.go b/edge/client/error_response.go index 732fa526..d316f720 100644 --- a/edge/client/error_response.go +++ b/edge/client/error_response.go @@ -9,12 +9,19 @@ import ( "github.com/rs/zerolog/log" ) -func logPollingError(resp *http.Response, errMsg string) error { +func logPollingError(resp *http.Response, ctxMsg, errMsg string) error { var respErr httperror.HandlerError if err := json.NewDecoder(resp.Body).Decode(&respErr); err != nil { - log.Error().Err(err).Int("response_code", resp.StatusCode).Msg("failed to parse response error") + log. + Error(). + Err(err). + Str("context", ctxMsg). + Int("response_code", resp.StatusCode). + Msg("PollClient failed to decode server response") } - log.Error().Err(respErr.Err). + log. + Error().Err(respErr.Err). + Str("context", ctxMsg). Str("response message", respErr.Message). Int("status code", respErr.StatusCode). Msg(errMsg) diff --git a/edge/client/portainer_edge_async_client.go b/edge/client/portainer_edge_async_client.go index ae4d9515..e4505674 100644 --- a/edge/client/portainer_edge_async_client.go +++ b/edge/client/portainer_edge_async_client.go @@ -415,7 +415,7 @@ func (client *PortainerAsyncClient) executeAsyncRequest(payload AsyncRequest, po defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, logPollingError(resp, "short async poll request failed") + return nil, logPollingError(resp, "AsyncEdgeAgentExecuteAsyncRequest", fmt.Sprintf("AsyncEdgeAgent [%d] failed to execute async request", client.getEndpointIDFn())) } var asyncResponse AsyncResponse diff --git a/edge/client/portainer_edge_client.go b/edge/client/portainer_edge_client.go index 87629bf3..13839695 100644 --- a/edge/client/portainer_edge_client.go +++ b/edge/client/portainer_edge_client.go @@ -117,7 +117,7 @@ func (client *PortainerEdgeClient) GetEnvironmentID() (portainer.EndpointID, err defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return 0, logPollingError(resp, "global key request failed") + return 0, logPollingError(resp, "EdgeAgentGetEnvironmentID", fmt.Sprintf("EdgeAgent [%d] failed to request global key", client.getEndpointIDFn())) } var responseData globalKeyResponse @@ -160,7 +160,7 @@ func (client *PortainerEdgeClient) GetEnvironmentStatus(flags ...string) (*PollS } if resp.StatusCode != http.StatusOK { - return nil, logPollingError(resp, "short poll request failed") + return nil, logPollingError(resp, "EdgeAgentGetEnvironmentStatus", fmt.Sprintf("EdgeAgent [%d] failed to request edge environment status", client.getEndpointIDFn())) } var responseData PollStatusResponse @@ -195,7 +195,7 @@ func (client *PortainerEdgeClient) GetEdgeStackConfig(edgeStackID int, version * defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, logPollingError(resp, "GetEdgeStackConfig operation failed") + return nil, logPollingError(resp, "EdgeAgentGetEdgeStackConfig", fmt.Sprintf("EdgeAgent [%d] failed to request edge stack config", client.getEndpointIDFn())) } var data edge.StackPayload @@ -250,7 +250,7 @@ func (client *PortainerEdgeClient) SetEdgeStackStatus( resp.Body.Close() if resp.StatusCode != http.StatusOK { - return logPollingError(resp, "SetEdgeStackStatus operation failed") + return logPollingError(resp, "EdgeAgentSetEdgeStackStatus", fmt.Sprintf("EdgeAgent [%d] failed to set edge stack status", client.getEndpointIDFn())) } return nil @@ -285,7 +285,7 @@ func (client *PortainerEdgeClient) SetEdgeJobStatus(edgeJobStatus agent.EdgeJobS resp.Body.Close() if resp.StatusCode != http.StatusOK { - return logPollingError(resp, "SetEdgeJobStatus operation failed") + return logPollingError(resp, "EdgeAgentSetEdgeJobStatus", fmt.Sprintf("EdgeAgent [%d] failed to set edge job status", client.getEndpointIDFn())) } return nil @@ -308,10 +308,10 @@ func (client *PortainerEdgeClient) GetEdgeConfig(id EdgeConfigID) (*EdgeConfig, if resp.StatusCode != http.StatusOK { if resp.StatusCode == http.StatusForbidden { - return nil, logPollingError(resp, "GetEdgeConfig operation forbidden") + return nil, logPollingError(resp, "EdgeAgentGetEdgeConfig", fmt.Sprintf("EdgeAgent [%d] is forbidden to get the info of edge config [%d]", client.getEndpointIDFn(), id)) } - return nil, logPollingError(resp, "GetEdgeConfig operation failed") + return nil, logPollingError(resp, "EdgeAgentGetEdgeConfig", fmt.Sprintf("EdgeAgent [%d] failed to get the info of edge config [%d]", client.getEndpointIDFn(), id)) } var data EdgeConfig @@ -341,7 +341,7 @@ func (client *PortainerEdgeClient) SetEdgeConfigState(id EdgeConfigID, state Edg resp.Body.Close() if resp.StatusCode != http.StatusOK { - return logPollingError(resp, fmt.Sprintf("edge_config_id: %d, state: %s, error: %s", id, state, "SetEdgeConfigState operation failed")) + return logPollingError(resp, "EdgeAgentSetEdgeConfigState", fmt.Sprintf("EdgeAgent [%d] failed to set the state [%s] to edge config [%d]", client.getEndpointIDFn(), state, id)) } return nil From 55b9929e4d27d40a827de08821895ea9eeb2a83b Mon Sep 17 00:00:00 2001 From: oscarzhou Date: Wed, 10 Jul 2024 12:52:45 +1200 Subject: [PATCH 8/8] fix(edge): improve the log struct --- edge/client/error_response.go | 37 ++++++-- edge/client/portainer_edge_async_client.go | 13 ++- edge/client/portainer_edge_client.go | 105 +++++++++++++++++---- edge/poll.go | 4 +- 4 files changed, 131 insertions(+), 28 deletions(-) diff --git a/edge/client/error_response.go b/edge/client/error_response.go index d316f720..c399be01 100644 --- a/edge/client/error_response.go +++ b/edge/client/error_response.go @@ -2,28 +2,47 @@ package client import ( "encoding/json" - "errors" "net/http" httperror "github.com/portainer/portainer/pkg/libhttp/error" "github.com/rs/zerolog/log" ) -func logPollingError(resp *http.Response, ctxMsg, errMsg string) error { +type NonOkResponseError struct { + msg string +} + +func newNonOkResponseError(msg string) *NonOkResponseError { + return &NonOkResponseError{msg: msg} +} + +func (e *NonOkResponseError) Error() string { + return e.msg +} + +type ForbiddenResponseError struct { + msg string +} + +func newForbiddenResponseError(msg string) *ForbiddenResponseError { + return &ForbiddenResponseError{msg: msg} +} + +func (e *ForbiddenResponseError) Error() string { + return e.msg +} + +func decodeNonOkayResponse(resp *http.Response, ctxMsg string) *httperror.HandlerError { var respErr httperror.HandlerError if err := json.NewDecoder(resp.Body).Decode(&respErr); err != nil { log. Error(). Err(err). + CallerSkipFrame(1). Str("context", ctxMsg). Int("response_code", resp.StatusCode). Msg("PollClient failed to decode server response") + return nil } - log. - Error().Err(respErr.Err). - Str("context", ctxMsg). - Str("response message", respErr.Message). - Int("status code", respErr.StatusCode). - Msg(errMsg) - return errors.New(errMsg) + return &respErr } diff --git a/edge/client/portainer_edge_async_client.go b/edge/client/portainer_edge_async_client.go index e4505674..b48bfccb 100644 --- a/edge/client/portainer_edge_async_client.go +++ b/edge/client/portainer_edge_async_client.go @@ -415,7 +415,18 @@ func (client *PortainerAsyncClient) executeAsyncRequest(payload AsyncRequest, po defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, logPollingError(resp, "AsyncEdgeAgentExecuteAsyncRequest", fmt.Sprintf("AsyncEdgeAgent [%d] failed to execute async request", client.getEndpointIDFn())) + ctxMsg := "AsyncEdgeAgentExecuteAsyncRequest" + errMsg := "AsyncEdgeAgent failed to execute async request" + if err := decodeNonOkayResponse(resp, ctxMsg); err != nil { + log. + Error().Err(err.Err). + Str("context", ctxMsg). + Str("response message", err.Message). + Int("status code", err.StatusCode). + Int("endpoint id", int(client.getEndpointIDFn())). + Msg(errMsg) + } + return nil, newNonOkResponseError(errMsg) } var asyncResponse AsyncResponse diff --git a/edge/client/portainer_edge_client.go b/edge/client/portainer_edge_client.go index 13839695..21aeeb93 100644 --- a/edge/client/portainer_edge_client.go +++ b/edge/client/portainer_edge_client.go @@ -47,14 +47,6 @@ type logFilePayload struct { FileContent string } -type NonOkResponseError struct { - msg string -} - -func (e *NonOkResponseError) Error() string { - return e.msg -} - // NewPortainerEdgeClient returns a pointer to a new PortainerEdgeClient instance func NewPortainerEdgeClient(serverAddress string, setEIDFn setEndpointIDFn, getEIDFn getEndpointIDFn, edgeID string, agentPlatform agent.ContainerPlatform, metaFields agent.EdgeMetaFields, httpClient *edgeHTTPClient) *PortainerEdgeClient { c := &PortainerEdgeClient{ @@ -117,7 +109,18 @@ func (client *PortainerEdgeClient) GetEnvironmentID() (portainer.EndpointID, err defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return 0, logPollingError(resp, "EdgeAgentGetEnvironmentID", fmt.Sprintf("EdgeAgent [%d] failed to request global key", client.getEndpointIDFn())) + ctxMsg := "EdgeAgentGetEnvironmentID" + errMsg := "EdgeAgent failed to request global key" + if err := decodeNonOkayResponse(resp, ctxMsg); err != nil { + log. + Error().Err(err.Err). + Str("context", ctxMsg). + Str("response message", err.Message). + Int("status code", err.StatusCode). + Int("endpoint id", int(client.getEndpointIDFn())). + Msg(errMsg) + } + return 0, newNonOkResponseError(errMsg) } var responseData globalKeyResponse @@ -160,7 +163,18 @@ func (client *PortainerEdgeClient) GetEnvironmentStatus(flags ...string) (*PollS } if resp.StatusCode != http.StatusOK { - return nil, logPollingError(resp, "EdgeAgentGetEnvironmentStatus", fmt.Sprintf("EdgeAgent [%d] failed to request edge environment status", client.getEndpointIDFn())) + ctxMsg := "EdgeAgentGetEnvironmentStatus" + errMsg := "EdgeAgent failed to request edge environment status" + if err := decodeNonOkayResponse(resp, ctxMsg); err != nil { + log. + Error().Err(err.Err). + Str("context", ctxMsg). + Str("response message", err.Message). + Int("status code", err.StatusCode). + Int("endpoint id", int(client.getEndpointIDFn())). + Msg(errMsg) + } + return nil, newNonOkResponseError(errMsg) } var responseData PollStatusResponse @@ -195,7 +209,18 @@ func (client *PortainerEdgeClient) GetEdgeStackConfig(edgeStackID int, version * defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, logPollingError(resp, "EdgeAgentGetEdgeStackConfig", fmt.Sprintf("EdgeAgent [%d] failed to request edge stack config", client.getEndpointIDFn())) + ctxMsg := "EdgeAgentGetEdgeStackConfig" + errMsg := "EdgeAgent failed to request edge stack config" + if err := decodeNonOkayResponse(resp, ctxMsg); err != nil { + log. + Error().Err(err.Err). + Str("context", ctxMsg). + Str("response message", err.Message). + Int("status code", err.StatusCode). + Int("endpoint id", int(client.getEndpointIDFn())). + Msg(errMsg) + } + return nil, newNonOkResponseError(errMsg) } var data edge.StackPayload @@ -250,7 +275,18 @@ func (client *PortainerEdgeClient) SetEdgeStackStatus( resp.Body.Close() if resp.StatusCode != http.StatusOK { - return logPollingError(resp, "EdgeAgentSetEdgeStackStatus", fmt.Sprintf("EdgeAgent [%d] failed to set edge stack status", client.getEndpointIDFn())) + ctxMsg := "EdgeAgentSetEdgeStackStatus" + errMsg := "EdgeAgent failed to set edge stack status" + if err := decodeNonOkayResponse(resp, ctxMsg); err != nil { + log. + Error().Err(err.Err). + Str("context", ctxMsg). + Str("response message", err.Message). + Int("status code", err.StatusCode). + Int("endpoint id", int(client.getEndpointIDFn())). + Msg(errMsg) + } + return newNonOkResponseError(errMsg) } return nil @@ -285,7 +321,18 @@ func (client *PortainerEdgeClient) SetEdgeJobStatus(edgeJobStatus agent.EdgeJobS resp.Body.Close() if resp.StatusCode != http.StatusOK { - return logPollingError(resp, "EdgeAgentSetEdgeJobStatus", fmt.Sprintf("EdgeAgent [%d] failed to set edge job status", client.getEndpointIDFn())) + ctxMsg := "EdgeAgentSetEdgeJobStatus" + errMsg := "EdgeAgent failed to set edge job status" + if err := decodeNonOkayResponse(resp, ctxMsg); err != nil { + log. + Error().Err(err.Err). + Str("context", ctxMsg). + Str("response message", err.Message). + Int("status code", err.StatusCode). + Int("endpoint id", int(client.getEndpointIDFn())). + Msg(errMsg) + } + return newNonOkResponseError(errMsg) } return nil @@ -307,11 +354,24 @@ func (client *PortainerEdgeClient) GetEdgeConfig(id EdgeConfigID) (*EdgeConfig, } if resp.StatusCode != http.StatusOK { + ctxMsg := "EdgeAgentGetEdgeConfig" + errMsg := "EdgeAgent failed to get edge config info" + if err := decodeNonOkayResponse(resp, ctxMsg); err != nil { + log. + Error().Err(err.Err). + Str("context", ctxMsg). + Str("response message", err.Message). + Int("status code", err.StatusCode). + Int("endpoint id", int(client.getEndpointIDFn())). + Int("edge config", int(id)). + Msg(errMsg) + } + if resp.StatusCode == http.StatusForbidden { - return nil, logPollingError(resp, "EdgeAgentGetEdgeConfig", fmt.Sprintf("EdgeAgent [%d] is forbidden to get the info of edge config [%d]", client.getEndpointIDFn(), id)) + return nil, newForbiddenResponseError(errMsg) } - return nil, logPollingError(resp, "EdgeAgentGetEdgeConfig", fmt.Sprintf("EdgeAgent [%d] failed to get the info of edge config [%d]", client.getEndpointIDFn(), id)) + return nil, newNonOkResponseError(errMsg) } var data EdgeConfig @@ -341,7 +401,20 @@ func (client *PortainerEdgeClient) SetEdgeConfigState(id EdgeConfigID, state Edg resp.Body.Close() if resp.StatusCode != http.StatusOK { - return logPollingError(resp, "EdgeAgentSetEdgeConfigState", fmt.Sprintf("EdgeAgent [%d] failed to set the state [%s] to edge config [%d]", client.getEndpointIDFn(), state, id)) + ctxMsg := "EdgeAgentSetEdgeConfigState" + errMsg := "EdgeAgent failed to set state to edge config" + if err := decodeNonOkayResponse(resp, ctxMsg); err != nil { + log. + Error().Err(err.Err). + Str("context", ctxMsg). + Str("response message", err.Message). + Int("status code", err.StatusCode). + Int("endpoint id", int(client.getEndpointIDFn())). + Int("edge config id", int(id)). + Int("edge state", int(state)). + Msg(errMsg) + } + return newNonOkResponseError(errMsg) } return nil diff --git a/edge/poll.go b/edge/poll.go index fd8cd359..7e585908 100644 --- a/edge/poll.go +++ b/edge/poll.go @@ -5,7 +5,6 @@ import ( "errors" "math/rand" "strconv" - "strings" "time" "github.com/portainer/agent" @@ -345,7 +344,8 @@ func (service *PollService) processEdgeConfig(fn func(*client.EdgeConfig) error, if err != nil { log.Error().Err(err).Msg("an error occurred while retrieving an edge configuration") - if strings.Contains(err.Error(), "forbidden") { + var forbiddenError *client.ForbiddenResponseError + if errors.As(err, &forbiddenError) { if err := service.portainerClient.SetEdgeConfigState(edgeConfigID, client.EdgeConfigFailureState); err != nil { log.Error().Err(err).Msg("an error occurred while updating the edge configuration state") }