|
@@ -6,6 +6,7 @@ import (
|
|
|
"fmt"
|
|
"fmt"
|
|
|
"net/http"
|
|
"net/http"
|
|
|
"strings"
|
|
"strings"
|
|
|
|
|
+ "time"
|
|
|
|
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/google/uuid"
|
|
|
"github.com/porter-dev/porter/api/server/authz"
|
|
"github.com/porter-dev/porter/api/server/authz"
|
|
@@ -34,6 +35,10 @@ func NewCreateUpdatePorterAppEventHandler(
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+const (
|
|
|
|
|
+ crashLoopBackoffSubstring string = "stuck in a restart loop"
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
func (p *CreateUpdatePorterAppEventHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
func (p *CreateUpdatePorterAppEventHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
ctx, span := telemetry.NewSpan(r.Context(), "serve-post-porter-app-event")
|
|
ctx, span := telemetry.NewSpan(r.Context(), "serve-post-porter-app-event")
|
|
|
defer span.End()
|
|
defer span.End()
|
|
@@ -58,17 +63,19 @@ func (p *CreateUpdatePorterAppEventHandler) ServeHTTP(w http.ResponseWriter, r *
|
|
|
telemetry.WithAttributes(span,
|
|
telemetry.WithAttributes(span,
|
|
|
telemetry.AttributeKV{Key: "porter-app-name", Value: appName},
|
|
telemetry.AttributeKV{Key: "porter-app-name", Value: appName},
|
|
|
telemetry.AttributeKV{Key: "porter-app-event-type", Value: string(request.Type)},
|
|
telemetry.AttributeKV{Key: "porter-app-event-type", Value: string(request.Type)},
|
|
|
- telemetry.AttributeKV{Key: "porter-app-event-status", Value: request.Status},
|
|
|
|
|
|
|
+ telemetry.AttributeKV{Key: "porter-app-event-status", Value: string(request.Status)},
|
|
|
telemetry.AttributeKV{Key: "porter-app-event-external-source", Value: request.TypeExternalSource},
|
|
telemetry.AttributeKV{Key: "porter-app-event-external-source", Value: request.TypeExternalSource},
|
|
|
telemetry.AttributeKV{Key: "porter-app-event-id", Value: request.ID},
|
|
telemetry.AttributeKV{Key: "porter-app-event-id", Value: request.ID},
|
|
|
|
|
+ telemetry.AttributeKV{Key: "deployment-target-id", Value: request.DeploymentTargetID},
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
if request.Type == types.PorterAppEventType_Build {
|
|
if request.Type == types.PorterAppEventType_Build {
|
|
|
- reportBuildStatus(ctx, request, p.Config(), user, project, appName)
|
|
|
|
|
|
|
+ validateApplyV2 := project.GetFeatureFlag(models.ValidateApplyV2, p.Config().LaunchDarklyClient)
|
|
|
|
|
+ reportBuildStatus(ctx, request, p.Config(), user, project, appName, validateApplyV2)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if request.ID == "" {
|
|
if request.ID == "" {
|
|
|
- event, err := p.createNewAppEvent(ctx, *cluster, appName, request.Status, string(request.Type), request.TypeExternalSource, request.Metadata)
|
|
|
|
|
|
|
+ event, err := p.createNewAppEvent(ctx, *cluster, appName, request.DeploymentTargetID, request.Status, string(request.Type), request.TypeExternalSource, request.Metadata)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
e := telemetry.Error(ctx, span, err, "error creating new app event")
|
|
e := telemetry.Error(ctx, span, err, "error creating new app event")
|
|
|
p.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(e, http.StatusBadRequest))
|
|
p.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(e, http.StatusBadRequest))
|
|
@@ -87,19 +94,24 @@ func (p *CreateUpdatePorterAppEventHandler) ServeHTTP(w http.ResponseWriter, r *
|
|
|
p.WriteResult(w, r, event)
|
|
p.WriteResult(w, r, event)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func reportBuildStatus(ctx context.Context, request *types.CreateOrUpdatePorterAppEventRequest, config *config.Config, user *models.User, project *models.Project, stackName string) {
|
|
|
|
|
|
|
+func reportBuildStatus(ctx context.Context, request *types.CreateOrUpdatePorterAppEventRequest, config *config.Config, user *models.User, project *models.Project, stackName string, validateApplyV2 bool) {
|
|
|
ctx, span := telemetry.NewSpan(ctx, "report-build-status")
|
|
ctx, span := telemetry.NewSpan(ctx, "report-build-status")
|
|
|
defer span.End()
|
|
defer span.End()
|
|
|
|
|
|
|
|
- telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "porter-app-build-status", Value: request.Status})
|
|
|
|
|
|
|
+ telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "porter-app-build-status", Value: string(request.Status)})
|
|
|
|
|
|
|
|
var errStr string
|
|
var errStr string
|
|
|
|
|
+ var buildLogs string
|
|
|
if errors, ok := request.Metadata["errors"]; ok {
|
|
if errors, ok := request.Metadata["errors"]; ok {
|
|
|
if errs, ok := errors.(map[string]interface{}); ok {
|
|
if errs, ok := errors.(map[string]interface{}); ok {
|
|
|
errStringMap := make(map[string]string)
|
|
errStringMap := make(map[string]string)
|
|
|
for k, v := range errs {
|
|
for k, v := range errs {
|
|
|
if valueStr, ok := v.(string); ok {
|
|
if valueStr, ok := v.(string); ok {
|
|
|
- errStringMap[k] = valueStr
|
|
|
|
|
|
|
+ if k == "b64-build-logs" {
|
|
|
|
|
+ buildLogs = valueStr
|
|
|
|
|
+ } else {
|
|
|
|
|
+ errStringMap[k] = valueStr
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -112,11 +124,11 @@ func reportBuildStatus(ctx context.Context, request *types.CreateOrUpdatePorterA
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- _ = TrackStackBuildStatus(config, user, project, stackName, errStr, request.Status)
|
|
|
|
|
|
|
+ _ = TrackStackBuildStatus(ctx, config, user, project, stackName, errStr, request.Status, validateApplyV2, buildLogs)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// createNewAppEvent will create a new app event for the given porter app name. If the app event is an agent event, then it will be created only if there is no existing event which has the agent ID. In the case that an existing event is found, that will be returned instead
|
|
// createNewAppEvent will create a new app event for the given porter app name. If the app event is an agent event, then it will be created only if there is no existing event which has the agent ID. In the case that an existing event is found, that will be returned instead
|
|
|
-func (p *CreateUpdatePorterAppEventHandler) createNewAppEvent(ctx context.Context, cluster models.Cluster, porterAppName string, status types.PorterAppEventStatus, eventType string, externalSource string, requestMetadata map[string]any) (types.PorterAppEvent, error) {
|
|
|
|
|
|
|
+func (p *CreateUpdatePorterAppEventHandler) createNewAppEvent(ctx context.Context, cluster models.Cluster, porterAppName string, deploymentTargetID string, status types.PorterAppEventStatus, eventType string, externalSource string, requestMetadata map[string]any) (types.PorterAppEvent, error) {
|
|
|
ctx, span := telemetry.NewSpan(ctx, "create-porter-app-event")
|
|
ctx, span := telemetry.NewSpan(ctx, "create-porter-app-event")
|
|
|
defer span.End()
|
|
defer span.End()
|
|
|
|
|
|
|
@@ -138,13 +150,29 @@ func (p *CreateUpdatePorterAppEventHandler) createNewAppEvent(ctx context.Contex
|
|
|
// Agent has no way to know what the porter app event id is, so if we must dedup here
|
|
// Agent has no way to know what the porter app event id is, so if we must dedup here
|
|
|
// TODO: create a filter to filter by only agent events. Not an issue now as app events are deduped per hour on the agent side
|
|
// TODO: create a filter to filter by only agent events. Not an issue now as app events are deduped per hour on the agent side
|
|
|
if agentEventID, ok := requestMetadata["agent_event_id"]; ok {
|
|
if agentEventID, ok := requestMetadata["agent_event_id"]; ok {
|
|
|
- existingEvents, _, err := p.Repo().PorterAppEvent().ListEventsByPorterAppID(ctx, app.ID)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return types.PorterAppEvent{}, telemetry.Error(ctx, span, err, "error listing porter app events for event type")
|
|
|
|
|
|
|
+ var existingEvents []*models.PorterAppEvent
|
|
|
|
|
+ if deploymentTargetID == "" {
|
|
|
|
|
+ existingEvents, _, err = p.Repo().PorterAppEvent().ListEventsByPorterAppID(ctx, app.ID)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return types.PorterAppEvent{}, telemetry.Error(ctx, span, err, "error listing porter app events for event type")
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ deploymentTargetUUID, err := uuid.Parse(deploymentTargetID)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return types.PorterAppEvent{}, telemetry.Error(ctx, span, err, "error parsing deployment target id")
|
|
|
|
|
+ }
|
|
|
|
|
+ if deploymentTargetUUID == uuid.Nil {
|
|
|
|
|
+ return types.PorterAppEvent{}, telemetry.Error(ctx, span, err, "deployment target id cannot be nil")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ existingEvents, _, err = p.Repo().PorterAppEvent().ListEventsByPorterAppIDAndDeploymentTargetID(ctx, app.ID, deploymentTargetUUID)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return types.PorterAppEvent{}, telemetry.Error(ctx, span, err, "error listing porter app events for event type with deployment target id")
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
for _, existingEvent := range existingEvents {
|
|
for _, existingEvent := range existingEvents {
|
|
|
- if existingEvent.Type == eventType {
|
|
|
|
|
|
|
+ if existingEvent != nil && existingEvent.Type == eventType {
|
|
|
existingAgentEventID, ok := existingEvent.Metadata["agent_event_id"]
|
|
existingAgentEventID, ok := existingEvent.Metadata["agent_event_id"]
|
|
|
if !ok {
|
|
if !ok {
|
|
|
continue
|
|
continue
|
|
@@ -158,12 +186,29 @@ func (p *CreateUpdatePorterAppEventHandler) createNewAppEvent(ctx context.Contex
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // before creating a new app_event type event, check the event for crashloop backoff
|
|
|
|
|
+ // if the event is a crashloop backoff, then update the service status of the deployment event associated it to FAILED, since the service's deployment will never succeed from crashloop backoff
|
|
|
|
|
+ // only applies to v2 apps (where the deployment target id is not empty)
|
|
|
|
|
+ if deploymentTargetID != "" {
|
|
|
|
|
+ updateMetadata, appEventFormattedCorrectly := appEventMatchesDetail(requestMetadata, crashLoopBackoffSubstring)
|
|
|
|
|
+ if appEventFormattedCorrectly {
|
|
|
|
|
+ _ = p.updateDeployEventMatchingAppEventDetails(
|
|
|
|
|
+ ctx,
|
|
|
|
|
+ porterAppName,
|
|
|
|
|
+ app.ID,
|
|
|
|
|
+ deploymentTargetID,
|
|
|
|
|
+ updateMetadata,
|
|
|
|
|
+ types.PorterAppEventStatus_Failed,
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if eventType == string(types.PorterAppEventType_Deploy) {
|
|
if eventType == string(types.PorterAppEventType_Deploy) {
|
|
|
// Agent has no way to know what the porter app event id is, so update the deploy event if it exists
|
|
// Agent has no way to know what the porter app event id is, so update the deploy event if it exists
|
|
|
if _, ok := requestMetadata["deploy_status"]; ok {
|
|
if _, ok := requestMetadata["deploy_status"]; ok {
|
|
|
- return p.updateDeployEvent(ctx, porterAppName, app.ID, requestMetadata), nil
|
|
|
|
|
|
|
+ return p.updateDeployEvent(ctx, porterAppName, app.ID, deploymentTargetID, requestMetadata), nil
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -176,6 +221,17 @@ func (p *CreateUpdatePorterAppEventHandler) createNewAppEvent(ctx context.Contex
|
|
|
Metadata: make(map[string]any),
|
|
Metadata: make(map[string]any),
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if deploymentTargetID != "" {
|
|
|
|
|
+ deploymentTargetUUID, err := uuid.Parse(deploymentTargetID)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return types.PorterAppEvent{}, telemetry.Error(ctx, span, err, "error parsing deployment target id")
|
|
|
|
|
+ }
|
|
|
|
|
+ if deploymentTargetUUID == uuid.Nil {
|
|
|
|
|
+ return types.PorterAppEvent{}, telemetry.Error(ctx, span, err, "deployment target id cannot be nil")
|
|
|
|
|
+ }
|
|
|
|
|
+ event.DeploymentTargetID = deploymentTargetUUID
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
for k, v := range requestMetadata {
|
|
for k, v := range requestMetadata {
|
|
|
event.Metadata[k] = v
|
|
event.Metadata[k] = v
|
|
|
}
|
|
}
|
|
@@ -246,40 +302,86 @@ func (p *CreateUpdatePorterAppEventHandler) updateExistingAppEvent(ctx context.C
|
|
|
// 4. the services specified in the updatedStatusMetadata match the services in the deploy event metadata
|
|
// 4. the services specified in the updatedStatusMetadata match the services in the deploy event metadata
|
|
|
// 5. some of the above services are still in the PROGRESSING state
|
|
// 5. some of the above services are still in the PROGRESSING state
|
|
|
// if one of these conditions is not met, then an empty event is returned and no update is made; otherwise, the matched event is returned
|
|
// if one of these conditions is not met, then an empty event is returned and no update is made; otherwise, the matched event is returned
|
|
|
-func (p *CreateUpdatePorterAppEventHandler) updateDeployEvent(ctx context.Context, appName string, appID uint, updatedStatusMetadata map[string]any) types.PorterAppEvent {
|
|
|
|
|
|
|
+func (p *CreateUpdatePorterAppEventHandler) updateDeployEvent(ctx context.Context, appName string, appID uint, deploymentTargetID string, updatedStatusMetadata map[string]any) types.PorterAppEvent {
|
|
|
ctx, span := telemetry.NewSpan(ctx, "update-deploy-event")
|
|
ctx, span := telemetry.NewSpan(ctx, "update-deploy-event")
|
|
|
defer span.End()
|
|
defer span.End()
|
|
|
|
|
|
|
|
- revision, ok := updatedStatusMetadata["revision"]
|
|
|
|
|
- if !ok {
|
|
|
|
|
- _ = telemetry.Error(ctx, span, nil, "revision not found in request metadata")
|
|
|
|
|
- return types.PorterAppEvent{}
|
|
|
|
|
- }
|
|
|
|
|
- revisionFloat64, ok := revision.(float64)
|
|
|
|
|
- if !ok {
|
|
|
|
|
- _ = telemetry.Error(ctx, span, nil, "revision not a float64")
|
|
|
|
|
- return types.PorterAppEvent{}
|
|
|
|
|
- }
|
|
|
|
|
- telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "revision", Value: revisionFloat64})
|
|
|
|
|
|
|
+ var serviceName string
|
|
|
|
|
+ var matchEvent models.PorterAppEvent
|
|
|
|
|
|
|
|
- podName, ok := updatedStatusMetadata["pod_name"]
|
|
|
|
|
- if !ok {
|
|
|
|
|
- _ = telemetry.Error(ctx, span, nil, "pod name not found in request metadata")
|
|
|
|
|
- return types.PorterAppEvent{}
|
|
|
|
|
- }
|
|
|
|
|
- podNameStr, ok := podName.(string)
|
|
|
|
|
- if !ok {
|
|
|
|
|
- _ = telemetry.Error(ctx, span, nil, "pod name not a string")
|
|
|
|
|
- return types.PorterAppEvent{}
|
|
|
|
|
- }
|
|
|
|
|
- telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "pod-name", Value: podNameStr})
|
|
|
|
|
|
|
+ if deploymentTargetID != "" {
|
|
|
|
|
+ appRevisionIDField, ok := updatedStatusMetadata["app_revision_id"]
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ _ = telemetry.Error(ctx, span, nil, "app_revision_id not found in request metadata")
|
|
|
|
|
+ return types.PorterAppEvent{}
|
|
|
|
|
+ }
|
|
|
|
|
+ appRevisionID, ok := appRevisionIDField.(string)
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ _ = telemetry.Error(ctx, span, nil, "appRevisionID is not a string")
|
|
|
|
|
+ return types.PorterAppEvent{}
|
|
|
|
|
+ }
|
|
|
|
|
+ telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "app-revision-id", Value: appRevisionID})
|
|
|
|
|
|
|
|
- serviceName := getServiceNameFromPodName(podNameStr, appName)
|
|
|
|
|
- if serviceName == "" {
|
|
|
|
|
- _ = telemetry.Error(ctx, span, nil, "service name not found in pod name")
|
|
|
|
|
- return types.PorterAppEvent{}
|
|
|
|
|
|
|
+ serviceNameField, ok := updatedStatusMetadata["service_name"]
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ _ = telemetry.Error(ctx, span, nil, "service_name not found in request metadata")
|
|
|
|
|
+ return types.PorterAppEvent{}
|
|
|
|
|
+ }
|
|
|
|
|
+ serviceName, ok = serviceNameField.(string)
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ _ = telemetry.Error(ctx, span, nil, "serviceName is not a string")
|
|
|
|
|
+ return types.PorterAppEvent{}
|
|
|
|
|
+ }
|
|
|
|
|
+ telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "service-name", Value: serviceName})
|
|
|
|
|
+
|
|
|
|
|
+ var err error
|
|
|
|
|
+ matchEvent, err = p.Repo().PorterAppEvent().ReadDeployEventByAppRevisionID(ctx, appID, appRevisionID)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ _ = telemetry.Error(ctx, span, err, "error finding matching deploy event")
|
|
|
|
|
+ return types.PorterAppEvent{}
|
|
|
|
|
+ }
|
|
|
|
|
+ telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "updating-deployment-event", Value: false})
|
|
|
|
|
+ } else {
|
|
|
|
|
+ revision, ok := updatedStatusMetadata["revision"]
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ _ = telemetry.Error(ctx, span, nil, "revision not found in request metadata")
|
|
|
|
|
+ return types.PorterAppEvent{}
|
|
|
|
|
+ }
|
|
|
|
|
+ revisionFloat64, ok := revision.(float64)
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ _ = telemetry.Error(ctx, span, nil, "revision not a float64")
|
|
|
|
|
+ return types.PorterAppEvent{}
|
|
|
|
|
+ }
|
|
|
|
|
+ telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "revision", Value: revisionFloat64})
|
|
|
|
|
+
|
|
|
|
|
+ podName, ok := updatedStatusMetadata["pod_name"]
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ _ = telemetry.Error(ctx, span, nil, "pod name not found in request metadata")
|
|
|
|
|
+ return types.PorterAppEvent{}
|
|
|
|
|
+ }
|
|
|
|
|
+ podNameStr, ok := podName.(string)
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ _ = telemetry.Error(ctx, span, nil, "pod name not a string")
|
|
|
|
|
+ return types.PorterAppEvent{}
|
|
|
|
|
+ }
|
|
|
|
|
+ telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "pod-name", Value: podNameStr})
|
|
|
|
|
+
|
|
|
|
|
+ serviceName = getServiceNameFromPodName(podNameStr, appName)
|
|
|
|
|
+ if serviceName == "" {
|
|
|
|
|
+ _ = telemetry.Error(ctx, span, nil, "service name not found in pod name")
|
|
|
|
|
+ return types.PorterAppEvent{}
|
|
|
|
|
+ }
|
|
|
|
|
+ telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "service-name", Value: serviceName})
|
|
|
|
|
+
|
|
|
|
|
+ var err error
|
|
|
|
|
+ matchEvent, err = p.Repo().PorterAppEvent().ReadDeployEventByRevision(ctx, appID, revisionFloat64)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ _ = telemetry.Error(ctx, span, err, "error finding matching deploy event")
|
|
|
|
|
+ return types.PorterAppEvent{}
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "updating-deployment-event", Value: false})
|
|
|
}
|
|
}
|
|
|
- telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "service-name", Value: serviceName})
|
|
|
|
|
|
|
|
|
|
newStatus, ok := updatedStatusMetadata["deploy_status"]
|
|
newStatus, ok := updatedStatusMetadata["deploy_status"]
|
|
|
if !ok {
|
|
if !ok {
|
|
@@ -306,14 +408,6 @@ func (p *CreateUpdatePorterAppEventHandler) updateDeployEvent(ctx context.Contex
|
|
|
|
|
|
|
|
telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "new-status", Value: string(porterAppEventStatus)})
|
|
telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "new-status", Value: string(porterAppEventStatus)})
|
|
|
|
|
|
|
|
- matchEvent, err := p.Repo().PorterAppEvent().ReadDeployEventByRevision(ctx, appID, revisionFloat64)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- _ = telemetry.Error(ctx, span, err, "error finding matching deploy event")
|
|
|
|
|
- return types.PorterAppEvent{}
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "updating-deployment-event", Value: false})
|
|
|
|
|
-
|
|
|
|
|
// first check to see if the event is empty, meaning there was no match found, or not progressing, meaning it has already been updated
|
|
// first check to see if the event is empty, meaning there was no match found, or not progressing, meaning it has already been updated
|
|
|
if matchEvent.ID == uuid.Nil || matchEvent.Status != string(types.PorterAppEventStatus_Progressing) {
|
|
if matchEvent.ID == uuid.Nil || matchEvent.Status != string(types.PorterAppEventStatus_Progressing) {
|
|
|
return types.PorterAppEvent{}
|
|
return types.PorterAppEvent{}
|
|
@@ -375,6 +469,7 @@ func (p *CreateUpdatePorterAppEventHandler) updateDeployEvent(ctx context.Contex
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
if allServicesDone {
|
|
if allServicesDone {
|
|
|
|
|
+ matchEvent.Metadata["end_time"] = time.Now().UTC()
|
|
|
if anyServicesFailed {
|
|
if anyServicesFailed {
|
|
|
matchEvent.Status = string(types.PorterAppEventStatus_Failed)
|
|
matchEvent.Status = string(types.PorterAppEventStatus_Failed)
|
|
|
} else {
|
|
} else {
|
|
@@ -382,7 +477,7 @@ func (p *CreateUpdatePorterAppEventHandler) updateDeployEvent(ctx context.Contex
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- err = p.Repo().PorterAppEvent().UpdateEvent(ctx, &matchEvent)
|
|
|
|
|
|
|
+ err := p.Repo().PorterAppEvent().UpdateEvent(ctx, &matchEvent)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
_ = telemetry.Error(ctx, span, err, "error updating deploy event")
|
|
_ = telemetry.Error(ctx, span, err, "error updating deploy event")
|
|
|
return matchEvent.ToPorterAppEvent()
|
|
return matchEvent.ToPorterAppEvent()
|
|
@@ -424,3 +519,75 @@ func getServiceNameFromPodName(podName, porterAppName string) string {
|
|
|
|
|
|
|
|
return ""
|
|
return ""
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+// appEventMatchesDetail checks if the app event metadata matches the detail string, returning true if so
|
|
|
|
|
+// also returns the app event metadata as a defined struct, rather than a generic map
|
|
|
|
|
+func appEventMatchesDetail(eventMetadata map[string]any, detail string) (*types.PorterAppAppEventMetadata, bool) {
|
|
|
|
|
+ appEventMetadata := &types.PorterAppAppEventMetadata{}
|
|
|
|
|
+
|
|
|
|
|
+ by, err := json.Marshal(eventMetadata)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return appEventMetadata, false
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ err = json.Unmarshal(by, appEventMetadata)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return appEventMetadata, false
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if appEventMetadata.AppRevisionID == "" {
|
|
|
|
|
+ return appEventMetadata, false
|
|
|
|
|
+ }
|
|
|
|
|
+ if appEventMetadata.ServiceName == "" {
|
|
|
|
|
+ return appEventMetadata, false
|
|
|
|
|
+ }
|
|
|
|
|
+ if !strings.Contains(appEventMetadata.Detail, detail) {
|
|
|
|
|
+ return appEventMetadata, false
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return appEventMetadata, true
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// updateDeployEventMatchingAppEventDetails updates the deploy event and service specified by the app event metadata, if it exists
|
|
|
|
|
+func (p *CreateUpdatePorterAppEventHandler) updateDeployEventMatchingAppEventDetails(
|
|
|
|
|
+ ctx context.Context,
|
|
|
|
|
+ porterAppName string,
|
|
|
|
|
+ porterAppId uint,
|
|
|
|
|
+ deploymentTargetID string,
|
|
|
|
|
+ updateMetadata *types.PorterAppAppEventMetadata,
|
|
|
|
|
+ status types.PorterAppEventStatus,
|
|
|
|
|
+) error {
|
|
|
|
|
+ ctx, span := telemetry.NewSpan(ctx, "update-deploy-event-matching-app-event-details")
|
|
|
|
|
+ defer span.End()
|
|
|
|
|
+
|
|
|
|
|
+ if updateMetadata == nil {
|
|
|
|
|
+ return telemetry.Error(ctx, span, nil, "update metadata is nil")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ telemetry.WithAttributes(
|
|
|
|
|
+ span,
|
|
|
|
|
+ telemetry.AttributeKV{Key: "porter-app-name", Value: porterAppName},
|
|
|
|
|
+ telemetry.AttributeKV{Key: "porter-app-id", Value: porterAppId},
|
|
|
|
|
+ telemetry.AttributeKV{Key: "deployment-target-id", Value: deploymentTargetID},
|
|
|
|
|
+ telemetry.AttributeKV{Key: "app-revision-id", Value: updateMetadata.AppRevisionID},
|
|
|
|
|
+ telemetry.AttributeKV{Key: "service-name", Value: updateMetadata.ServiceName},
|
|
|
|
|
+ telemetry.AttributeKV{Key: "detail", Value: updateMetadata.Detail},
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ // convert the metadata to a map[string]interface{} because that is the type updateDeployEvent expects
|
|
|
|
|
+ // TODO: refactor updateDeployEvent so we don't have to do this
|
|
|
|
|
+ updateMetadataBytes, err := json.Marshal(updateMetadata)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return telemetry.Error(ctx, span, err, "error marshaling update metadata")
|
|
|
|
|
+ }
|
|
|
|
|
+ updateMetadataMap := make(map[string]interface{})
|
|
|
|
|
+ err = json.Unmarshal(updateMetadataBytes, &updateMetadataMap)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return telemetry.Error(ctx, span, err, "error unmarshaling update metadata")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ updateMetadataMap["deploy_status"] = string(status)
|
|
|
|
|
+ // we do not need the returned updated event
|
|
|
|
|
+ _ = p.updateDeployEvent(ctx, porterAppName, porterAppId, deploymentTargetID, updateMetadataMap)
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|