Skip to content
This repository was archived by the owner on Dec 21, 2023. It is now read-only.

Commit cf4bfd8

Browse files
authored
feat: Expose methods to automatically generate events from parent event (#538)
* feat: Refactor helper function to generate started and finished events Signed-off-by: odubajDT <ondrej.dubaj@dynatrace.com> * add docs comments Signed-off-by: odubajDT <ondrej.dubaj@dynatrace.com> * introduce alias to not have breaing changes Signed-off-by: odubajDT <ondrej.dubaj@dynatrace.com> * working version Signed-off-by: odubajDT <ondrej.dubaj@dynatrace.com> * minor change Signed-off-by: odubajDT <ondrej.dubaj@dynatrace.com> * covered by unit tests Signed-off-by: odubajDT <ondrej.dubaj@dynatrace.com> * additional test Signed-off-by: odubajDT <ondrej.dubaj@dynatrace.com> * refactor Signed-off-by: odubajDT <ondrej.dubaj@dynatrace.com> Signed-off-by: odubajDT <ondrej.dubaj@dynatrace.com>
1 parent 278ad8b commit cf4bfd8

File tree

7 files changed

+827
-519
lines changed

7 files changed

+827
-519
lines changed

pkg/lib/v0_2_0/error.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package v0_2_0
2+
3+
type Error struct {
4+
StatusType StatusType
5+
ResultType ResultType
6+
Message string
7+
Err error
8+
}
9+
10+
func (e Error) Error() string {
11+
return e.Message
12+
}

pkg/lib/v0_2_0/events.go

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/keptn/go-utils/pkg/api/models"
1616
"github.com/keptn/go-utils/pkg/common/strutils"
1717
"github.com/keptn/go-utils/pkg/lib/keptn"
18+
"github.com/sirupsen/logrus"
1819

1920
ceObs "github.com/cloudevents/sdk-go/observability/opentelemetry/v2/client"
2021
ceObsHttp "github.com/cloudevents/sdk-go/observability/opentelemetry/v2/http"
@@ -23,6 +24,14 @@ import (
2324
httpprotocol "github.com/cloudevents/sdk-go/v2/protocol/http"
2425
)
2526

27+
const UnableGetContextMsg = "unable to get keptn context from parent event %s"
28+
const UnableGetTypeMsg = "unable to get keptn event type from parent event %s"
29+
30+
const (
31+
shkeptnspecversion = "0.2.4"
32+
cloudeventsversion = "1.0"
33+
)
34+
2635
const MAX_SEND_RETRIES = 3
2736

2837
const DefaultHTTPEventEndpoint = "http://localhost:8081/event"
@@ -473,3 +482,169 @@ func ToKeptnEvent(event cloudevents.Event) (models.KeptnContextExtendedCE, error
473482

474483
return keptnEvent, nil
475484
}
485+
486+
// CreateStartedEvent takes a parent event (e.g. .triggered event) and creates a corresponding .started event
487+
func CreateStartedEvent(source string, parentEvent models.KeptnContextExtendedCE, eventData interface{}) (*models.KeptnContextExtendedCE, error) {
488+
if err := validateParentEvent(parentEvent); err != nil {
489+
return nil, err
490+
}
491+
492+
startedEventType, err := ReplaceEventTypeKind(*parentEvent.Type, "started")
493+
if err != nil {
494+
return nil, fmt.Errorf("unable to create '.started' event for parent event %s: %w", parentEvent.ID, err)
495+
}
496+
497+
if eventData == nil {
498+
commonEventData := EventData{}
499+
if err := parentEvent.DataAs(&commonEventData); err != nil {
500+
logrus.Errorf("unable to retrieve event data from parent event %s: %s", parentEvent.ID, err.Error())
501+
}
502+
eventData = commonEventData
503+
}
504+
505+
return createEvent(source, startedEventType, parentEvent, eventData), nil
506+
}
507+
508+
// CreateFinishedEvent takes a parent event (e.g. .triggered event) and creates a corresponding .finished event
509+
func CreateFinishedEvent(source string, parentEvent models.KeptnContextExtendedCE, eventData interface{}) (*models.KeptnContextExtendedCE, error) {
510+
if err := validateParentEvent(parentEvent); err != nil {
511+
return nil, err
512+
}
513+
514+
finishedEventType, err := ReplaceEventTypeKind(*parentEvent.Type, "finished")
515+
if err != nil {
516+
return nil, fmt.Errorf("unable to create '.finished' event: %v from %s", err, *parentEvent.Type)
517+
}
518+
519+
var genericEventData map[string]interface{}
520+
err = Decode(eventData, &genericEventData)
521+
if err != nil || genericEventData == nil {
522+
return nil, fmt.Errorf("unable to decode generic event data")
523+
}
524+
525+
if genericEventData["status"] == nil || genericEventData["status"] == "" {
526+
genericEventData["status"] = "succeeded"
527+
}
528+
529+
if genericEventData["result"] == nil || genericEventData["result"] == "" {
530+
genericEventData["result"] = "pass"
531+
}
532+
533+
return createEvent(source, finishedEventType, parentEvent, genericEventData), nil
534+
}
535+
536+
// CreateFinishedEventWithError takes a parent event (e.g. .triggered event) and creates a corresponding errored .finished event
537+
func CreateFinishedEventWithError(source string, parentEvent models.KeptnContextExtendedCE, eventData interface{}, errVal *Error) (*models.KeptnContextExtendedCE, error) {
538+
if err := validateParentEvent(parentEvent); err != nil {
539+
return nil, err
540+
}
541+
542+
finishedEventType, err := ReplaceEventTypeKind(*parentEvent.Type, "finished")
543+
if err != nil {
544+
return nil, fmt.Errorf("unable to create '.finished' event for parent event %s: %w", parentEvent.ID, err)
545+
}
546+
547+
if errVal == nil {
548+
errVal = &Error{}
549+
}
550+
551+
if eventData == nil {
552+
commonEventData := EventData{}
553+
if err := parentEvent.DataAs(&commonEventData); err != nil {
554+
logrus.Errorf("Unable to retrieve event data from parent event %s: %s", parentEvent.ID, err.Error())
555+
}
556+
commonEventData.Result = errVal.ResultType
557+
commonEventData.Status = errVal.StatusType
558+
commonEventData.Message = errVal.Message
559+
eventData = commonEventData
560+
}
561+
562+
return createEvent(source, finishedEventType, parentEvent, eventData), nil
563+
}
564+
565+
// CreateErrorEvent takes a parent event (e.g. .triggered event) and creates a corresponding errored event
566+
func CreateErrorEvent(source string, parentEvent models.KeptnContextExtendedCE, eventData interface{}, errVal *Error) (*models.KeptnContextExtendedCE, error) {
567+
if err := validateParentEvent(parentEvent); err != nil {
568+
return nil, err
569+
}
570+
571+
if errVal == nil {
572+
errVal = &Error{}
573+
}
574+
575+
if IsTaskEventType(*parentEvent.Type) && IsTriggeredEventType(*parentEvent.Type) {
576+
errorFinishedEvent, err := CreateFinishedEventWithError(source, parentEvent, eventData, errVal)
577+
if err != nil {
578+
return nil, err
579+
}
580+
return errorFinishedEvent, nil
581+
}
582+
errorLogEvent, err := CreateErrorLogEvent(source, parentEvent, eventData, errVal)
583+
if err != nil {
584+
return nil, err
585+
}
586+
return errorLogEvent, nil
587+
}
588+
589+
// CreateErrorLogEvent takes a parent event (e.g. .triggered event) and creates a corresponding errored .log event
590+
func CreateErrorLogEvent(source string, parentEvent models.KeptnContextExtendedCE, eventData interface{}, errVal *Error) (*models.KeptnContextExtendedCE, error) {
591+
if err := validateParentEvent(parentEvent); err != nil {
592+
return nil, err
593+
}
594+
595+
if errVal == nil {
596+
errVal = &Error{}
597+
}
598+
599+
if IsTaskEventType(*parentEvent.Type) && IsTriggeredEventType(*parentEvent.Type) {
600+
errorFinishedEvent, err := CreateFinishedEventWithError(source, parentEvent, eventData, errVal)
601+
if err != nil {
602+
return nil, err
603+
}
604+
return errorFinishedEvent, nil
605+
}
606+
607+
if eventData == nil {
608+
errorEventData := ErrorLogEvent{}
609+
if err := parentEvent.DataAs(&errorEventData); err != nil {
610+
logrus.Errorf("unable to retrieve error log data from parent event %s: %s", parentEvent.ID, err.Error())
611+
}
612+
if IsTaskEventType(*parentEvent.Type) {
613+
taskName, _, err := ParseTaskEventType(*parentEvent.Type)
614+
if err == nil && taskName != "" {
615+
errorEventData.Task = taskName
616+
}
617+
}
618+
errorEventData.Message = errVal.Message
619+
eventData = errorEventData
620+
}
621+
622+
return createEvent(source, ErrorLogEventName, parentEvent, eventData), nil
623+
}
624+
625+
func createEvent(source string, eventType string, parentEvent models.KeptnContextExtendedCE, eventData interface{}) *models.KeptnContextExtendedCE {
626+
return &models.KeptnContextExtendedCE{
627+
ID: uuid.NewString(),
628+
Triggeredid: parentEvent.ID,
629+
Shkeptncontext: parentEvent.Shkeptncontext,
630+
Contenttype: cloudevents.ApplicationJSON,
631+
Data: eventData,
632+
Source: strutils.Stringp(source),
633+
Shkeptnspecversion: shkeptnspecversion,
634+
Specversion: cloudeventsversion,
635+
Time: time.Now().UTC(),
636+
Type: strutils.Stringp(eventType),
637+
}
638+
}
639+
640+
func validateParentEvent(parentEvent models.KeptnContextExtendedCE) error {
641+
if parentEvent.Type == nil || *parentEvent.Type == "" {
642+
return fmt.Errorf(UnableGetTypeMsg, parentEvent.ID)
643+
}
644+
645+
if parentEvent.Shkeptncontext == "" {
646+
return fmt.Errorf(UnableGetContextMsg, parentEvent.ID)
647+
}
648+
649+
return nil
650+
}

0 commit comments

Comments
 (0)