Skip to content
This repository has been archived by the owner on Jan 12, 2024. It is now read-only.

feat: Use keptn/go-utils to access Keptn APIs #767

Merged
merged 21 commits into from
Apr 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,13 @@ func _main(args []string, envCfg envConfig) int {

if env.IsServiceSyncEnabled() {
go func() {
onboard.NewDefaultServiceSynchronizer().Run()
serviceSynchronizer, err := onboard.NewDefaultServiceSynchronizer()
if err != nil {
log.WithError(err).Error("Could not create service synchronizer")
return
}

serviceSynchronizer.Run()
}()
}

Expand All @@ -58,7 +64,13 @@ func _main(args []string, envCfg envConfig) int {
}

func gotEvent(ctx context.Context, event cloudevents.Event) error {
err := event_handler.NewEventHandler(event).HandleEvent()
handler, err := event_handler.NewEventHandler(event)
if err != nil {
log.WithError(err).Error("Could not create event handler")
return err
}

err = handler.HandleEvent()
if err != nil {
log.WithError(err).Error("HandleEvent() returned an error")
}
Expand Down
3 changes: 2 additions & 1 deletion internal/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import (
"github.com/keptn/go-utils/pkg/lib/keptn"
)

const KEPTNSBRIDGE_LABEL = "Keptns Bridge"
const BridgeLabel = "Keptns Bridge"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[golint] reported by reviewdog 🐶
exported const BridgeLabel should have comment or be unexported

const ProblemURLLabel = "Problem URL"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[golint] reported by reviewdog 🐶
exported const ProblemURLLabel should have comment or be unexported


// ShipyardControllerURLEnvironmentVariableName is the name of the environment variable for specifying the shipyard controller URL.
const ShipyardControllerURLEnvironmentVariableName = "SHIPYARD_CONTROLLER"
Expand Down
4 changes: 2 additions & 2 deletions internal/config/dynatrace_config_getter.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ type DynatraceConfigProvider interface {
}

type DynatraceConfigGetter struct {
resourceClient keptn.DynatraceConfigResourceClientInterface
resourceClient keptn.DynatraceConfigReaderInterface
}

func NewDynatraceConfigGetter(client keptn.DynatraceConfigResourceClientInterface) *DynatraceConfigGetter {
func NewDynatraceConfigGetter(client keptn.DynatraceConfigReaderInterface) *DynatraceConfigGetter {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[golint] reported by reviewdog 🐶
exported function NewDynatraceConfigGetter should have comment or be unexported

return &DynatraceConfigGetter{
resourceClient: client,
}
Expand Down
3 changes: 2 additions & 1 deletion internal/deployment/evaluation_finished_event_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package deployment

import (
"fmt"

"github.com/keptn-contrib/dynatrace-service/internal/common"
"github.com/keptn-contrib/dynatrace-service/internal/dynatrace"
"github.com/keptn-contrib/dynatrace-service/internal/keptn"
Expand Down Expand Up @@ -50,7 +51,7 @@ func (eh *EvaluationFinishedEventHandler) HandleEvent() error {
pid, err := eh.eClient.FindProblemID(eh.event)
if err == nil && pid != "" {
// Comment we push over
comment := fmt.Sprintf("[Keptn remediation evaluation](%s) resulted in %s (%.2f/100)", eh.event.GetLabels()[common.KEPTNSBRIDGE_LABEL], eh.event.GetResult(), eh.event.GetEvaluationScore())
comment := fmt.Sprintf("[Keptn remediation evaluation](%s) resulted in %s (%.2f/100)", eh.event.GetLabels()[common.BridgeLabel], eh.event.GetResult(), eh.event.GetEvaluationScore())

// this is posting the Event on the problem as a comment
dynatrace.NewProblemsClient(eh.dtClient).AddProblemComment(pid, comment)
Expand Down
17 changes: 10 additions & 7 deletions internal/event_handler/error_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,19 @@ import (
"github.com/keptn-contrib/dynatrace-service/internal/sli"
)

// ErrorHandler handles errors by trying to send them to Keptn Uniform.
type ErrorHandler struct {
err error
evt cloudevents.Event
err error
evt cloudevents.Event
uniformClient keptn.UniformClientInterface
}

func NewErrorHandler(err error, event cloudevents.Event) *ErrorHandler {
// NewErrorHandler creates a new ErrorHandler for the specified error, event and UniformClientInterface.
func NewErrorHandler(err error, event cloudevents.Event, uniformClient keptn.UniformClientInterface) *ErrorHandler {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[golint] reported by reviewdog 🐶
exported function NewErrorHandler should have comment or be unexported

return &ErrorHandler{
err: err,
evt: event,
err: err,
evt: event,
uniformClient: uniformClient,
}
}

Expand Down Expand Up @@ -59,8 +63,7 @@ func (eh ErrorHandler) sendErroredGetSLIFinishedEvent(keptnClient *keptn.Client)
}

func (eh ErrorHandler) sendErrorEvent(keptnClient *keptn.Client) error {
uniformClient := keptn.NewDefaultUniformClient()
integrationID, err := uniformClient.GetIntegrationIDFor(event.GetEventSource())
integrationID, err := eh.uniformClient.GetIntegrationIDByName(event.GetEventSource())
if err != nil {
log.WithError(err).Error("Could not retrieve integration ID from Keptn Uniform")
// no need to continue here, message will not show up in Uniform
Expand Down
43 changes: 26 additions & 17 deletions internal/event_handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import (
"fmt"

cloudevents "github.com/cloudevents/sdk-go/v2"
api "github.com/keptn/go-utils/pkg/api/utils"
keptnevents "github.com/keptn/go-utils/pkg/lib"
keptnv2 "github.com/keptn/go-utils/pkg/lib/v0_2_0"
log "github.com/sirupsen/logrus"

"github.com/keptn-contrib/dynatrace-service/internal/adapter"
"github.com/keptn-contrib/dynatrace-service/internal/common"
"github.com/keptn-contrib/dynatrace-service/internal/config"
"github.com/keptn-contrib/dynatrace-service/internal/credentials"
"github.com/keptn-contrib/dynatrace-service/internal/deployment"
Expand All @@ -20,22 +22,29 @@ import (
"github.com/keptn-contrib/dynatrace-service/internal/sli"
)

// DynatraceEventHandler is the common interface for all event handlers.
type DynatraceEventHandler interface {
HandleEvent() error
}

func NewEventHandler(event cloudevents.Event) DynatraceEventHandler {
eventHandler, err := getEventHandler(event)
// NewEventHandler creates a new DynatraceEventHandler for the specified event or returns an error.
func NewEventHandler(event cloudevents.Event) (DynatraceEventHandler, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[golint] reported by reviewdog 🐶
exported function NewEventHandler should have comment or be unexported

keptnAPISet, err := api.New(common.GetShipyardControllerURL())
if err != nil {
return nil, fmt.Errorf("could not create Keptn API set: %w", err)
}

eventHandler, err := getEventHandler(event, *keptnAPISet)
if err != nil {
err = fmt.Errorf("cannot handle event: %w", err)
log.Error(err.Error())
return NewErrorHandler(err, event)
return NewErrorHandler(err, event, keptn.NewUniformClient(keptnAPISet.UniformV1())), nil
}

return eventHandler
return eventHandler, nil
}

func getEventHandler(event cloudevents.Event) (DynatraceEventHandler, error) {
func getEventHandler(event cloudevents.Event, keptnAPISet api.APISet) (DynatraceEventHandler, error) {
log.WithField("eventType", event.Type()).Debug("Received event")

keptnEvent, err := getEventAdapter(event)
Expand All @@ -52,7 +61,7 @@ func getEventHandler(event cloudevents.Event) (DynatraceEventHandler, error) {
return nil, errors.New("event has no project")
}

dynatraceConfigGetter := config.NewDynatraceConfigGetter(keptn.NewDefaultResourceClient())
dynatraceConfigGetter := config.NewDynatraceConfigGetter(keptn.NewConfigClient(keptn.NewResourceClient(keptnAPISet.ResourcesV1())))
dynatraceConfig, err := dynatraceConfigGetter.GetDynatraceConfig(keptnEvent)
if err != nil {
return nil, fmt.Errorf("could not get configuration: %w", err)
Expand All @@ -77,29 +86,29 @@ func getEventHandler(event cloudevents.Event) (DynatraceEventHandler, error) {

switch aType := keptnEvent.(type) {
case *monitoring.ConfigureMonitoringAdapter:
return monitoring.NewConfigureMonitoringEventHandler(keptnEvent.(*monitoring.ConfigureMonitoringAdapter), dtClient, kClient, keptn.NewDefaultResourceClient(), keptn.NewDefaultServiceClient()), nil
return monitoring.NewConfigureMonitoringEventHandler(keptnEvent.(*monitoring.ConfigureMonitoringAdapter), dtClient, kClient, keptn.NewConfigClient(keptn.NewResourceClient(keptnAPISet.ResourcesV1())), keptn.NewServiceClient(keptnAPISet.ServicesV1(), keptnAPISet.APIV1())), nil
case *problem.ProblemAdapter:
return problem.NewProblemEventHandler(keptnEvent.(*problem.ProblemAdapter), kClient), nil
case *problem.ActionTriggeredAdapter:
return problem.NewActionTriggeredEventHandler(keptnEvent.(*problem.ActionTriggeredAdapter), dtClient, keptn.NewDefaultEventClient(), dynatraceConfig.AttachRules), nil
return problem.NewActionTriggeredEventHandler(keptnEvent.(*problem.ActionTriggeredAdapter), dtClient, keptn.NewEventClient(keptnAPISet.EventsV1()), dynatraceConfig.AttachRules), nil
case *problem.ActionStartedAdapter:
return problem.NewActionStartedEventHandler(keptnEvent.(*problem.ActionStartedAdapter), dtClient, keptn.NewDefaultEventClient()), nil
return problem.NewActionStartedEventHandler(keptnEvent.(*problem.ActionStartedAdapter), dtClient, keptn.NewEventClient(keptnAPISet.EventsV1())), nil
case *problem.ActionFinishedAdapter:
return problem.NewActionFinishedEventHandler(keptnEvent.(*problem.ActionFinishedAdapter), dtClient, keptn.NewDefaultEventClient(), dynatraceConfig.AttachRules), nil
return problem.NewActionFinishedEventHandler(keptnEvent.(*problem.ActionFinishedAdapter), dtClient, keptn.NewEventClient(keptnAPISet.EventsV1()), dynatraceConfig.AttachRules), nil
case *sli.GetSLITriggeredAdapter:
return sli.NewGetSLITriggeredHandler(keptnEvent.(*sli.GetSLITriggeredAdapter), dtClient, kClient, keptn.NewDefaultResourceClient(), dynatraceConfig.DtCreds, dynatraceConfig.Dashboard), nil
return sli.NewGetSLITriggeredHandler(keptnEvent.(*sli.GetSLITriggeredAdapter), dtClient, kClient, keptn.NewConfigClient(keptn.NewResourceClient(keptnAPISet.ResourcesV1())), dynatraceConfig.DtCreds, dynatraceConfig.Dashboard), nil
case *deployment.DeploymentFinishedAdapter:
return deployment.NewDeploymentFinishedEventHandler(keptnEvent.(*deployment.DeploymentFinishedAdapter), dtClient, keptn.NewDefaultEventClient(), dynatraceConfig.AttachRules), nil
return deployment.NewDeploymentFinishedEventHandler(keptnEvent.(*deployment.DeploymentFinishedAdapter), dtClient, keptn.NewEventClient(keptnAPISet.EventsV1()), dynatraceConfig.AttachRules), nil
case *deployment.TestTriggeredAdapter:
return deployment.NewTestTriggeredEventHandler(keptnEvent.(*deployment.TestTriggeredAdapter), dtClient, keptn.NewDefaultEventClient(), dynatraceConfig.AttachRules), nil
return deployment.NewTestTriggeredEventHandler(keptnEvent.(*deployment.TestTriggeredAdapter), dtClient, keptn.NewEventClient(keptnAPISet.EventsV1()), dynatraceConfig.AttachRules), nil
case *deployment.TestFinishedAdapter:
return deployment.NewTestFinishedEventHandler(keptnEvent.(*deployment.TestFinishedAdapter), dtClient, keptn.NewDefaultEventClient(), dynatraceConfig.AttachRules), nil
return deployment.NewTestFinishedEventHandler(keptnEvent.(*deployment.TestFinishedAdapter), dtClient, keptn.NewEventClient(keptnAPISet.EventsV1()), dynatraceConfig.AttachRules), nil
case *deployment.EvaluationFinishedAdapter:
return deployment.NewEvaluationFinishedEventHandler(keptnEvent.(*deployment.EvaluationFinishedAdapter), dtClient, keptn.NewDefaultEventClient(), dynatraceConfig.AttachRules), nil
return deployment.NewEvaluationFinishedEventHandler(keptnEvent.(*deployment.EvaluationFinishedAdapter), dtClient, keptn.NewEventClient(keptnAPISet.EventsV1()), dynatraceConfig.AttachRules), nil
case *deployment.ReleaseTriggeredAdapter:
return deployment.NewReleaseTriggeredEventHandler(keptnEvent.(*deployment.ReleaseTriggeredAdapter), dtClient, keptn.NewDefaultEventClient(), dynatraceConfig.AttachRules), nil
return deployment.NewReleaseTriggeredEventHandler(keptnEvent.(*deployment.ReleaseTriggeredAdapter), dtClient, keptn.NewEventClient(keptnAPISet.EventsV1()), dynatraceConfig.AttachRules), nil
default:
return NewErrorHandler(fmt.Errorf("this should not have happened, we are missing an implementation for: %T", aType), event), nil
return NewErrorHandler(fmt.Errorf("this should not have happened, we are missing an implementation for: %T", aType), event, keptn.NewUniformClient(keptnAPISet.UniformV1())), nil
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,29 @@ import (
"github.com/keptn-contrib/dynatrace-service/internal/dynatrace"
)

type SLOResourceReaderInterface interface {
// SLOReaderInterface provides functionality for getting SLOs.
type SLOReaderInterface interface {
// GetSLOs gets the SLOs stored for exactly the specified project, stage and service.
GetSLOs(project string, stage string, service string) (*keptn.ServiceLevelObjectives, error)
}
type SLIAndSLOResourceWriterInterface interface {

// SLIAndSLOWriterInterface provides functionality for uploading SLIs and SLOs.
type SLIAndSLOWriterInterface interface {
// UploadSLIs uploads the SLIs for the specified project, stage and service.
UploadSLIs(project string, stage string, service string, slis *dynatrace.SLI) error

// UploadSLOs uploads the SLOs for the specified project, stage and service.
UploadSLOs(project string, stage string, service string, slos *keptn.ServiceLevelObjectives) error
}
type ResourceClientInterface interface {
SLOResourceReaderInterface
SLIAndSLOResourceWriterInterface

// SLOAndSLIClientInterface provides functionality for getting SLOs and uploading SLIs and SLOs.
type SLOAndSLIClientInterface interface {
SLOReaderInterface
SLIAndSLOWriterInterface
}

type DynatraceConfigResourceClientInterface interface {
// DynatraceConfigReaderInterface provides functionality for getting a Dynatrace config.
type DynatraceConfigReaderInterface interface {
// GetDynatraceConfig gets the Dynatrace config for the specified project, stage and service, checking first on the service, then stage and then project level.
GetDynatraceConfig(project string, stage string, service string) (string, error)
}
Expand All @@ -35,25 +41,20 @@ const sloFilename = "slo.yaml"
const sliFilename = "dynatrace/sli.yaml"
const configFilename = "dynatrace/dynatrace.conf.yaml"

// ResourceClient is the default implementation for the *ResourceClientInterfaces using a ConfigResourceClientInterface
type ResourceClient struct {
client ConfigResourceClientInterface
}

// NewDefaultResourceClient creates a new ResourceClient with a default Keptn resource handler for the configuration service
func NewDefaultResourceClient() *ResourceClient {
return NewResourceClient(
NewDefaultConfigResourceClient())
// ConfigClient is the default implementation for ResourceClientInterface using a ConfigResourceClientInterface.
type ConfigClient struct {
client ResourceClientInterface
}

// NewResourceClient creates a new ResourceClient with a Keptn resource handler for the configuration service
func NewResourceClient(client ConfigResourceClientInterface) *ResourceClient {
return &ResourceClient{
// NewConfigClient creates a new ConfigClient with a Keptn resource handler for the configuration service.
func NewConfigClient(client ResourceClientInterface) *ConfigClient {
return &ConfigClient{
client: client,
}
}

func (rc *ResourceClient) GetSLOs(project string, stage string, service string) (*keptn.ServiceLevelObjectives, error) {
// GetSLOs gets the SLOs stored for exactly the specified project, stage and service.
func (rc *ConfigClient) GetSLOs(project string, stage string, service string) (*keptn.ServiceLevelObjectives, error) {
resource, err := rc.client.GetServiceResource(project, stage, service, sloFilename)
if err != nil {
return nil, err
Expand All @@ -68,8 +69,8 @@ func (rc *ResourceClient) GetSLOs(project string, stage string, service string)
return slos, nil
}

func (rc *ResourceClient) UploadSLOs(project string, stage string, service string, slos *keptn.ServiceLevelObjectives) error {
// and now we save it back to Keptn
// UploadSLOs uploads the SLOs for the specified project, stage and service.
func (rc *ConfigClient) UploadSLOs(project string, stage string, service string, slos *keptn.ServiceLevelObjectives) error {
yamlAsByteArray, err := yaml.Marshal(slos)
if err != nil {
return fmt.Errorf("could not convert SLOs to YAML: %s", err)
Expand All @@ -78,7 +79,8 @@ func (rc *ResourceClient) UploadSLOs(project string, stage string, service strin
return rc.client.UploadResource(yamlAsByteArray, sloFilename, project, stage, service)
}

func (rc *ResourceClient) UploadSLIs(project string, stage string, service string, slis *dynatrace.SLI) error {
// UploadSLIs uploads the SLIs for the specified project, stage and service.
func (rc *ConfigClient) UploadSLIs(project string, stage string, service string, slis *dynatrace.SLI) error {
yamlAsByteArray, err := yaml.Marshal(slis)
if err != nil {
return fmt.Errorf("could not convert SLIs to YAML: %s", err)
Expand All @@ -87,6 +89,7 @@ func (rc *ResourceClient) UploadSLIs(project string, stage string, service strin
return rc.client.UploadResource(yamlAsByteArray, sliFilename, project, stage, service)
}

func (rc *ResourceClient) GetDynatraceConfig(project string, stage string, service string) (string, error) {
// GetDynatraceConfig gets the Dynatrace config for the specified project, stage and service, checking first on the service, then stage and then project level.
func (rc *ConfigClient) GetDynatraceConfig(project string, stage string, service string) (string, error) {
return rc.client.GetResource(project, stage, service, configFilename)
}
Loading