From 91c940971dd01d641ddeb16ea9044e21520dd799 Mon Sep 17 00:00:00 2001 From: TannerGabriel Date: Wed, 31 Aug 2022 13:07:34 +0200 Subject: [PATCH] feat!: Reimplement service with go-sdk (#351) * chore: Remove useLocalFileSystem implementation Signed-off-by: TannerGabriel * Implement main and event handler in go-sdk Signed-off-by: TannerGabriel * Add go-sdk environment variables + Update code Signed-off-by: TannerGabriel * Start reimplementing unit tests Signed-off-by: TannerGabriel * Use go-utils APIV2 Signed-off-by: TannerGabriel * Add PUBSUB topic + Code quality changes Signed-off-by: TannerGabriel * Change uniform subscription default value Signed-off-by: TannerGabriel * Fix / escaping in GetAllKeptnResources Signed-off-by: TannerGabriel * Add logging to tests Signed-off-by: TannerGabriel * Add health endpoints in Helm file + Fix jobconfig integration tests Signed-off-by: TannerGabriel * Add mountFile unit tests + PR comments Signed-off-by: TannerGabriel * Remove log statements Signed-off-by: TannerGabriel * Convert eventhandler tests to go-sdk Signed-off-by: TannerGabriel * Fix JobConfigReader creation in event handler Signed-off-by: TannerGabriel * Add function documentation Signed-off-by: TannerGabriel Signed-off-by: TannerGabriel --- .github/workflows/integration-tests.yaml | 5 +- README.md | 4 +- chart/templates/configmap.yaml | 1 + chart/templates/deployment.yaml | 169 ++++---- chart/values.yaml | 3 + .../main.go | 32 +- cmd/job-executor-service/main.go | 126 +++--- go.mod | 9 +- go.sum | 69 +--- pkg/config/fake/reader_mock.go | 15 + pkg/config/reader.go | 4 + pkg/eventhandler/eventhandlers.go | 150 ++++--- pkg/eventhandler/eventhandlers_test.go | 383 +++++++++++------- pkg/eventhandler/eventmapper.go | 26 +- pkg/eventhandler/eventmapper_test.go | 36 +- pkg/eventhandler/fake/eventhandlers_mock.go | 3 +- pkg/file/file.go | 9 +- pkg/file/file_test.go | 102 +++-- pkg/keptn/config_service.go | 249 ------------ pkg/keptn/config_service_test.go | 299 -------------- pkg/keptn/fake/config_service_mock.go | 137 ------- pkg/keptn/fake/keptn_resourcehandler_mock.go | 260 +++++++++++- pkg/keptn/resource_service.go | 113 +++++- pkg/keptn/resource_service_test.go | 13 +- test/e2e/gitcommitid_test.go | 4 +- test/e2e/jobconfig_test.go | 11 +- test/e2e/keptn.go | 59 ++- test/e2e/noingress_test.go | 1 + test/e2e/utils.go | 3 +- 29 files changed, 1003 insertions(+), 1292 deletions(-) delete mode 100644 pkg/keptn/config_service.go delete mode 100644 pkg/keptn/config_service_test.go delete mode 100644 pkg/keptn/fake/config_service_mock.go diff --git a/.github/workflows/integration-tests.yaml b/.github/workflows/integration-tests.yaml index 5810e1e4..fb02fb3b 100644 --- a/.github/workflows/integration-tests.yaml +++ b/.github/workflows/integration-tests.yaml @@ -32,7 +32,7 @@ jobs: strategy: fail-fast: false matrix: - keptn-version: ["0.16.1", "0.17.0", "${{ needs.fetch_latest_keptn_versions.outputs.LATEST_KEPTN_RELEASE }}", "${{ needs.fetch_latest_keptn_versions.outputs.LATEST_KEPTN_PRERELEASE }}"] # https://github.com/keptn/keptn/releases + keptn-version: ["0.18.1", "${{ needs.fetch_latest_keptn_versions.outputs.LATEST_KEPTN_RELEASE }}", "${{ needs.fetch_latest_keptn_versions.outputs.LATEST_KEPTN_PRERELEASE }}"] # https://github.com/keptn/keptn/releases network-policy: [true, false] job-network-policy: [true, false] env: @@ -42,6 +42,7 @@ jobs: BRANCH: ${{ github.head_ref || github.ref_name }} JES_E2E_TEST: true JES_NAMESPACE: keptn-jes-e2e + GITEA_PROVISIONER_VERSION: "0.1.1" GITEA_ADMIN_USERNAME: GiteaAdmin GITEA_NAMESPACE: gitea KUBECONFIG: /etc/rancher/k3s/k3s.yaml @@ -124,7 +125,7 @@ jobs: GITEA_ADMIN_PASSWORD: ${{ steps.gitea_credentials.outputs.GITEA_ADMIN_PASSWORD }} GITEA_ENDPOINT: ${{ steps.gitea.outputs.GITEA_ENDPOINT }} run: | - helm install keptn-gitea-provisioner-service https://github.com/keptn-sandbox/keptn-gitea-provisioner-service/releases/download/0.1.0/keptn-gitea-provisioner-service-0.1.0.tgz \ + helm install keptn-gitea-provisioner-service https://github.com/keptn-sandbox/keptn-gitea-provisioner-service/releases/download/${GITEA_PROVISIONER_VERSION}/keptn-gitea-provisioner-service-${GITEA_PROVISIONER_VERSION}.tgz \ --set gitea.endpoint=${GITEA_ENDPOINT} \ --set gitea.admin.create=true \ --set gitea.admin.username=${GITEA_ADMIN_USERNAME} \ diff --git a/README.md b/README.md index 230b20b9..a3b60462 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ running in the Keptn ecosystem: | 0.16.x | keptncontrib/job-executor-service:0.2.3 | v2 | | 0.16.x | keptncontrib/job-executor-service:0.2.4 | v2 | | 0.17.x | keptncontrib/job-executor-service:0.2.5 | v2 | - +| 0.18.x | keptncontrib/job-executor-service:0.3.0 | v2 | **Please Note**: - Newer Keptn versions might be compatible, but compatibility has not been verified at the time of the release. @@ -91,7 +91,7 @@ keptn add-resource --project jes-example --service hello --stage production --re Trigger the `example-seq` sequence. ```shell -keptn trigger sequence --sequence example-seq --project jes-example --service hello --stage production +keptn trigger sequence example-seq --project jes-example --service hello --stage production ``` Have a look at the sequences for the project in Keptn bridge, it should look similar to the screenshot below: diff --git a/chart/templates/configmap.yaml b/chart/templates/configmap.yaml index ec79ed9f..95175bfa 100644 --- a/chart/templates/configmap.yaml +++ b/chart/templates/configmap.yaml @@ -10,6 +10,7 @@ data: default_resource_requests_cpu: "50m" default_resource_requests_memory: "128Mi" keptn_api_endpoint: {{ include "job-executor-service.remote-control-plane.endpoint" . }} + configuration_service: "{{ include "job-executor-service.remote-control-plane.endpoint" . }}/resource-service" default_job_service_account: "{{ include "job-executor-service.jobConfig.serviceAccountName" . }}" allow_privileged_jobs: "{{ .Values.jobConfig.allowPrivilegedJobs | default "false" }}" additional_job_labels: | diff --git a/chart/templates/deployment.yaml b/chart/templates/deployment.yaml index e8d24e72..0db7548a 100644 --- a/chart/templates/deployment.yaml +++ b/chart/templates/deployment.yaml @@ -39,6 +39,14 @@ spec: - name: http containerPort: 8080 protocol: TCP + livenessProbe: + httpGet: + path: /health + port: 8080 + readinessProbe: + httpGet: + path: /health + port: 8080 volumeMounts: - mountPath: "/config" name: job-executor-settings @@ -49,8 +57,8 @@ spec: secretKeyRef: name: job-service-keptn-secrets key: token - - name: CONFIGURATION_SERVICE - value: "http://localhost:8081/configuration-service" + - name: PUBSUB_TOPIC + value: {{ ((.Values).subscription).pubsubTopic | default "sh.keptn.>" }} - name: env value: 'production' - name: JOB_NAMESPACE @@ -100,101 +108,76 @@ spec: configMapKeyRef: name: job-service-config key: task_deadline_seconds + - name: KEPTN_API_ENDPOINT + valueFrom: + configMapKeyRef: + name: job-service-config + key: keptn_api_endpoint + - name: CONFIGURATION_SERVICE + valueFrom: + configMapKeyRef: + name: job-service-config + key: configuration_service + - name: K8S_DEPLOYMENT_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: 'metadata.labels[''app.kubernetes.io/name'']' + - name: K8S_DEPLOYMENT_VERSION + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: 'metadata.labels[''app.kubernetes.io/version'']' + - name: K8S_DEPLOYMENT_COMPONENT + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: 'metadata.labels[''app.kubernetes.io/component'']' + - name: K8S_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: K8S_NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: K8S_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name - name: FULL_DEPLOYMENT_NAME value: {{ include "job-executor-service.fullname" . }} - resources: - {{- toYaml .Values.resources | nindent 12 }} - - name: distributor - image: "{{ .Values.distributor.image.repository }}:{{ .Values.distributor.image.tag | default .Chart.AppVersion }}" - securityContext: - {{- toYaml .Values.distributor.securityContext | nindent 12 }} - imagePullPolicy: Always - ports: - - containerPort: 8080 - resources: - requests: - memory: "16Mi" - cpu: "25m" - limits: - memory: "32Mi" - cpu: "100m" - env: - - name: PUBSUB_TOPIC - value: "{{ .Values.remoteControlPlane.topicSubscription }}" - - name: PUBSUB_RECIPIENT - value: '127.0.0.1' - - name: STAGE_FILTER - value: "{{ .Values.distributor.stageFilter }}" - - name: PROJECT_FILTER - value: "{{ .Values.distributor.projectFilter }}" - - name: SERVICE_FILTER - value: "{{ .Values.distributor.serviceFilter }}" - - name: DISTRIBUTOR_VERSION - value: {{ .Values.distributor.image.tag | default .Chart.AppVersion }} - - name: VERSION - valueFrom: - fieldRef: - fieldPath: metadata.labels['app.kubernetes.io/version'] - - name: K8S_DEPLOYMENT_NAME - valueFrom: - fieldRef: - fieldPath: metadata.labels['app.kubernetes.io/name'] - - name: K8S_POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: K8S_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: K8S_NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - - name: KEPTN_API_ENDPOINT - valueFrom: - configMapKeyRef: + - name: HTTP_SSL_VERIFY + value: "{{ .Values.remoteControlPlane.api.apiValidateTls | default "true" }}" + {{- if eq ((.Values.remoteControlPlane).api.authMode) "oauth" }} + - name: OAUTH_CLIENT_ID + valueFrom: + configMapKeyRef: name: job-service-config - key: keptn_api_endpoint - {{- if eq ((.Values.remoteControlPlane).api.authMode) "token" }} - - name: KEPTN_API_TOKEN - valueFrom: - secretKeyRef: + key: oauth_client_id + - name: OAUTH_CLIENT_SECRET + valueFrom: + secretKeyRef: name: job-service-keptn-secrets - key: token - {{- end }} - - name: HTTP_SSL_VERIFY - value: "{{ .Values.remoteControlPlane.api.apiValidateTls | default "true" }}" - {{- if (((.Values.distributor).config).queueGroup).enabled | default true }} - - name: PUBSUB_GROUP - valueFrom: - fieldRef: - fieldPath: metadata.labels['app.kubernetes.io/name'] - {{- end }} - {{- if eq ((.Values.remoteControlPlane).api.authMode) "oauth" }} - - name: OAUTH_CLIENT_ID - valueFrom: - configMapKeyRef: - name: job-service-config - key: oauth_client_id - - name: OAUTH_CLIENT_SECRET - valueFrom: - secretKeyRef: - name: job-service-keptn-secrets - key: oauth_client_secret - - name: OAUTH_DISCOVERY - valueFrom: - configMapKeyRef: - name: job-service-config - key: oauth_discovery - - name: OAUTH_SCOPES - valueFrom: - configMapKeyRef: - name: job-service-config - key: oauth_scopes - {{- end }} - - name: API_PROXY_MAX_PAYLOAD_BYTES_KB - value: "128" + key: oauth_client_secret + - name: OAUTH_DISCOVERY + valueFrom: + configMapKeyRef: + name: job-service-config + key: oauth_discovery + - name: OAUTH_SCOPES + valueFrom: + configMapKeyRef: + name: job-service-config + key: oauth_scopes + {{- end }} + - name: API_PROXY_MAX_PAYLOAD_BYTES_KB + value: "128" + resources: + {{- toYaml .Values.resources | nindent 12 }} volumes: - name: job-executor-settings projected: diff --git a/chart/values.yaml b/chart/values.yaml index ce0a95fd..9466b095 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -6,6 +6,9 @@ image: # Overrides the image tag whose default is the chart appVersion. tag: "" +subscription: + pubsubTopic: "sh.keptn.event.test.triggered,sh.keptn.event.deployment.triggered,sh.keptn.event.evaluation.triggered,sh.keptn.event.release.triggered,sh.keptn.event.approval.triggered,sh.keptn.event.action.triggered" # Sets the events the service subscribes to + jobexecutorserviceinitcontainer: image: repository: docker.io/keptncontrib/job-executor-service-initcontainer # Container Image Name diff --git a/cmd/job-executor-service-initcontainer/main.go b/cmd/job-executor-service-initcontainer/main.go index ea2401ff..83db65a5 100644 --- a/cmd/job-executor-service-initcontainer/main.go +++ b/cmd/job-executor-service-initcontainer/main.go @@ -4,8 +4,9 @@ import ( "context" oauthutils "github.com/keptn/go-utils/pkg/common/oauth2" "golang.org/x/oauth2/clientcredentials" + "keptn-contrib/job-executor-service/pkg/config" "keptn-contrib/job-executor-service/pkg/file" - "keptn-contrib/job-executor-service/pkg/keptn" + keptn_interface "keptn-contrib/job-executor-service/pkg/keptn" "log" "net/http" "net/url" @@ -14,6 +15,8 @@ import ( "github.com/kelseyhightower/envconfig" api "github.com/keptn/go-utils/pkg/api/utils/v2" + //api "github.com/keptn/go-utils/pkg/api/utils/v2" + keptnv2 "github.com/keptn/go-utils/pkg/lib/v0_2_0" "github.com/spf13/afero" ) @@ -24,7 +27,7 @@ const OAuthDiscoveryTimeout = 10 * time.Second type envConfig struct { // Whether we are running locally (e.g., for testing) or on production Env string `envconfig:"ENV" default:"local"` - // URL of the Keptn configuration service (this is where we can fetch files from the config repo) + // URL of the Keptn API Endpoint KeptnAPIURL string `envconfig:"KEPTN_API_URL" required:"true"` // The token of the keptn API KeptnAPIToken string `envconfig:"KEPTN_API_TOKEN" required:"true"` @@ -112,25 +115,20 @@ func main() { log.Fatalf("unable to create keptn API: %s", err) } - useLocalFileSystem := false - - // configure keptn options - if env.Env == "local" { - log.Println("env=local: Running with local filesystem to fetch resources") - useLocalFileSystem = true - } - // re-create the event from job-executor-service - eventProps := keptn.EventProperties{ - Project: env.Project, - Stage: env.Stage, - Service: env.Service, - GitCommitID: env.GitCommitID, + eventProps := &keptnv2.EventData{ + Project: env.Project, + Stage: env.Stage, + Service: env.Service, } - configService := keptn.NewConfigService(useLocalFileSystem, eventProps, keptnAPI.Resources()) + resourceService := keptn_interface.NewV1ResourceHandler(*eventProps, keptnAPI.Resources()) + + jobConfigHandler := config.JobConfigReader{ + Keptn: resourceService, + } - err = file.MountFiles(env.Action, env.Task, fs, configService) + err = file.MountFiles(env.Action, env.Task, env.GitCommitID, fs, jobConfigHandler) if err != nil { log.Printf("Error while copying files: %s", err.Error()) os.Exit(-1) diff --git a/cmd/job-executor-service/main.go b/cmd/job-executor-service/main.go index 5f1f64f2..d6b4440b 100644 --- a/cmd/job-executor-service/main.go +++ b/cmd/job-executor-service/main.go @@ -3,11 +3,11 @@ package main import ( "context" "fmt" + "github.com/keptn/go-utils/pkg/sdk" + "github.com/sirupsen/logrus" "log" - "net" "os" - api "github.com/keptn/go-utils/pkg/api/utils" v1 "k8s.io/api/core/v1" "keptn-contrib/job-executor-service/pkg/config" @@ -34,10 +34,10 @@ type envConfig struct { Path string `envconfig:"RCV_PATH" default:"/"` // Whether we are running locally (e.g., for testing) or on production Env string `envconfig:"ENV" default:"local"` - // URL of the Keptn configuration service (this is where we can fetch files from the config repo) - ConfigurationServiceURL string `envconfig:"CONFIGURATION_SERVICE" default:""` // The k8s namespace the job will run in JobNamespace string `envconfig:"JOB_NAMESPACE" required:"true"` + // URL of the Keptn API endpoint + KeptnAPIENDPOINT string `envconfig:"KEPTN_API_ENDPOINT" required:"true"` // The token of the keptn API KeptnAPIToken string `envconfig:"KEPTN_API_TOKEN"` // The init container image to use @@ -93,28 +93,13 @@ var /* const */ JobLabels map[string]string // TaskDeadlineSecondsPtr represents the max duration of a task run, no limit if nil var TaskDeadlineSecondsPtr *int64 -/** - * This method gets called when a new event is received from the Keptn Event Distributor - * Depending on the Event Type will call the specific event handler functions, e.g: handleDeploymentFinishedEvent - * See https://github.com/keptn/spec/blob/0.2.0-alpha/cloudevents.md for details on the payload - */ -func processKeptnCloudEvent(ctx context.Context, event cloudevents.Event, allowList *utils.ImageFilterList) error { - // create keptn handler - log.Printf("Initializing Keptn Handler") - myKeptn, err := keptnv2.NewKeptn(&event, keptnOptions) - if err != nil { - return fmt.Errorf("could not create Keptn Handler: %w", err) - } +const serviceName = "job-executor-service" +const eventWildcard = "*" - log.Printf("gotEvent(%s): %s - %s", event.Type(), myKeptn.KeptnContext, event.Context.GetID()) - - // create a uniform handler talking to the distributor - uniformHandler := api.NewUniformHandler("localhost:8081/controlPlane") - var eventHandler = &eventhandler.EventHandler{ - Keptn: myKeptn, - JobConfigReader: &config.JobConfigReader{ - Keptn: keptn_interface.NewV1ResourceHandler(myKeptn.Event, myKeptn.ResourceHandler), - }, +// NewEventHandler creates a new EventHandler +func NewEventHandler(allowList *utils.ImageFilterList) *eventhandler.EventHandler { + //uniformHandler := api.NewUniformHandler("localhost:8081/controlPlane") + return &eventhandler.EventHandler{ ServiceName: ServiceName, Mapper: new(eventhandler.KeptnCloudEventMapper), ImageFilter: imageFilterImpl{ @@ -133,22 +118,13 @@ func processKeptnCloudEvent(ctx context.Context, event cloudevents.Event, allowL TaskDeadlineSeconds: TaskDeadlineSecondsPtr, JesDeploymentName: env.FullDeploymentName, }, - K8s: k8sutils.NewK8s(""), // FIXME Why do we pass a namespoace if it's ignored? - ErrorSender: keptn_interface.NewErrorLogSender(ServiceName, uniformHandler, myKeptn), + K8s: k8sutils.NewK8s(""), // FIXME Why do we pass a namespace if it's ignored? } - - // prevent duplicate events - https://github.com/keptn/keptn/issues/3888 - go eventHandler.HandleEvent() - - return nil } /** * Usage: ./main * no args: starts listening for cloudnative events on localhost:port/path - * - * Environment Variables - * env=runlocal -> will fetch resources from local drive instead of configuration service */ func main() { if err := envconfig.Process("", &env); err != nil { @@ -194,26 +170,19 @@ func main() { TaskDeadlineSecondsPtr = &env.TaskDeadlineSeconds } - os.Exit(_main(os.Args[1:], env)) + _main(os.Args[1:], env) } /** * Opens up a listener on localhost:port/path and passes incoming requets to gotEvent */ -func _main(args []string, env envConfig) int { - - // configure keptn options - if env.Env == "local" { - log.Println("env=local: Running with local filesystem to fetch resources") - keptnOptions.UseLocalFileSystem = true - } - +func _main(args []string, env envConfig) { // Checking if the given job service account is empty if env.DefaultJobServiceAccount == "" { log.Println("WARNING: No default service account for jobs configured: using kubernetes default service account!") } - keptnOptions.ConfigurationServiceURL = env.ConfigurationServiceURL + keptnOptions.ConfigurationServiceURL = fmt.Sprintf("%s/resource-service", env.KeptnAPIENDPOINT) log.Println("Starting job-executor-service...") log.Printf(" on Port = %d; Path=%s", env.Port, env.Path) @@ -223,43 +192,62 @@ func _main(args []string, env envConfig) int { log.Printf("Creating new http handler") - // configure http server to receive cloudevents - listeningAddr := fmt.Sprintf("localhost:%d", env.Port) - listener, err := net.Listen( - "tcp", listeningAddr, - ) + imageFilterList, err := utils.BuildImageAllowList(env.AllowedImageList) if err != nil { - log.Fatalf("error listening on tcp %s: %v", listeningAddr, err) + log.Fatalf("failed to generate the allowlist, %v", err) } - p, err := cloudevents.NewHTTP( - cloudevents.WithPath(env.Path), - cloudevents.WithListener( - listener, - ), - ) + // Handle all events and filter them later in jobEventFilter + log.Fatal(sdk.NewKeptn( + serviceName, + sdk.WithTaskHandler( + eventWildcard, + NewEventHandler(imageFilterList), + jobEventFilter), + sdk.WithLogger(logrus.New()), + ).Start()) +} - if err != nil { - log.Fatalf("failed to create client, %v", err) +// jobEventFilter checks if a job/config exists and whether it contains the event type +func jobEventFilter(keptnHandle sdk.IKeptn, event sdk.KeptnEvent) bool { + keptnHandle.Logger().Infof("Received event of type: %s from %s with id: %s", *event.Type, *event.Source, event.ID) + + data := &keptnv2.EventData{} + if err := keptnv2.Decode(event.Data, data); err != nil { + keptnHandle.Logger().Errorf("Could not parse event: %s", err.Error()) + return false } - c, err := cloudevents.NewClient(p) - if err != nil { - log.Fatalf("failed to create client, %v", err) + + jcr := &config.JobConfigReader{ + Keptn: keptn_interface.NewV1ResourceHandler(*data, keptnHandle.APIV2().Resources()), } - imageFilterList, err := utils.BuildImageAllowList(env.AllowedImageList) + // Check if the job configuration can be found + configuration, _, err := jcr.GetJobConfig(event.GitCommitID) + if err != nil { - log.Fatalf("failed to generate the allowlist, %v", err) + keptnHandle.Logger().Infof("could not retrieve config for job-executor-service: %e", err) + return false } - processCloudEventFunc := func(ctx context.Context, event cloudevents.Event) error { - return processKeptnCloudEvent(ctx, event, imageFilterList) + // Check if we have an action that we can use, if it isn't the case we produce a log output + mapper := new(eventhandler.KeptnCloudEventMapper) + eventAsInterface, err := mapper.Map(event) + if err != nil { + keptnHandle.Logger().Infof("failed to convert incoming cloudevent: %v", err) + return false } - log.Printf("Starting receiver") - log.Fatal(c.StartReceiver(ctx, processCloudEventFunc)) + hasMatchingEvent := configuration.IsEventMatch(*event.Type, eventAsInterface) + if !hasMatchingEvent { + keptnHandle.Logger().Infof( + "No match found for event %s of type %s. Skipping...", event.ID, + event.Type, + ) + return false + } - return 0 + return true } type imageFilterImpl struct { diff --git a/go.mod b/go.mod index fa537f5e..e984808b 100644 --- a/go.mod +++ b/go.mod @@ -9,12 +9,13 @@ require ( github.com/gobwas/glob v0.2.3 github.com/golang/mock v1.6.0 github.com/kelseyhightower/envconfig v1.4.0 - github.com/keptn/go-utils v0.17.0 + github.com/keptn/go-utils v0.18.1-0.20220829063445-1f5af67a8cf3 github.com/mitchellh/mapstructure v1.5.0 + github.com/sirupsen/logrus v1.8.1 github.com/spf13/afero v1.8.2 github.com/stretchr/testify v1.8.0 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d - golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 + golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.24.3 k8s.io/apimachinery v0.24.3 @@ -26,6 +27,7 @@ require ( github.com/PaesslerAG/gval v1.0.0 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/avast/retry-go v3.0.0+incompatible // indirect github.com/benbjohnson/clock v1.3.0 // indirect github.com/cloudevents/sdk-go/observability/opentelemetry/v2 v2.0.0-20211001212819-74757a691209 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -49,6 +51,9 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/nats-io/nats.go v1.16.0 // indirect + github.com/nats-io/nkeys v0.3.0 // indirect + github.com/nats-io/nuid v1.0.1 // indirect github.com/nxadm/tail v1.4.8 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/go.sum b/go.sum index 514b90c0..3cac40f8 100644 --- a/go.sum +++ b/go.sum @@ -29,7 +29,6 @@ cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.102.0 h1:DAq3r8y4mDgyB/ZPJ9v/5VJNqjgJAxTn6ZYLlUywOu8= cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= @@ -84,11 +83,11 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdko github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -99,7 +98,6 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cloudevents/sdk-go/observability/opentelemetry/v2 v2.0.0-20211001212819-74757a691209 h1:pR23jlIJMXGMxljxP6QYytEsMQpPU2WT3Wjp1FWYOq0= github.com/cloudevents/sdk-go/observability/opentelemetry/v2 v2.0.0-20211001212819-74757a691209/go.mod h1:DmxtN+a7U9ktD8I0nTlI9CCrin/Tf7OdXxE3KBTjlOw= github.com/cloudevents/sdk-go/v2 v2.5.0/go.mod h1:nlXhgFkf0uTopxmRXalyMwS2LG70cRGPrxzmjJgSG0U= -github.com/cloudevents/sdk-go/v2 v2.10.0/go.mod h1:GpCBmUj7DIRiDhVvsK5d6WCbgTWs8DxAWTRtAwQmIXs= github.com/cloudevents/sdk-go/v2 v2.10.1 h1:qNFovJ18fWOd8Q9ydWJPk1oiFudXyv1GxJIP7MwPjuM= github.com/cloudevents/sdk-go/v2 v2.10.1/go.mod h1:GpCBmUj7DIRiDhVvsK5d6WCbgTWs8DxAWTRtAwQmIXs= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -129,7 +127,6 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= @@ -146,7 +143,6 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= @@ -162,7 +158,6 @@ github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -257,8 +252,6 @@ github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0 github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= -github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= @@ -277,18 +270,17 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= -github.com/keptn/go-utils v0.17.0 h1:AfxqcL1OBIRHbPDmxRzaVhgAf7Wz/wWrwafdw9i1iP0= -github.com/keptn/go-utils v0.17.0/go.mod h1:EPhgzrqJYbHzK8qbWDDKihWeRJKIkVGR7vi+jaAPftw= +github.com/keptn/go-utils v0.18.1-0.20220829063445-1f5af67a8cf3 h1:oxIfLMVAad11GT/tunwAftZcUDMJmPLaLsQAXzsui0E= +github.com/keptn/go-utils v0.18.1-0.20220829063445-1f5af67a8cf3/go.mod h1:jPys4TFvxkN6KY3IhM5XWBeCCPQeLzsT6zTwt4iYfes= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.14.4/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.14.4 h1:eijASRJcobkVtSt81Olfh7JX43osYLwy5krOJo6YEu4= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -300,7 +292,7 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -316,11 +308,13 @@ github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8m github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/nats-io/jwt/v2 v2.2.1-0.20220330180145-442af02fd36a/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k= -github.com/nats-io/nats-server/v2 v2.8.4/go.mod h1:8zZa+Al3WsESfmgSs98Fi06dRWLH5Bnq90m5bKD/eT4= -github.com/nats-io/nats.go v1.15.0/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= +github.com/nats-io/jwt/v2 v2.2.1-0.20220330180145-442af02fd36a h1:lem6QCvxR0Y28gth9P+wV2K/zYUUAkJ+55U8cpS0p5I= +github.com/nats-io/nats-server/v2 v2.8.4 h1:0jQzze1T9mECg8YZEl8+WYUXb9JKluJfCBriPUtluB4= +github.com/nats-io/nats.go v1.16.0 h1:zvLE7fGBQYW6MWaFaRdsgm9qT39PJDQoju+DS8KsO1g= github.com/nats-io/nats.go v1.16.0/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= +github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8= github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= @@ -332,12 +326,10 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU= -github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -348,12 +340,12 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= @@ -375,7 +367,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -383,30 +374,23 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/contrib v0.23.0 h1:MgRuo0JZZX8J9WLRjyd7OpTSbaLOdQXXJa6SnZvlWLM= go.opentelemetry.io/contrib v0.23.0/go.mod h1:EH4yDYeNoaTqn/8yCWQmfNB78VHfGX2Jt2bvnvzBlGM= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.23.0/go.mod h1:wLrbAf2Qb+kFsEjowrxOcuy2SE0dcY0VwFiiYCmUeFQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0 h1:mac9BKRqwaX6zxHPDe3pvmWpwuuIM0vuXv2juCnQevE= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0/go.mod h1:5eCOqeGphOyz6TsY3ZDNjE33SM/TFAK3RGuCL2naTgY= go.opentelemetry.io/otel v1.0.0-RC3/go.mod h1:Ka5j3ua8tZs4Rkq4Ex3hwgBgOchyPVq5S6P2lz//nKQ= go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg= -go.opentelemetry.io/otel v1.2.0/go.mod h1:aT17Fk0Z1Nor9e0uisf98LrntPGMnk4frBO9+dkf69I= go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM= go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0/go.mod h1:14T5gr+Y6s2AgHPqBMgnGwp04csUjQmYXFWPeiBoq5s= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.2.0/go.mod h1:9mLBBnPRf3sf+ASVH2p9xREXVBvwib02FxcKnavtExg= go.opentelemetry.io/otel/internal/metric v0.23.0/go.mod h1:z+RPiDJe30YnCrOhFGivwBS+DU1JU/PiLKkk4re2DNY= go.opentelemetry.io/otel/metric v0.23.0/go.mod h1:G/Nn9InyNnIv7J6YVkQfpc0JCfKBNJaERBGw08nqmVQ= go.opentelemetry.io/otel/metric v0.30.0 h1:Hs8eQZ8aQgs0U49diZoaS6Uaxw3+bBE3lcMUKBFIk3c= go.opentelemetry.io/otel/metric v0.30.0/go.mod h1:/ShZ7+TS4dHzDFmfi1kSXMhMVubNoP0oIaBp70J6UXU= -go.opentelemetry.io/otel/sdk v1.2.0/go.mod h1:jNN8QtpvbsKhgaC6V5lHiejMoKD+V8uadoSafgHPx1U= go.opentelemetry.io/otel/trace v1.0.0-RC3/go.mod h1:VUt2TUYd8S2/ZRX09ZDFZQwn2RqfMB5MzO17jBojGxo= go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs= -go.opentelemetry.io/otel/trace v1.2.0/go.mod h1:N5FLswTubnxKxOJHM7XZC074qpeEdLy3CgAVsdMucK0= go.opentelemetry.io/otel/trace v1.7.0 h1:O37Iogk1lEkMRXewVtZ1BBTVn5JEp8GrJvP92bJqC6o= go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.10.0/go.mod h1:zG20xCK0szZ1xdokeSOwEcmlXu+x9kkdRe6N1DhKcfU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -424,13 +408,10 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -469,7 +450,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -508,11 +488,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -541,8 +518,8 @@ golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 h1:VnGaRqoLmqZH/3TMLJwYCEWkR4j1nuIU1U9TvbqsDUw= -golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c h1:q3gFqPqH7NVofKo3c3yETAP//pPI+G5mvB7qqj1Y5kY= +golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -557,7 +534,6 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -592,7 +568,6 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -611,11 +586,9 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -626,9 +599,7 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d h1:Zu/JngovGLVi6t2J3nmAf3AoTDwuzw85YZ3b9o4yU7s= golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -645,7 +616,6 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -695,7 +665,6 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -706,7 +675,6 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717 h1:hI3jKY4Hpf63ns040onEbB3dAkR/H/P83hw1TG8dD3Y= -golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -825,7 +793,6 @@ google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= @@ -869,9 +836,6 @@ google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= @@ -924,27 +888,20 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.22.11/go.mod h1:l2IQ0P1TtTvSeWnjqTrFQ7sX5LR1H9a9Knb0N2ILJKE= k8s.io/api v0.24.3 h1:tt55QEmKd6L2k5DP6G/ZzdMQKvG5ro4H4teClqm0sTY= k8s.io/api v0.24.3/go.mod h1:elGR/XSZrS7z7cSZPzVWaycpJuGIw57j9b95/1PdJNI= -k8s.io/apimachinery v0.22.11/go.mod h1:ZvVLP5iLhwVFg2Yx9Gh5W0um0DUauExbRhe+2Z8I1EU= k8s.io/apimachinery v0.24.3 h1:hrFiNSA2cBZqllakVYyH/VyEh4B581bQRmqATJSeQTg= k8s.io/apimachinery v0.24.3/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= -k8s.io/client-go v0.22.11/go.mod h1:zNje4oH4oU3DchJmlmU71VeOgPxiJ+r/Rh8VRq7Jq6E= k8s.io/client-go v0.24.3 h1:Nl1840+6p4JqkFWEW2LnMKU667BUxw03REfLAVhuKQY= k8s.io/client-go v0.24.3/go.mod h1:AAovolf5Z9bY1wIg2FZ8LPQlEdKHjLI7ZD4rw920BJw= -k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc= k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 h1:Gii5eqf+GmIEwGNKQYQClCayuJCe2/4fZUvF7VG99sU= k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc= k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/pkg/config/fake/reader_mock.go b/pkg/config/fake/reader_mock.go index a6ab2310..987f71ac 100644 --- a/pkg/config/fake/reader_mock.go +++ b/pkg/config/fake/reader_mock.go @@ -33,6 +33,21 @@ func (m *MockKeptnResourceService) EXPECT() *MockKeptnResourceServiceMockRecorde return m.recorder } +// GetAllKeptnResources mocks base method. +func (m *MockKeptnResourceService) GetAllKeptnResources(arg0 string) (map[string][]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAllKeptnResources", arg0) + ret0, _ := ret[0].(map[string][]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAllKeptnResources indicates an expected call of GetAllKeptnResources. +func (mr *MockKeptnResourceServiceMockRecorder) GetAllKeptnResources(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllKeptnResources", reflect.TypeOf((*MockKeptnResourceService)(nil).GetAllKeptnResources), arg0) +} + // GetProjectResource mocks base method. func (m *MockKeptnResourceService) GetProjectResource(arg0, arg1 string) ([]byte, error) { m.ctrl.T.Helper() diff --git a/pkg/config/reader.go b/pkg/config/reader.go index a9d49c4e..08f5633c 100644 --- a/pkg/config/reader.go +++ b/pkg/config/reader.go @@ -6,6 +6,7 @@ import ( "log" ) +// Needs to be escaped manually when sending it to the api-gateway-nginx const jobConfigResourceName = "job/config.yaml" //go:generate mockgen -destination=fake/reader_mock.go -package=fake . KeptnResourceService @@ -21,6 +22,9 @@ type KeptnResourceService interface { // GetStageResource returns the resource that was defined in the stage GetStageResource(resource string, gitCommitID string) ([]byte, error) + + // GetAllKeptnResources returns all resources that were defined in the stage + GetAllKeptnResources(resource string) (map[string][]byte, error) } // JobConfigReader retrieves and parses job configuration from Keptn diff --git a/pkg/eventhandler/eventhandlers.go b/pkg/eventhandler/eventhandlers.go index e1a05a74..6e3b7cde 100644 --- a/pkg/eventhandler/eventhandlers.go +++ b/pkg/eventhandler/eventhandlers.go @@ -1,8 +1,9 @@ package eventhandler import ( - "errors" "fmt" + "github.com/keptn/go-utils/pkg/sdk" + keptn_interface "keptn-contrib/job-executor-service/pkg/keptn" "log" "strconv" "strings" @@ -33,7 +34,7 @@ type ImageFilter interface { // parsed JSON of the event data type EventMapper interface { // Map transforms a cloud event into a generic map[string]interface{} - Map(cloudevents.Event) (map[string]interface{}, error) + Map(event sdk.KeptnEvent) (map[string]interface{}, error) } // JobConfigReader retrieves the job-executor-service configuration @@ -62,7 +63,6 @@ type K8s interface { // EventHandler contains all information needed to process an event type EventHandler struct { - Keptn *keptnv2.Keptn ServiceName string JobConfigReader JobConfigReader JobSettings k8sutils.JobSettings @@ -82,20 +82,19 @@ type dataForFinishedEvent struct { end time.Time } -// HandleEvent handles all events in a generic manner -func (eh *EventHandler) HandleEvent() error { - - eventAsInterface, err := eh.Mapper.Map(*eh.Keptn.CloudEvent) +// Execute handles all events in a generic manner +func (eh *EventHandler) Execute(k sdk.IKeptn, event sdk.KeptnEvent) (interface{}, *sdk.Error) { + eventAsInterface, err := eh.Mapper.Map(event) if err != nil { log.Printf("failed to convert incoming cloudevent: %v", err) - return err + return nil, &sdk.Error{Err: err, StatusType: keptnv2.StatusErrored, ResultType: keptnv2.ResultFailed, Message: "failed to convert incoming cloudevent: " + err.Error()} } - log.Printf( - "Attempting to handle event %s of type %s ...", eh.Keptn.CloudEvent.Context.GetID(), - eh.Keptn.CloudEvent.Type(), + k.Logger().Infof( + "Attempting to handle event %s of type %s ...", event.ID, + *event.Type, ) - log.Printf("CloudEvent %T: %v", eventAsInterface, eventAsInterface) + k.Logger().Infof("CloudEvent %T: %v", eventAsInterface, eventAsInterface) // Get the git commit id from the cloud event (if it exists) and use it to query the job configuration var gitCommitID string @@ -103,69 +102,58 @@ func (eh *EventHandler) HandleEvent() error { gitCommitID, _ = commitId.(string) } - configuration, configHash, err := eh.JobConfigReader.GetJobConfig(gitCommitID) - - if err != nil { - errorLogErr := eh.ErrorSender.SendErrorLogEvent( - eh.Keptn.CloudEvent, fmt.Errorf( - "could not retrieve config for job-executor-service: %w", err, - ), - ) + data := &keptnv2.EventData{} + if err := keptnv2.Decode(event.Data, data); err != nil { + k.Logger().Errorf("Could not parse event: %s", err.Error()) + return nil, &sdk.Error{Err: err, StatusType: keptnv2.StatusErrored, ResultType: keptnv2.ResultFailed, Message: fmt.Sprintf("Could not parse event: %s", err.Error())} + } - if errorLogErr != nil { - log.Printf( - "Failed sending error log for keptn context %s: %v. Initial error: %v", eh.Keptn.KeptnContext, - errorLogErr, err, - ) + var jobConfigReader JobConfigReader + if eh.JobConfigReader == nil { + jobConfigReader = &config.JobConfigReader{ + Keptn: keptn_interface.NewV1ResourceHandler(*data, k.APIV2().Resources()), } - - return err + } else { + // Used to pass a mock in the unit tests + jobConfigReader = eh.JobConfigReader } - // Check if we have an action that we can use, if it isn't the case we produce a log output - hasMatchingEvent := configuration.IsEventMatch(eh.Keptn.CloudEvent.Type(), eventAsInterface) - if !hasMatchingEvent { - log.Printf( - "No match found for event %s of type %s. Skipping...", eh.Keptn.CloudEvent.Context.GetID(), - eh.Keptn.CloudEvent.Type(), - ) - return nil + configuration, configHash, err := jobConfigReader.GetJobConfig(gitCommitID) + if err != nil { + return nil, &sdk.Error{Err: err, StatusType: keptnv2.StatusErrored, ResultType: keptnv2.ResultFailed, Message: "could not retrieve config for job-executor-service: " + err.Error()} } // For each action that matches the given event type we execute all containing tasks: for actionIndex, action := range configuration.Actions { - if action.IsEventMatch(eh.Keptn.CloudEvent.Type(), eventAsInterface) { + if action.IsEventMatch(*event.Type, eventAsInterface) { log.Printf( - "Match found for event %s of type %s. Starting k8s job to run action '%s'", eh.Keptn.CloudEvent.Context.GetID(), - eh.Keptn.CloudEvent.Type(), action.Name, + "Match found for event %s of type %s. Starting k8s job to run action '%s'", event.ID, + *event.Type, action.Name, ) - eh.startK8sJob(&action, actionIndex, configHash, gitCommitID, eventAsInterface) + finishedEvent, err := eh.startK8sJob(k, event, data, &action, actionIndex, configHash, gitCommitID, eventAsInterface) + if err != nil { + return nil, err + } else if finishedEvent != nil { + return finishedEvent, nil + } } } - return nil + k.Logger().Info("Returning empty response") + return nil, nil } -func (eh *EventHandler) startK8sJob(action *config.Action, actionIndex int, configHash string, gitCommitID string, +func (eh *EventHandler) startK8sJob(k sdk.IKeptn, event sdk.KeptnEvent, eventData keptn.EventProperties, action *config.Action, actionIndex int, configHash string, gitCommitID string, jsonEventData interface{}, -) { - - if !action.Silent { - _, err := eh.Keptn.SendTaskStartedEvent(nil, eh.ServiceName) - if err != nil { - log.Printf("Error while sending started event: %s\n", err.Error()) - return - } - } - +) (interface{}, *sdk.Error) { err := eh.K8s.ConnectToCluster() if err != nil { - log.Printf("Error while connecting to cluster: %s\n", err.Error()) + k.Logger().Infof("Error while connecting to k8s cluster: %e", err) if !action.Silent { - sendJobFailedEvent(eh.Keptn, "", eh.ServiceName, err) + return nil, &sdk.Error{Err: err, StatusType: keptnv2.StatusErrored, ResultType: keptnv2.ResultFailed, Message: fmt.Sprintf("Error while connecting to cluster: %s", err.Error())} } - return + return nil, nil } var allJobLogs []jobLogs @@ -179,21 +167,21 @@ func (eh *EventHandler) startK8sJob(action *config.Action, actionIndex int, conf if !eh.ImageFilter.IsImageAllowed(task.Image) { errorText := fmt.Sprintf("Forbidden: Image %s does not match configured image allowlist.\n", task.Image) - log.Printf(errorText) + k.Logger().Infof(errorText) if !action.Silent { - sendTaskFailedEvent(eh.Keptn, task.Name, eh.ServiceName, errors.New(errorText), "") + return nil, &sdk.Error{Err: err, StatusType: keptnv2.StatusErrored, ResultType: keptnv2.ResultFailed, Message: errorText} } - return + return nil, nil } } for index, task := range action.Tasks { - log.Printf("Starting task %s/%s: '%s' ...", strconv.Itoa(index+1), strconv.Itoa(len(action.Tasks)), task.Name) + k.Logger().Infof("Starting task %s/%s: '%s' ...", strconv.Itoa(index+1), strconv.Itoa(len(action.Tasks)), task.Name) // k8s job name max length is 63 characters, with the naming scheme below up to 999 tasks per action are supported // the naming scheme is also unique if multiple actions in one cloud event are executed - jobName := fmt.Sprintf("job-executor-service-job-%s-%03d-%03d", eh.Keptn.CloudEvent.ID()[:24], actionIndex, index+1) + jobName := fmt.Sprintf("job-executor-service-job-%s-%03d-%03d", event.ID[:24], actionIndex, index+1) namespace := eh.JobSettings.JobNamespace @@ -211,15 +199,14 @@ func (eh *EventHandler) startK8sJob(action *config.Action, actionIndex int, conf } err = eh.K8s.CreateK8sJob( - jobName, jobDetails, eh.Keptn.Event, eh.JobSettings, jsonEventData, namespace, + jobName, jobDetails, eventData, eh.JobSettings, jsonEventData, namespace, ) if err != nil { - log.Printf("Error while creating job: %s\n", err) + k.Logger().Infof("Error while creating job: %s\n", err) if !action.Silent { - sendTaskFailedEvent(eh.Keptn, task.Name, eh.ServiceName, err, "") + return nil, &sdk.Error{Err: err, StatusType: keptnv2.StatusErrored, ResultType: keptnv2.ResultFailed, Message: fmt.Sprintf("Error while creating job: %s", err)} } - return } maxPollDuration := defaultMaxPollDuration @@ -230,25 +217,25 @@ func (eh *EventHandler) startK8sJob(action *config.Action, actionIndex int, conf logs, err := eh.K8s.GetLogsOfPod(jobName, namespace) if err != nil { - log.Printf("Error while retrieving logs: %s\n", err.Error()) + k.Logger().Infof("Error while retrieving logs: %s\n", err.Error()) } if jobErr != nil { - log.Printf("Error while creating job: %s\n", jobErr.Error()) + k.Logger().Infof("Error while creating job: %s\n", jobErr.Error()) erroredEventMessages, eventErr := eh.K8s.GetFailedEventsForJob(jobName, namespace) if eventErr != nil { - log.Printf("Error while retrieving events: %s\n", eventErr.Error()) + k.Logger().Infof("Error while retrieving events: %s\n", eventErr.Error()) } else if erroredEventMessages != "" { // Found some failed events for this job - appending them to logs logs = logs + "\n" + erroredEventMessages } if !action.Silent { - sendTaskFailedEvent(eh.Keptn, task.Name, eh.ServiceName, jobErr, logs) + return nil, &sdk.Error{Err: err, StatusType: keptnv2.StatusErrored, ResultType: keptnv2.ResultFailed, Message: fmt.Sprintf("Error while creating job: %s", jobErr.Error())} } - return + return nil, nil } allJobLogs = append( @@ -261,11 +248,14 @@ func (eh *EventHandler) startK8sJob(action *config.Action, actionIndex int, conf additionalFinishedEventData.end = time.Now() - log.Printf("Successfully finished processing of event: %s\n", eh.Keptn.CloudEvent.ID()) + k.Logger().Infof("Successfully finished processing of event: %s\n", event.ID) if !action.Silent { - sendTaskFinishedEvent(eh.Keptn, eh.ServiceName, allJobLogs, additionalFinishedEventData) + k.Logger().Infof("Getting task finished event") + return getTaskFinishedEvent(event, eventData, allJobLogs, additionalFinishedEventData), nil } + + return nil, nil } func sendTaskFailedEvent(myKeptn *keptnv2.Keptn, taskName string, serviceName string, err error, logs string) { @@ -304,7 +294,8 @@ func sendJobFailedEvent(myKeptn *keptnv2.Keptn, jobName string, serviceName stri } } -func sendTaskFinishedEvent(myKeptn *keptnv2.Keptn, serviceName string, jobLogs []jobLogs, data dataForFinishedEvent) { +// getTaskFinishedEvent returns the finished data for the received event as an interface which can be directly returned using the go-sdk +func getTaskFinishedEvent(event sdk.KeptnEvent, receivedEventData keptn.EventProperties, jobLogs []jobLogs, data dataForFinishedEvent) interface{} { var logMessage strings.Builder for _, jobLogs := range jobLogs { @@ -317,26 +308,21 @@ func sendTaskFinishedEvent(myKeptn *keptnv2.Keptn, serviceName string, jobLogs [ Status: keptnv2.StatusSucceeded, Result: keptnv2.ResultPass, Message: logMessage.String(), + Project: receivedEventData.GetProject(), + Stage: receivedEventData.GetStage(), + Service: receivedEventData.GetService(), } - var err error - - if isTestTriggeredEvent(myKeptn.CloudEvent.Type()) && !data.start.IsZero() && !data.end.IsZero() { - event := &keptnv2.TestFinishedEventData{ + if isTestTriggeredEvent(*event.Type) && !data.start.IsZero() && !data.end.IsZero() { + return keptnv2.TestFinishedEventData{ Test: keptnv2.TestFinishedDetails{ Start: data.start.Format(time.RFC3339), End: data.end.Format(time.RFC3339), }, EventData: *eventData, } - _, err = myKeptn.SendTaskFinishedEvent(event, serviceName) } else { - _, err = myKeptn.SendTaskFinishedEvent(eventData, serviceName) - } - - if err != nil { - log.Printf("Error while sending finished event: %s\n", err.Error()) - return + return eventData } } diff --git a/pkg/eventhandler/eventhandlers_test.go b/pkg/eventhandler/eventhandlers_test.go index 4ac9c5e8..43097968 100644 --- a/pkg/eventhandler/eventhandlers_test.go +++ b/pkg/eventhandler/eventhandlers_test.go @@ -4,24 +4,24 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" - "reflect" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - cloudevents "github.com/cloudevents/sdk-go/v2" "github.com/golang/mock/gomock" + "github.com/keptn/go-utils/pkg/api/models" + keptnapi "github.com/keptn/go-utils/pkg/api/models" "github.com/keptn/go-utils/pkg/lib/keptn" keptnv2 "github.com/keptn/go-utils/pkg/lib/v0_2_0" keptnfake "github.com/keptn/go-utils/pkg/lib/v0_2_0/fake" - + "github.com/keptn/go-utils/pkg/sdk" + "github.com/stretchr/testify/require" + "io/ioutil" "keptn-contrib/job-executor-service/pkg/config" - "keptn-contrib/job-executor-service/pkg/k8sutils" - eventhandlerfake "keptn-contrib/job-executor-service/pkg/eventhandler/fake" + "keptn-contrib/job-executor-service/pkg/k8sutils" + "log" + "reflect" + "strings" + "testing" + "time" ) const testEvent = ` @@ -85,12 +85,22 @@ func initializeTestObjects(eventFileName string) (*keptnv2.Keptn, *cloudevents.E var keptnOptions = keptn.KeptnOpts{ EventSender: fakeEventSender, } - keptnOptions.UseLocalFileSystem = true myKeptn, err := keptnv2.NewKeptn(incomingEvent, keptnOptions) return myKeptn, incomingEvent, fakeEventSender, err } +func newEvent(filename string) keptnapi.KeptnContextExtendedCE { + content, err := ioutil.ReadFile(filename) + if err != nil { + log.Fatal(err) + } + event := keptnapi.KeptnContextExtendedCE{} + err = json.Unmarshal(content, &event) + _ = err + return event +} + func TestErrorMappingEvent(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -106,12 +116,7 @@ func TestErrorMappingEvent(t *testing.T) { mappingError, ) - myKeptn, _, _, err := initializeTestObjects("../../test/events/action.triggered.json") - - require.NoError(t, err) - sut := EventHandler{ - Keptn: myKeptn, JobConfigReader: mockJobConfigReader, ServiceName: "test-jes", JobSettings: k8sutils.JobSettings{}, @@ -119,9 +124,20 @@ func TestErrorMappingEvent(t *testing.T) { Mapper: mockMapper, ErrorSender: mockUniformErrorSender, } - err = sut.HandleEvent() - assert.Error(t, err) - assert.ErrorIs(t, err, mappingError) + fakeKeptn := sdk.NewFakeKeptn("test-job-executor-service") + fakeKeptn.AddTaskHandler("*", &sut) + + err := fakeKeptn.NewEvent(newEvent("../../test/events/action.triggered.json")) + + require.NoError(t, err) + + fakeKeptn.AssertSentEventStatus(t, 1, keptnv2.StatusErrored) + fakeKeptn.AssertSentEventResult(t, 1, keptnv2.ResultFailed) + fakeKeptn.AssertSentEvent(t, 1, func(ce models.KeptnContextExtendedCE) bool { + getActionFinishedData := keptnv2.GetActionFinishedEventData{} + ce.DataAs(&getActionFinishedData) + return strings.Contains(getActionFinishedData.Message, mappingError.Error()) + }) } type matcherErrorIs struct { @@ -151,21 +167,13 @@ func TestErrorGettingJobConfig(t *testing.T) { mockUniformErrorSender := eventhandlerfake.NewMockErrorLogSender(mockCtrl) errorGettingJobConfig := errors.New("error getting resource") + mockJobConfigReader.EXPECT().GetJobConfig("").Return( nil, "", errorGettingJobConfig, ).Times(1) - myKeptn, _, fakeEventSender, err := initializeTestObjects("../../test/events/action.triggered.json") - require.NoError(t, err) - - mockUniformErrorSender.EXPECT().SendErrorLogEvent( - myKeptn.CloudEvent, - &matcherErrorIs{targetErr: errorGettingJobConfig}, - ).Times(1) - sut := EventHandler{ - Keptn: myKeptn, JobConfigReader: mockJobConfigReader, ServiceName: "", JobSettings: k8sutils.JobSettings{}, @@ -174,9 +182,21 @@ func TestErrorGettingJobConfig(t *testing.T) { ErrorSender: mockUniformErrorSender, } - err = sut.HandleEvent() - assert.ErrorIs(t, err, errorGettingJobConfig) - assert.NoError(t, fakeEventSender.AssertSentEventTypes([]string{})) + fakeKeptn := sdk.NewFakeKeptn("test-job-executor-service") + fakeKeptn.AddTaskHandler("*", &sut) + + err := fakeKeptn.NewEvent(newEvent("../../test/events/action.triggered.json")) + + require.NoError(t, err) + + fakeKeptn.AssertSentEventType(t, 1, "sh.keptn.event.action.finished") + fakeKeptn.AssertSentEventStatus(t, 1, keptnv2.StatusErrored) + fakeKeptn.AssertSentEventResult(t, 1, keptnv2.ResultFailed) + fakeKeptn.AssertSentEvent(t, 1, func(ce models.KeptnContextExtendedCE) bool { + getActionFinishedData := keptnv2.GetActionFinishedEventData{} + ce.DataAs(&getActionFinishedData) + return strings.Contains(getActionFinishedData.Message, errorGettingJobConfig.Error()) + }) } func TestErrorConnectingToK8s(t *testing.T) { @@ -242,11 +262,7 @@ func TestErrorConnectingToK8s(t *testing.T) { connectionError := errors.New("error connecting to k8s cluster") mockK8s.EXPECT().ConnectToCluster().Return(connectionError).Times(1) - myKeptn, _, mockEventSender, err := initializeTestObjects("../../test/events/action.triggered.json") - require.NoError(t, err) - sut := EventHandler{ - Keptn: myKeptn, JobConfigReader: mockJobConfigReader, ServiceName: "test-jes", JobSettings: k8sutils.JobSettings{}, @@ -256,15 +272,16 @@ func TestErrorConnectingToK8s(t *testing.T) { ErrorSender: mockUniformErrorSender, } - err = sut.HandleEvent() + fakeKeptn := sdk.NewFakeKeptn("test-job-executor-service") + fakeKeptn.AddTaskHandler("*", &sut) + + err := fakeKeptn.NewEvent(newEvent("../../test/events/action.triggered.json")) + require.NoError(t, err) // TODO: weird that if connection to k8s fails we don't send back an error from the handling function - assert.NoError(t, err) - assert.NoError( - t, mockEventSender.AssertSentEventTypes( - test.expectedEventTypes, - ), - ) + for i, eventType := range test.expectedEventTypes { + fakeKeptn.AssertSentEventType(t, i, eventType) + } }, ) } @@ -389,10 +406,6 @@ func TestEventMatching(t *testing.T) { mockUniformErrorSender := eventhandlerfake.NewMockErrorLogSender(mockCtrl) - myKeptn, _, mockEventSender, err := initializeTestObjects(test.inputs.eventFile) - - require.NoError(t, err) - totalNoOfExpectedTasks := 0 for _, invocation := range test.expected.jobsInvocations { for range invocation.taskNames { @@ -405,7 +418,7 @@ func TestEventMatching(t *testing.T) { TaskIndex: 0, JobConfigHash: "", }), - gomock.Eq(myKeptn.Event), + gomock.Any(), gomock.Eq(k8sutils.JobSettings{}), gomock.Any(), gomock.Eq(""), @@ -429,45 +442,36 @@ func TestEventMatching(t *testing.T) { ).Times(totalNoOfExpectedTasks) sut := EventHandler{ - Keptn: myKeptn, JobConfigReader: mockJobConfigReader, - ServiceName: "test-jes", + ServiceName: "", JobSettings: k8sutils.JobSettings{}, ImageFilter: mockFilter, Mapper: new(KeptnCloudEventMapper), - K8s: mockK8s, ErrorSender: mockUniformErrorSender, + K8s: mockK8s, } - err = sut.HandleEvent() - assert.NoError(t, err) - assert.NoError(t, mockEventSender.AssertSentEventTypes(test.expected.events)) + fakeKeptn := sdk.NewFakeKeptn("test-job-executor-service") + fakeKeptn.AddTaskHandler("*", &sut) + + err := fakeKeptn.NewEvent(newEvent(test.inputs.eventFile)) + require.NoError(t, err) + + for index, event := range test.expected.events { + fakeKeptn.AssertSentEventType(t, index, event) + } }, ) } } func TestStartK8s(t *testing.T) { - jobNamespace1 := "keptn" - jobNamespace2 := "keptn-2" - myKeptn, _, fakeEventSender, err := initializeTestObjects("../../test/events/action.triggered.json") - require.NoError(t, err) - k8sMock := createK8sMock(t) - - eventData := &keptnv2.EventData{} - myKeptn.CloudEvent.DataAs(eventData) - eh := EventHandler{ - ServiceName: "job-executor-service", - Keptn: myKeptn, - ImageFilter: acceptAllImagesFilter{}, - JobSettings: k8sutils.JobSettings{ - JobNamespace: jobNamespace1, - }, - K8s: k8sMock, - } - mapper := new(KeptnCloudEventMapper) - eventPayloadAsInterface, err := mapper.Map(*eh.Keptn.CloudEvent) + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + mockFilter := eventhandlerfake.NewMockImageFilter(mockCtrl) + mockJobConfigReader := eventhandlerfake.NewMockJobConfigReader(mockCtrl) + mockUniformErrorSender := eventhandlerfake.NewMockErrorLogSender(mockCtrl) maxPollDuration := 1006 action := config.Action{ @@ -479,11 +483,33 @@ func TestStartK8s(t *testing.T) { }, { Name: "Run locust healthy snack tests", - Namespace: jobNamespace2, + Namespace: "keptn2", + }, + }, + Events: []config.Event{ + { + Name: "sh.keptn.event.action.triggered", }, }, } + mockJobConfigReader.EXPECT().GetJobConfig("").Return( + &config.Config{ + Actions: []config.Action{action}, + }, "", nil, + ).Times(1) + + eh := EventHandler{ + JobConfigReader: mockJobConfigReader, + ServiceName: "test-jes", + JobSettings: k8sutils.JobSettings{}, + ImageFilter: mockFilter, + Mapper: new(KeptnCloudEventMapper), + K8s: k8sMock, + ErrorSender: mockUniformErrorSender, + } + + mockFilter.EXPECT().IsImageAllowed(gomock.Any()).Return(true).MinTimes(1) k8sMock.EXPECT().ConnectToCluster().Times(1) k8sMock.EXPECT().CreateK8sJob( gomock.Eq(jobName1), gomock.Eq(k8sutils.JobDetails{ @@ -493,7 +519,7 @@ func TestStartK8s(t *testing.T) { TaskIndex: 0, JobConfigHash: "", }), gomock.Any(), gomock.Any(), - gomock.Any(), jobNamespace1, + gomock.Any(), gomock.Any(), ).Times(1) k8sMock.EXPECT().CreateK8sJob( gomock.Eq(jobName2), gomock.Eq(k8sutils.JobDetails{ @@ -503,39 +529,40 @@ func TestStartK8s(t *testing.T) { TaskIndex: 1, JobConfigHash: "", }), gomock.Any(), gomock.Any(), - gomock.Any(), jobNamespace2, + gomock.Any(), gomock.Any(), ).Times(1) - k8sMock.EXPECT().AwaitK8sJobDone(gomock.Eq(jobName1), 1006*time.Second, pollInterval, jobNamespace1).Times(1) - k8sMock.EXPECT().AwaitK8sJobDone(gomock.Eq(jobName2), defaultMaxPollDuration, pollInterval, jobNamespace2).Times(1) - k8sMock.EXPECT().GetLogsOfPod(gomock.Eq(jobName1), jobNamespace1).Times(1) - k8sMock.EXPECT().GetLogsOfPod(gomock.Eq(jobName2), jobNamespace2).Times(1) + k8sMock.EXPECT().AwaitK8sJobDone(gomock.Eq(jobName1), 1006*time.Second, pollInterval, + gomock.Any()).Times(1) + k8sMock.EXPECT().AwaitK8sJobDone(gomock.Eq(jobName2), defaultMaxPollDuration, pollInterval, gomock.Any()).Times(1) + k8sMock.EXPECT().GetLogsOfPod(gomock.Eq(jobName1), gomock.Any()).Times(1) + k8sMock.EXPECT().GetLogsOfPod(gomock.Eq(jobName2), gomock.Any()).Times(1) - eh.startK8sJob(&action, 0, "", "", eventPayloadAsInterface) + fakeKeptn := sdk.NewFakeKeptn("test-job-executor-service") + fakeKeptn.AddTaskHandler("*", &eh) - err = fakeEventSender.AssertSentEventTypes( - []string{ - "sh.keptn.event.action.started", "sh.keptn.event.action.finished", - }, - ) - assert.NoError(t, err) + err := fakeKeptn.NewEvent(newEvent("../../test/events/action.triggered.json")) + require.NoError(t, err) + + fakeKeptn.AssertSentEventType(t, 0, "sh.keptn.event.action.started") + fakeKeptn.AssertSentEventType(t, 1, "sh.keptn.event.action.finished") } func TestStartK8sJobSilent(t *testing.T) { - myKeptn, _, fakeEventSender, err := initializeTestObjects("../../test/events/action.triggered.json") - require.NoError(t, err) - k8sMock := createK8sMock(t) + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + mockJobConfigReader := eventhandlerfake.NewMockJobConfigReader(mockCtrl) + mockUniformErrorSender := eventhandlerfake.NewMockErrorLogSender(mockCtrl) - eventData := &keptnv2.EventData{} - myKeptn.CloudEvent.DataAs(eventData) eh := EventHandler{ - ServiceName: "job-executor-service", - Keptn: myKeptn, - ImageFilter: acceptAllImagesFilter{}, - K8s: k8sMock, + ServiceName: "job-executor-service", + ImageFilter: acceptAllImagesFilter{}, + JobConfigReader: mockJobConfigReader, + Mapper: new(KeptnCloudEventMapper), + K8s: k8sMock, + ErrorSender: mockUniformErrorSender, + JobSettings: k8sutils.JobSettings{}, } - mapper := new(KeptnCloudEventMapper) - eventPayloadAsInterface, err := mapper.Map(*eh.Keptn.CloudEvent) action := config.Action{ Name: "Run locust", @@ -547,9 +574,20 @@ func TestStartK8sJobSilent(t *testing.T) { Name: "Run locust healthy snack tests", }, }, + Events: []config.Event{ + { + Name: "sh.keptn.event.action.triggered", + }, + }, Silent: true, } + mockJobConfigReader.EXPECT().GetJobConfig("").Return( + &config.Config{ + Actions: []config.Action{action}, + }, "", nil, + ).Times(1) + k8sMock.EXPECT().ConnectToCluster().Times(1) k8sMock.EXPECT().CreateK8sJob( gomock.Eq(jobName1), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), @@ -561,28 +599,32 @@ func TestStartK8sJobSilent(t *testing.T) { k8sMock.EXPECT().GetLogsOfPod(gomock.Eq(jobName1), gomock.Any()).Times(1) k8sMock.EXPECT().GetLogsOfPod(gomock.Eq(jobName2), gomock.Any()).Times(1) - eh.startK8sJob(&action, 0, "", "", eventPayloadAsInterface) + fakeKeptn := sdk.NewFakeKeptn("test-job-executor-service") + fakeKeptn.AddTaskHandler("*", &eh) - err = fakeEventSender.AssertSentEventTypes([]string{}) - assert.NoError(t, err) + err := fakeKeptn.NewEvent(newEvent("../../test/events/action.triggered.json")) + require.NoError(t, err) + + // Only one event means the finished event was skipped + fakeKeptn.AssertNumberOfEventSent(t, 1) } func TestStartK8s_TestFinishedEvent(t *testing.T) { - myKeptn, _, fakeEventSender, err := initializeTestObjects("../../test/events/test.triggered.json") - require.NoError(t, err) - k8sMock := createK8sMock(t) + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + mockJobConfigReader := eventhandlerfake.NewMockJobConfigReader(mockCtrl) + mockUniformErrorSender := eventhandlerfake.NewMockErrorLogSender(mockCtrl) - eventData := &keptnv2.EventData{} - myKeptn.CloudEvent.DataAs(eventData) eh := EventHandler{ - ServiceName: "job-executor-service", - Keptn: myKeptn, - ImageFilter: acceptAllImagesFilter{}, - K8s: k8sMock, + ServiceName: "job-executor-service", + ImageFilter: acceptAllImagesFilter{}, + JobConfigReader: mockJobConfigReader, + Mapper: new(KeptnCloudEventMapper), + K8s: k8sMock, + ErrorSender: mockUniformErrorSender, + JobSettings: k8sutils.JobSettings{}, } - mapper := new(KeptnCloudEventMapper) - eventPayloadAsInterface, err := mapper.Map(*eh.Keptn.CloudEvent) action := config.Action{ Name: "Run locust", @@ -591,8 +633,19 @@ func TestStartK8s_TestFinishedEvent(t *testing.T) { Name: "Run locust healthy snack tests", }, }, + Events: []config.Event{ + { + Name: "sh.keptn.event.test.triggered", + }, + }, } + mockJobConfigReader.EXPECT().GetJobConfig("").Return( + &config.Config{ + Actions: []config.Action{action}, + }, "", nil, + ).Times(1) + k8sMock.EXPECT().ConnectToCluster().Times(1) k8sMock.EXPECT().CreateK8sJob( gomock.Eq(jobName1), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), @@ -605,28 +658,27 @@ func TestStartK8s_TestFinishedEvent(t *testing.T) { require.NoError(t, err) time.Local = local - eh.startK8sJob(&action, 0, "", "", eventPayloadAsInterface) + fakeKeptn := sdk.NewFakeKeptn("test-job-executor-service") + fakeKeptn.AddTaskHandler("*", &eh) - err = fakeEventSender.AssertSentEventTypes( - []string{ - keptnv2.GetStartedEventType(keptnv2.TestTaskName), - keptnv2.GetFinishedEventType(keptnv2.TestTaskName), - }, - ) + err = fakeKeptn.NewEvent(newEvent("../../test/events/test.triggered.json")) require.NoError(t, err) - for _, cloudEvent := range fakeEventSender.SentEvents { - if cloudEvent.Type() == keptnv2.GetFinishedEventType(keptnv2.TestTaskName) { - eventData := &keptnv2.TestFinishedEventData{} - cloudEvent.DataAs(eventData) - - dateLayout := "2006-01-02T15:04:05Z" - _, err := time.Parse(dateLayout, eventData.Test.Start) - assert.NoError(t, err) - _, err = time.Parse(dateLayout, eventData.Test.End) - assert.NoError(t, err) - } + fakeKeptn.AssertSentEventType(t, 0, keptnv2.GetStartedEventType(keptnv2.TestTaskName)) + fakeKeptn.AssertSentEventType(t, 1, keptnv2.GetFinishedEventType(keptnv2.TestTaskName)) + + fakeKeptn.AssertSentEvent(t, 0, checkFinishedEvent) + fakeKeptn.AssertSentEvent(t, 1, checkFinishedEvent) +} + +func checkFinishedEvent(ce models.KeptnContextExtendedCE) bool { + eventData := &keptnv2.TestFinishedEventData{} + err := ce.DataAs(eventData) + if err != nil { + return false } + + return eventData.Status == keptnv2.StatusSucceeded } type disallowAllImagesFilter struct { @@ -638,21 +690,21 @@ func (f disallowAllImagesFilter) IsImageAllowed(_ string) bool { } func TestExpectImageNotAllowedError(t *testing.T) { - myKeptn, _, fakeEventSender, err := initializeTestObjects("../../test/events/test.triggered.json") - require.NoError(t, err) - k8sMock := createK8sMock(t) + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + mockJobConfigReader := eventhandlerfake.NewMockJobConfigReader(mockCtrl) + mockUniformErrorSender := eventhandlerfake.NewMockErrorLogSender(mockCtrl) - eventData := &keptnv2.EventData{} - myKeptn.CloudEvent.DataAs(eventData) eh := EventHandler{ - ServiceName: "job-executor-service", - Keptn: myKeptn, - ImageFilter: disallowAllImagesFilter{}, - K8s: k8sMock, + ServiceName: "job-executor-service", + ImageFilter: acceptAllImagesFilter{}, + JobConfigReader: mockJobConfigReader, + Mapper: new(KeptnCloudEventMapper), + K8s: k8sMock, + ErrorSender: mockUniformErrorSender, + JobSettings: k8sutils.JobSettings{}, } - mapper := new(KeptnCloudEventMapper) - eventPayloadAsInterface, err := mapper.Map(*eh.Keptn.CloudEvent) notAllowedImageName := "alpine:latest" action := config.Action{ @@ -663,8 +715,19 @@ func TestExpectImageNotAllowedError(t *testing.T) { Name: "Run some image", }, }, + Events: []config.Event{ + { + Name: "sh.keptn.event.test.triggered", + }, + }, } + mockJobConfigReader.EXPECT().GetJobConfig("").Return( + &config.Config{ + Actions: []config.Action{action}, + }, "", nil, + ).Times(1) + k8sMock.EXPECT().ConnectToCluster().Times(1) k8sMock.EXPECT().CreateK8sJob( gomock.Eq(jobName1), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), @@ -677,24 +740,30 @@ func TestExpectImageNotAllowedError(t *testing.T) { require.NoError(t, err) time.Local = local - eh.startK8sJob(&action, 0, "", "", eventPayloadAsInterface) + fakeKeptn := sdk.NewFakeKeptn("test-job-executor-service") + fakeKeptn.AddTaskHandler("*", &eh) - err = fakeEventSender.AssertSentEventTypes( - []string{ - keptnv2.GetStartedEventType(keptnv2.TestTaskName), - keptnv2.GetFinishedEventType(keptnv2.TestTaskName), - }, - ) + err = fakeKeptn.NewEvent(newEvent("../../test/events/test.triggered.json")) require.NoError(t, err) - for _, cloudEvent := range fakeEventSender.SentEvents { - if cloudEvent.Type() == keptnv2.GetFinishedEventType(keptnv2.TestTaskName) { - eventData := &keptnv2.TestFinishedEventData{} - cloudEvent.DataAs(eventData) + fakeKeptn.AssertSentEventType(t, 0, keptnv2.GetStartedEventType(keptnv2.TestTaskName)) + fakeKeptn.AssertSentEventType(t, 1, keptnv2.GetFinishedEventType(keptnv2.TestTaskName)) - assert.Equal(t, eventData.Status, keptnv2.StatusErrored) - assert.Equal(t, eventData.Result, keptnv2.ResultFailed) - assert.Contains(t, eventData.Message, notAllowedImageName) - } - } + fakeKeptn.AssertSentEvent(t, 0, checkFinishedEvent) } + +func checkFinishedEventImageNotAllowed(ce models.KeptnContextExtendedCE) bool { + eventData := &keptnv2.TestFinishedEventData{} + err := ce.DataAs(eventData) + if err != nil { + return false + } + + if eventData.Status != keptnv2.StatusErrored { + return false + } else if eventData.Result != keptnv2.ResultFailed { + return false + } + + return true +} \ No newline at end of file diff --git a/pkg/eventhandler/eventmapper.go b/pkg/eventhandler/eventmapper.go index 38e6449a..aa36b56c 100644 --- a/pkg/eventhandler/eventmapper.go +++ b/pkg/eventhandler/eventmapper.go @@ -1,10 +1,9 @@ package eventhandler import ( - "encoding/json" + keptnv2 "github.com/keptn/go-utils/pkg/lib/v0_2_0" + "github.com/keptn/go-utils/pkg/sdk" "log" - - cloudevents "github.com/cloudevents/sdk-go/v2" ) // KeptnCloudEventMapper is a simple mapper from cloudevent to map[string]interface{} @@ -14,29 +13,26 @@ type KeptnCloudEventMapper struct { } // Map transforms a cloud event into a generic map[string]interface{} as defined by EventMapper.Map -func (kcem *KeptnCloudEventMapper) Map(ce cloudevents.Event) (map[string]interface{}, error) { +func (kcem *KeptnCloudEventMapper) Map(ce sdk.KeptnEvent) (map[string]interface{}, error) { // we do the same in main#processKeptnCloudEvent:L82-85 but we use a &keptnv2.EventData{} there... var eventDataAsInterface interface{} - err := json.Unmarshal(ce.Data(), &eventDataAsInterface) + err := keptnv2.Decode(ce.Data, &eventDataAsInterface) if err != nil { log.Printf("failed to convert incoming cloudevent: %v", err) return nil, err } - extension, _ := ce.Context.GetExtension("shkeptncontext") - shKeptnContext := extension.(string) - - gitCommitID, _ := ce.Context.GetExtension("gitcommitid") + shKeptnContext := ce.Shkeptncontext eventAsInterface := make(map[string]interface{}) - eventAsInterface["id"] = ce.ID() + eventAsInterface["id"] = ce.ID eventAsInterface["shkeptncontext"] = shKeptnContext - eventAsInterface["time"] = ce.Time() - eventAsInterface["source"] = ce.Source() + eventAsInterface["time"] = ce.Time + eventAsInterface["source"] = ce.Source eventAsInterface["data"] = eventDataAsInterface - eventAsInterface["specversion"] = ce.SpecVersion() - eventAsInterface["type"] = ce.Type() - eventAsInterface["gitcommitid"] = gitCommitID + eventAsInterface["specversion"] = ce.Specversion + eventAsInterface["type"] = ce.Type + eventAsInterface["gitcommitid"] = ce.GitCommitID return eventAsInterface, nil } diff --git a/pkg/eventhandler/eventmapper_test.go b/pkg/eventhandler/eventmapper_test.go index 2a6d150f..37c3a758 100644 --- a/pkg/eventhandler/eventmapper_test.go +++ b/pkg/eventhandler/eventmapper_test.go @@ -1,40 +1,42 @@ package eventhandler import ( + "encoding/json" + keptnv2 "github.com/keptn/go-utils/pkg/lib/v0_2_0" + "github.com/keptn/go-utils/pkg/sdk" "testing" "time" - "github.com/cloudevents/sdk-go/v2/binding/spec" - "github.com/cloudevents/sdk-go/v2/event" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestInitializeEventPayloadAsInterface(t *testing.T) { - - context := spec.V1.NewContext() - context.SetID("0123") - context.SetSource("sourcysource") + source := "sourcysource" now := time.Now() - context.SetTime(now) - context.SetExtension("shkeptncontext", interface{}("mycontext")) - event := event.Event{ - Context: context, - DataEncoded: []byte(testEvent), + eventData := &keptnv2.EventData{} + err := json.Unmarshal([]byte(testEvent), eventData) + require.NoError(t, err) + + keptnEvent := sdk.KeptnEvent{ + ID: "0123", + Source: &source, + Time: now, + Shkeptncontext: "mycontext", + Data: eventData, } mapper := new(KeptnCloudEventMapper) - eventPayloadAsInterface, err := mapper.Map(event) + eventPayloadAsInterface, err := mapper.Map(keptnEvent) require.NoError(t, err) - assert.Equal(t, eventPayloadAsInterface["id"], "0123") - assert.Equal(t, eventPayloadAsInterface["source"], "sourcysource") - assert.Equal(t, eventPayloadAsInterface["time"], now) - assert.Equal(t, eventPayloadAsInterface["shkeptncontext"], "mycontext") + assert.Equal(t, "0123", eventPayloadAsInterface["id"]) + assert.Equal(t, now, eventPayloadAsInterface["time"]) + assert.Equal(t, "mycontext", eventPayloadAsInterface["shkeptncontext"]) data := eventPayloadAsInterface["data"] - dataAsMap := data.(map[string]interface{}) + dataAsMap := data.(interface{}).(map[string]interface{}) assert.Equal(t, dataAsMap["project"], "sockshop") } diff --git a/pkg/eventhandler/fake/eventhandlers_mock.go b/pkg/eventhandler/fake/eventhandlers_mock.go index b3c7e1b8..958619fa 100644 --- a/pkg/eventhandler/fake/eventhandlers_mock.go +++ b/pkg/eventhandler/fake/eventhandlers_mock.go @@ -13,6 +13,7 @@ import ( event "github.com/cloudevents/sdk-go/v2/event" gomock "github.com/golang/mock/gomock" keptn "github.com/keptn/go-utils/pkg/lib/keptn" + sdk "github.com/keptn/go-utils/pkg/sdk" ) // MockImageFilter is a mock of ImageFilter interface. @@ -76,7 +77,7 @@ func (m *MockEventMapper) EXPECT() *MockEventMapperMockRecorder { } // Map mocks base method. -func (m *MockEventMapper) Map(arg0 event.Event) (map[string]interface{}, error) { +func (m *MockEventMapper) Map(arg0 sdk.KeptnEvent) (map[string]interface{}, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Map", arg0) ret0, _ := ret[0].(map[string]interface{}) diff --git a/pkg/file/file.go b/pkg/file/file.go index 88484695..c53d6fb4 100644 --- a/pkg/file/file.go +++ b/pkg/file/file.go @@ -2,7 +2,7 @@ package file import ( "fmt" - "keptn-contrib/job-executor-service/pkg/keptn" + "keptn-contrib/job-executor-service/pkg/config" "log" "path/filepath" @@ -10,9 +10,8 @@ import ( ) // MountFiles requests all specified files of a task from the keptn configuration service and copies them to /keptn -func MountFiles(actionName string, taskName string, fs afero.Fs, configService keptn.ConfigService) error { - - configuration, err := configService.GetJobConfiguration() +func MountFiles(actionName string, taskName string, gitCommitID string, fs afero.Fs, jcr config.JobConfigReader) error { + configuration, _, err := jcr.GetJobConfig(gitCommitID) if err != nil { return fmt.Errorf("could not find config for job-executor-service: %v", err) } @@ -28,7 +27,7 @@ func MountFiles(actionName string, taskName string, fs afero.Fs, configService k } for _, resourcePath := range task.Files { - allServiceResources, err := configService.GetAllKeptnResources(fs, resourcePath) + allServiceResources, err := jcr.Keptn.GetAllKeptnResources(resourcePath) if err != nil { return fmt.Errorf("could not retrieve resources for task '%v': %v", taskName, err) } diff --git a/pkg/file/file_test.go b/pkg/file/file_test.go index fab4222e..17ac26fe 100644 --- a/pkg/file/file_test.go +++ b/pkg/file/file_test.go @@ -8,10 +8,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - keptnfake "keptn-contrib/job-executor-service/pkg/keptn/fake" - "github.com/golang/mock/gomock" "github.com/spf13/afero" + configfake "keptn-contrib/job-executor-service/pkg/config/fake" ) const simpleConfig = ` @@ -44,33 +43,36 @@ const yamlFile = ` // This is a yaml file ` -func CreateKeptnConfigServiceMock(t *testing.T) *keptnfake.MockConfigService { - +func CreateKeptnResourceServiceMock(t *testing.T) *configfake.MockKeptnResourceService { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() - return keptnfake.NewMockConfigService(mockCtrl) + return configfake.NewMockKeptnResourceService(mockCtrl) } func TestMountFiles(t *testing.T) { - fs := afero.NewMemMapFs() - configServiceMock := CreateKeptnConfigServiceMock(t) + resourceServiceMock := CreateKeptnResourceServiceMock(t) + + resourceServiceMock.EXPECT().GetServiceResource("job/config.yaml", "").Return( + []byte(simpleConfig), + nil, + ) + + sut := config2.JobConfigReader{Keptn: resourceServiceMock} - config, _ := config2.NewConfig([]byte(simpleConfig)) - configServiceMock.EXPECT().GetJobConfiguration().Times(1).Return(config, nil) - configServiceMock.EXPECT().GetAllKeptnResources( - fs, "locust", + resourceServiceMock.EXPECT().GetAllKeptnResources( + "locust", ).Times(1).Return( map[string][]byte{ "locust/basic.py": []byte(pythonFile), "locust/functional.py": []byte(pythonFile), }, nil, ) - configServiceMock.EXPECT().GetAllKeptnResources( - fs, "/helm/values.yaml", + resourceServiceMock.EXPECT().GetAllKeptnResources( + "/helm/values.yaml", ).Times(1).Return(map[string][]byte{"helm/values.yaml": []byte(yamlFile)}, nil) - err := MountFiles("action", "task", fs, configServiceMock) + err := MountFiles("action", "task", "", fs, sut) require.NoError(t, err) exists, err := afero.Exists(fs, "/keptn/locust/basic.py") @@ -91,68 +93,86 @@ func TestMountFiles(t *testing.T) { } func TestMountFilesConfigFileNotFound(t *testing.T) { - fs := afero.NewMemMapFs() - configServiceMock := CreateKeptnConfigServiceMock(t) + resourceServiceMock := CreateKeptnResourceServiceMock(t) + + resourceServiceMock.EXPECT().GetServiceResource("job/config.yaml", "").Return( + nil, + nil, + ) - configServiceMock.EXPECT().GetJobConfiguration().Times(1).Return(nil, errors.New("not found")) + sut := config2.JobConfigReader{Keptn: resourceServiceMock} - err := MountFiles("action", "task", fs, configServiceMock) + err := MountFiles("action", "task", "", fs, sut) require.Error(t, err) - assert.Contains(t, err.Error(), "not found") + assert.Contains(t, err.Error(), "could not find config for job-executor-service") } func TestMountFilesConfigFileNotValid(t *testing.T) { - fs := afero.NewMemMapFs() - configServiceMock := CreateKeptnConfigServiceMock(t) + resourceServiceMock := CreateKeptnResourceServiceMock(t) - config, configErr := config2.NewConfig([]byte(pythonFile)) - configServiceMock.EXPECT().GetJobConfiguration().Times(1).Return(config, configErr) + resourceServiceMock.EXPECT().GetServiceResource("job/config.yaml", "").Return( + []byte(pythonFile), + nil, + ) + + sut := config2.JobConfigReader{Keptn: resourceServiceMock} + + err := MountFiles("action", "task", "", fs, sut) - err := MountFiles("action", "task", fs, configServiceMock) require.Error(t, err) assert.Contains(t, err.Error(), "cannot unmarshal") } func TestMountFilesNoActionMatch(t *testing.T) { - fs := afero.NewMemMapFs() - configServiceMock := CreateKeptnConfigServiceMock(t) + resourceServiceMock := CreateKeptnResourceServiceMock(t) - config, _ := config2.NewConfig([]byte(simpleConfig)) - configServiceMock.EXPECT().GetJobConfiguration().Times(1).Return(config, nil) + resourceServiceMock.EXPECT().GetServiceResource("job/config.yaml", "").Return( + []byte(simpleConfig), + nil, + ) + + sut := config2.JobConfigReader{Keptn: resourceServiceMock} - err := MountFiles("actionNotMatching", "task", fs, configServiceMock) + err := MountFiles("actionNotMatching", "task", "", fs, sut) require.Error(t, err) assert.Contains(t, err.Error(), "no action found with name 'actionNotMatching'") } func TestMountFilesNoTaskMatch(t *testing.T) { - fs := afero.NewMemMapFs() - configServiceMock := CreateKeptnConfigServiceMock(t) + resourceServiceMock := CreateKeptnResourceServiceMock(t) - config, _ := config2.NewConfig([]byte(simpleConfig)) - configServiceMock.EXPECT().GetJobConfiguration().Times(1).Return(config, nil) + resourceServiceMock.EXPECT().GetServiceResource("job/config.yaml", "").Return( + []byte(simpleConfig), + nil, + ) + + sut := config2.JobConfigReader{Keptn: resourceServiceMock} - err := MountFiles("action", "taskNotMatching", fs, configServiceMock) + err := MountFiles("action", "taskNotMatching", "", fs, sut) require.Error(t, err) assert.Contains(t, err.Error(), "no task found with name 'taskNotMatching'") } func TestMountFilesFileNotFound(t *testing.T) { - fs := afero.NewMemMapFs() - configServiceMock := CreateKeptnConfigServiceMock(t) + resourceServiceMock := CreateKeptnResourceServiceMock(t) - config, _ := config2.NewConfig([]byte(simpleConfig)) - configServiceMock.EXPECT().GetJobConfiguration().Times(1).Return(config, nil) - configServiceMock.EXPECT().GetAllKeptnResources(fs, "/helm/values.yaml").Times(1).Return( - nil, errors.New("not found"), + resourceServiceMock.EXPECT().GetServiceResource("job/config.yaml", "").Return( + []byte(simpleConfig), + nil, ) - err := MountFiles("action", "task", fs, configServiceMock) + resourceServiceMock.EXPECT().GetAllKeptnResources( + "/helm/values.yaml", + ).Times(1).Return(nil, errors.New("not found")) + + sut := config2.JobConfigReader{Keptn: resourceServiceMock} + + err := MountFiles("action", "task", "", fs, sut) require.Error(t, err) assert.Contains(t, err.Error(), "not found") } diff --git a/pkg/keptn/config_service.go b/pkg/keptn/config_service.go deleted file mode 100644 index 6704ff48..00000000 --- a/pkg/keptn/config_service.go +++ /dev/null @@ -1,249 +0,0 @@ -package keptn - -import ( - "context" - "fmt" - "github.com/keptn/go-utils/pkg/api/models" - api "github.com/keptn/go-utils/pkg/api/utils/v2" - "keptn-contrib/job-executor-service/pkg/config" - "net/url" - "os" - "strings" - - "github.com/spf13/afero" -) - -//go:generate mockgen -source=config_service.go -destination=fake/config_service_mock.go -package=fake ConfigService - -// ConfigService provides methods to retrieve and match resources from the keptn resource service -type ConfigService interface { - GetKeptnResource(fs afero.Fs, resource string) ([]byte, error) - GetAllKeptnResources(fs afero.Fs, resource string) (map[string][]byte, error) - - // GetJobConfiguration returns the fetched job configuration - GetJobConfiguration() (*config.Config, error) -} - -//go:generate mockgen -source=config_service.go -destination=fake/config_service_mock.go -package=fake V2ResourceHandler - -// V2ResourceHandler provides methods to work with the keptn configuration service -type V2ResourceHandler interface { - // GetAllServiceResources returns a list of all resources. - GetAllServiceResources(ctx context.Context, project string, stage string, service string, - opts api.ResourcesGetAllServiceResourcesOptions) ([]*models.Resource, error) - - // GetResource returns a resource from the defined ResourceScope. - GetResource(ctx context.Context, scope api.ResourceScope, opts api.ResourcesGetResourceOptions) (*models.Resource, error) -} - -type configServiceImpl struct { - useLocalFileSystem bool - eventProperties EventProperties - resourceHandler V2ResourceHandler - jobConfigReader config.JobConfigReader -} - -// EventProperties represents a set of properties of a given cloud event -type EventProperties struct { - Project string - Stage string - Service string - GitCommitID string -} - -// NewConfigService creates and returns new ConfigService -func NewConfigService(useLocalFileSystem bool, event EventProperties, resourceHandler V2ResourceHandler) ConfigService { - configurationService := new(configServiceImpl) - - configurationService.useLocalFileSystem = useLocalFileSystem - configurationService.eventProperties = event - configurationService.resourceHandler = resourceHandler - configurationService.jobConfigReader = config.JobConfigReader{ - Keptn: configurationService, - } - - return configurationService -} - -// buildResourceHandlerV2Options builds the URIOption list such that it contains a well formatted gitCommitID -func buildResourceHandlerV2Options(gitCommitID string) api.ResourcesGetResourceOptions { - options := api.ResourcesGetResourceOptions{} - - if gitCommitID != "" { - options.URIOptions = []api.URIOption{ - api.AppendQuery(url.Values{ - "gitCommitID": []string{gitCommitID}, - }), - } - } - - return options -} - -// fetchKeptnResource sets the resource in the scope correctly and fetches the resource from Keptn with the given gitCommitID -func (k *configServiceImpl) fetchKeptnResource(resource string, scope *api.ResourceScope, gitCommitID string) ([]byte, error) { - // NOTE: No idea why, but the API requires a double query escape for a path element and does not accept leading / - // while emitting absolute paths in the response ... - scope.Resource(url.QueryEscape(strings.TrimPrefix(resource, "/"))) - - requestedResource, err := k.resourceHandler.GetResource( - context.Background(), - *scope, - buildResourceHandlerV2Options(gitCommitID), - ) - - // return Nil in case resource couldn't be retrieved - if err != nil || requestedResource.ResourceContent == "" { - return nil, fmt.Errorf("resource not found: %s - %s", resource, err) - } - - return []byte(requestedResource.ResourceContent), nil -} - -// GetKeptnResource returns a resource from the configuration repo based on the incoming cloud events project, service and stage -func (k *configServiceImpl) GetKeptnResource(fs afero.Fs, resource string) ([]byte, error) { - - // if we run in a runlocal mode we are just getting the file from the local disk - if k.useLocalFileSystem { - return k.getKeptnResourceFromLocal(fs, resource) - } - - scope := api.NewResourceScope() - scope.Project(k.eventProperties.Project) - scope.Stage(k.eventProperties.Stage) - scope.Service(k.eventProperties.Service) - - // finally download the resource: - return k.fetchKeptnResource(resource, scope, k.eventProperties.GitCommitID) -} - -// GetAllKeptnResources returns a map of keptn resources (key=URI, value=content) from the configuration repo with -// prefix 'resource' (matched with and without leading '/') -func (k *configServiceImpl) GetAllKeptnResources(fs afero.Fs, resource string) (map[string][]byte, error) { - - // if we run in a runlocal mode we are just getting the file from the local disk - if k.useLocalFileSystem { - return k.getKeptnResourcesFromLocal(fs, resource) - } - - keptnResources := make(map[string][]byte) - - // Check for an exact match in the resources - keptnResourceContent, err := k.GetKeptnResource(fs, resource) - if err == nil { - keptnResources[resource] = keptnResourceContent - return keptnResources, nil - } - - // NOTE: - // Since no exact file has been found, we have to assume that the given resource is a directory. - // Directories don't really exist in the API, so we have to use a HasPrefix match here - scope := api.NewResourceScope() - scope.Project(k.eventProperties.Project) - scope.Stage(k.eventProperties.Stage) - scope.Service(k.eventProperties.Service) - - // Get all files from Keptn to enumerate what is in the directory - requestedResources, err := k.resourceHandler.GetAllServiceResources(context.Background(), - k.eventProperties.Project, k.eventProperties.Stage, k.eventProperties.Service, - api.ResourcesGetAllServiceResourcesOptions{}, - ) - if err != nil { - return nil, fmt.Errorf("unable to list all resources: %w", err) - } - - // Create a path from the / and append a / to the end to match only files in that directory - resourceDirectoryName := resource + "/" - if !strings.HasPrefix(resourceDirectoryName, "/") { - resourceDirectoryName = "/" + resourceDirectoryName - } - - for _, serviceResource := range requestedResources { - if strings.HasPrefix(*serviceResource.ResourceURI, resourceDirectoryName) { - - // Query resource with the specified git commit id: - keptnResourceContent, err := k.GetKeptnResource(fs, *serviceResource.ResourceURI) - if err != nil { - return nil, fmt.Errorf("unable to fetch resource %s: %w", *serviceResource.ResourceURI, err) - } - - keptnResources[*serviceResource.ResourceURI] = keptnResourceContent - } - } - - return keptnResources, nil -} - -func (k *configServiceImpl) GetServiceResource(resource string, gitCommitID string) ([]byte, error) { - scope := api.NewResourceScope() - scope.Project(k.eventProperties.Project) - scope.Stage(k.eventProperties.Stage) - scope.Service(k.eventProperties.Service) - return k.fetchKeptnResource(resource, scope, gitCommitID) -} - -func (k *configServiceImpl) GetStageResource(resource string, gitCommitID string) ([]byte, error) { - scope := api.NewResourceScope() - scope.Project(k.eventProperties.Project) - scope.Stage(k.eventProperties.Stage) - return k.fetchKeptnResource(resource, scope, gitCommitID) -} - -func (k *configServiceImpl) GetProjectResource(resource string, gitCommitID string) ([]byte, error) { - scope := api.NewResourceScope() - scope.Project(k.eventProperties.Project) - return k.fetchKeptnResource(resource, scope, gitCommitID) -} - -func (k *configServiceImpl) GetJobConfiguration() (*config.Config, error) { - config, _, err := k.jobConfigReader.GetJobConfig(k.eventProperties.GitCommitID) - return config, err -} - -/** - * Retrieves a resource (=file) from the local file system. Basically checks if the file is available and if so returns it - */ -func (k *configServiceImpl) getKeptnResourceFromLocal(fs afero.Fs, resource string) ([]byte, error) { - _, err := fs.Stat(resource) - if err != nil { - return nil, err - } - - content, err := afero.ReadFile(fs, resource) - if err != nil { - return nil, err - } - return content, nil -} - -/** -* Retrieves a resource (=file or all files of a directory) from the local file system. Basically checks if the file/directory - is available and if so returns it or its files -*/ -func (k *configServiceImpl) getKeptnResourcesFromLocal(fs afero.Fs, resource string) (map[string][]byte, error) { - resources := make(map[string][]byte) - err := afero.Walk( - fs, resource, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - if info.IsDir() { - return nil - } - - content, err := k.getKeptnResourceFromLocal(fs, path) - if err != nil { - return err - } - resources[path] = content - return nil - }, - ) - - if err != nil { - return nil, err - } - - return resources, nil -} diff --git a/pkg/keptn/config_service_test.go b/pkg/keptn/config_service_test.go deleted file mode 100644 index 56f3516d..00000000 --- a/pkg/keptn/config_service_test.go +++ /dev/null @@ -1,299 +0,0 @@ -package keptn - -import ( - "errors" - "fmt" - "net/url" - "path" - "strings" - "testing" - - "github.com/keptn/go-utils/pkg/api/models" - api "github.com/keptn/go-utils/pkg/api/utils/v2" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - keptnfake "keptn-contrib/job-executor-service/pkg/keptn/fake" - - "github.com/golang/mock/gomock" - "github.com/spf13/afero" -) - -func CreateResourceHandlerMock(t *testing.T) *keptnfake.MockV2ResourceHandler { - mockCtrl := gomock.NewController(t) - return keptnfake.NewMockV2ResourceHandler(mockCtrl) -} - -const service = "carts" -const project = "sockshop" -const stage = "dev" -const gitCommitID = "6caf78d2c978f7f787" -const emptyJobConfig = `apiVersion: v2 -actions: - - name: Empty -` - -func TestGetAllKeptnResources(t *testing.T) { - locustBasic := "/locust/basic.py" - locustFunctional := "/locust/functional.py" - ignoredFile := "/locustIGNORED" - - resourceHandlerMock := CreateResourceHandlerMock(t) - resourceHandlerMock.EXPECT().GetAllServiceResources(gomock.Any(), project, stage, service, gomock.Any()).Times(1).Return( - []*models.Resource{ - { - Metadata: nil, - ResourceContent: "", - ResourceURI: &locustBasic, - }, - { - Metadata: nil, - ResourceContent: "", - ResourceURI: &locustFunctional, - }, - { - Metadata: nil, - ResourceContent: "", - ResourceURI: &ignoredFile, - }, - }, nil, - ) - - folderScope := api.NewResourceScope() - folderScope.Project(project) - folderScope.Stage(stage) - folderScope.Service(service) - folderScope.Resource("locust") - - resourceHandlerMock.EXPECT().GetResource(gomock.Any(), *folderScope, gomock.Any()).Times(1).Return( - nil, fmt.Errorf("internal Server Error - Not a file"), - ) - - scope1 := api.NewResourceScope() - scope1.Project(project) - scope1.Stage(stage) - scope1.Service(service) - scope1.Resource(url.QueryEscape(strings.TrimPrefix(locustBasic, "/"))) - - resourceHandlerMock.EXPECT().GetResource(gomock.Any(), *scope1, gomock.Any()).Times(1).Return( - &models.Resource{ - Metadata: nil, - ResourceContent: locustBasic, - ResourceURI: nil, - }, nil, - ) - - scope2 := api.NewResourceScope() - scope2.Project(project) - scope2.Stage(stage) - scope2.Service(service) - scope2.Resource(url.QueryEscape(strings.TrimPrefix(locustFunctional, "/"))) - - resourceHandlerMock.EXPECT().GetResource(gomock.Any(), *scope2, gomock.Any()).Times(1).Return( - &models.Resource{ - Metadata: nil, - ResourceContent: locustFunctional, - ResourceURI: nil, - }, nil, - ) - - ignoredFileScope := api.NewResourceScope() - ignoredFileScope.Project(project) - ignoredFileScope.Stage(stage) - ignoredFileScope.Service(service) - ignoredFileScope.Resource(url.QueryEscape(strings.TrimPrefix(locustFunctional, "/"))) - - resourceHandlerMock.EXPECT().GetResource(gomock.Any(), *ignoredFileScope, gomock.Any()).Times(0) - - event := EventProperties{ - Project: project, - Stage: stage, - Service: service, - GitCommitID: gitCommitID, - } - - configService := NewConfigService(false, event, resourceHandlerMock) - fs := afero.NewMemMapFs() - - keptnResources, err := configService.GetAllKeptnResources(fs, "locust") - require.NoError(t, err) - - val, ok := keptnResources[locustBasic] - assert.True(t, ok) - assert.Equal(t, locustBasic, string(val)) - - val, ok = keptnResources[locustFunctional] - assert.True(t, ok) - assert.Equal(t, locustFunctional, string(val)) -} - -func TestGetAllKeptnResourcesLocal(t *testing.T) { - locustPath := "/locust" - locustBasic := path.Join(locustPath, "basic.py") - locustFunctional := path.Join(locustPath, "functional.py") - - resourceHandlerMock := CreateResourceHandlerMock(t) - resourceHandlerMock.EXPECT().GetAllServiceResources(gomock.Any(), project, stage, service, gomock.Any()).Times(0) - - scope1 := api.NewResourceScope() - scope1.Project(project) - scope1.Stage(stage) - scope1.Service(service) - scope1.Resource(url.QueryEscape(locustBasic)) - - resourceHandlerMock.EXPECT().GetResource(gomock.Any(), scope1, gomock.Any()).Times(0) - - scope2 := api.NewResourceScope() - scope2.Project(project) - scope2.Stage(stage) - scope2.Service(service) - scope2.Resource(url.QueryEscape(locustFunctional)) - - resourceHandlerMock.EXPECT().GetResource(gomock.Any(), scope2, gomock.Any()).Times(0) - - event := EventProperties{ - Project: project, - Stage: stage, - Service: service, - GitCommitID: "", - } - - configService := NewConfigService(true, event, resourceHandlerMock) - fs := afero.NewMemMapFs() - - err := createFile(fs, locustBasic, []byte(locustBasic)) - require.NoError(t, err) - - err = createFile(fs, locustFunctional, []byte(locustFunctional)) - require.NoError(t, err) - - keptnResources, err := configService.GetAllKeptnResources(fs, locustPath) - require.NoError(t, err) - - val, ok := keptnResources[locustBasic] - assert.True(t, ok) - assert.Equal(t, locustBasic, string(val)) - - val, ok = keptnResources[locustFunctional] - assert.True(t, ok) - assert.Equal(t, string(val), locustFunctional) -} - -func TestErrorNoDirectoryResourcesLocal(t *testing.T) { - locustPath := "/locust" - locustBasic := path.Join(locustPath, "basic.py") - locustFunctional := path.Join(locustPath, "functional.py") - - resourceHandlerMock := CreateResourceHandlerMock(t) - resourceHandlerMock.EXPECT().GetAllServiceResources(gomock.Any(), project, stage, service, gomock.Any()).Times(0) - - scope1 := api.NewResourceScope() - scope1.Project(project) - scope1.Stage(stage) - scope1.Service(service) - scope1.Resource(url.QueryEscape(locustBasic)) - - resourceHandlerMock.EXPECT().GetResource(gomock.Any(), scope1, gomock.Any()).Times(0) - - scope2 := api.NewResourceScope() - scope2.Project(project) - scope2.Stage(stage) - scope2.Service(service) - scope2.Resource(url.QueryEscape(locustFunctional)) - - resourceHandlerMock.EXPECT().GetResource(gomock.Any(), scope2, gomock.Any()).Times(0) - - event := EventProperties{ - Project: project, - Stage: stage, - Service: service, - GitCommitID: "", - } - - configService := NewConfigService(true, event, resourceHandlerMock) - fs := afero.NewMemMapFs() - - _, err := configService.GetAllKeptnResources(fs, locustPath) - require.Error(t, err) -} - -func TestConfigServiceImpl_GetJobConfiguration(t *testing.T) { - - serviceScope := api.NewResourceScope() - serviceScope.Project(project) - serviceScope.Stage(stage) - serviceScope.Service(service) - serviceScope.Resource(url.QueryEscape("job/config.yaml")) - - stageScope := api.NewResourceScope() - stageScope.Project(project) - stageScope.Stage(stage) - stageScope.Resource(url.QueryEscape("job/config.yaml")) - - projectScope := api.NewResourceScope() - projectScope.Project(project) - projectScope.Resource(url.QueryEscape("job/config.yaml")) - - event := EventProperties{ - Project: project, - Stage: stage, - Service: service, - GitCommitID: "", - } - - jobConfigResource := &models.Resource{ - Metadata: nil, - ResourceContent: emptyJobConfig, - ResourceURI: nil, - } - - t.Run("service configuration", func(t *testing.T) { - resourceHandlerMock := CreateResourceHandlerMock(t) - configService := NewConfigService(false, event, resourceHandlerMock) - - resourceHandlerMock.EXPECT().GetResource(gomock.Any(), *serviceScope, gomock.Any()).Return(jobConfigResource, nil) - - configuration, err := configService.GetJobConfiguration() - assert.NoError(t, err) - assert.Len(t, configuration.Actions, 1) - }) - - t.Run("stage configuration", func(t *testing.T) { - resourceHandlerMock := CreateResourceHandlerMock(t) - configService := NewConfigService(false, event, resourceHandlerMock) - - resourceHandlerMock.EXPECT().GetResource(gomock.Any(), *serviceScope, gomock.Any()).Return(nil, errors.New("error")) - resourceHandlerMock.EXPECT().GetResource(gomock.Any(), *stageScope, gomock.Any()).Return(jobConfigResource, nil) - - configuration, err := configService.GetJobConfiguration() - assert.NoError(t, err) - assert.Len(t, configuration.Actions, 1) - }) - - t.Run("project configuration", func(t *testing.T) { - resourceHandlerMock := CreateResourceHandlerMock(t) - configService := NewConfigService(false, event, resourceHandlerMock) - - resourceHandlerMock.EXPECT().GetResource(gomock.Any(), *serviceScope, gomock.Any()).Return(nil, errors.New("error")) - resourceHandlerMock.EXPECT().GetResource(gomock.Any(), *stageScope, gomock.Any()).Return(nil, errors.New("error")) - resourceHandlerMock.EXPECT().GetResource(gomock.Any(), *projectScope, gomock.Any()).Return(jobConfigResource, nil) - - configuration, err := configService.GetJobConfiguration() - assert.NoError(t, err) - assert.Len(t, configuration.Actions, 1) - }) -} - -func createFile(fs afero.Fs, fileName string, content []byte) error { - file, err := fs.Create(fileName) - if err != nil { - return err - } - file.Write(content) - err = file.Close() - if err != nil { - return err - } - return nil -} diff --git a/pkg/keptn/fake/config_service_mock.go b/pkg/keptn/fake/config_service_mock.go deleted file mode 100644 index 1a8bbccb..00000000 --- a/pkg/keptn/fake/config_service_mock.go +++ /dev/null @@ -1,137 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: config_service.go - -// Package fake is a generated GoMock package. -package fake - -import ( - context "context" - config "keptn-contrib/job-executor-service/pkg/config" - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - models "github.com/keptn/go-utils/pkg/api/models" - v2 "github.com/keptn/go-utils/pkg/api/utils/v2" - afero "github.com/spf13/afero" -) - -// MockConfigService is a mock of ConfigService interface. -type MockConfigService struct { - ctrl *gomock.Controller - recorder *MockConfigServiceMockRecorder -} - -// MockConfigServiceMockRecorder is the mock recorder for MockConfigService. -type MockConfigServiceMockRecorder struct { - mock *MockConfigService -} - -// NewMockConfigService creates a new mock instance. -func NewMockConfigService(ctrl *gomock.Controller) *MockConfigService { - mock := &MockConfigService{ctrl: ctrl} - mock.recorder = &MockConfigServiceMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockConfigService) EXPECT() *MockConfigServiceMockRecorder { - return m.recorder -} - -// GetAllKeptnResources mocks base method. -func (m *MockConfigService) GetAllKeptnResources(fs afero.Fs, resource string) (map[string][]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAllKeptnResources", fs, resource) - ret0, _ := ret[0].(map[string][]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetAllKeptnResources indicates an expected call of GetAllKeptnResources. -func (mr *MockConfigServiceMockRecorder) GetAllKeptnResources(fs, resource interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllKeptnResources", reflect.TypeOf((*MockConfigService)(nil).GetAllKeptnResources), fs, resource) -} - -// GetJobConfiguration mocks base method. -func (m *MockConfigService) GetJobConfiguration() (*config.Config, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetJobConfiguration") - ret0, _ := ret[0].(*config.Config) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetJobConfiguration indicates an expected call of GetJobConfiguration. -func (mr *MockConfigServiceMockRecorder) GetJobConfiguration() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetJobConfiguration", reflect.TypeOf((*MockConfigService)(nil).GetJobConfiguration)) -} - -// GetKeptnResource mocks base method. -func (m *MockConfigService) GetKeptnResource(fs afero.Fs, resource string) ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetKeptnResource", fs, resource) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetKeptnResource indicates an expected call of GetKeptnResource. -func (mr *MockConfigServiceMockRecorder) GetKeptnResource(fs, resource interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetKeptnResource", reflect.TypeOf((*MockConfigService)(nil).GetKeptnResource), fs, resource) -} - -// MockV2ResourceHandler is a mock of V2ResourceHandler interface. -type MockV2ResourceHandler struct { - ctrl *gomock.Controller - recorder *MockV2ResourceHandlerMockRecorder -} - -// MockV2ResourceHandlerMockRecorder is the mock recorder for MockV2ResourceHandler. -type MockV2ResourceHandlerMockRecorder struct { - mock *MockV2ResourceHandler -} - -// NewMockV2ResourceHandler creates a new mock instance. -func NewMockV2ResourceHandler(ctrl *gomock.Controller) *MockV2ResourceHandler { - mock := &MockV2ResourceHandler{ctrl: ctrl} - mock.recorder = &MockV2ResourceHandlerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockV2ResourceHandler) EXPECT() *MockV2ResourceHandlerMockRecorder { - return m.recorder -} - -// GetAllServiceResources mocks base method. -func (m *MockV2ResourceHandler) GetAllServiceResources(ctx context.Context, project, stage, service string, opts v2.ResourcesGetAllServiceResourcesOptions) ([]*models.Resource, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAllServiceResources", ctx, project, stage, service, opts) - ret0, _ := ret[0].([]*models.Resource) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetAllServiceResources indicates an expected call of GetAllServiceResources. -func (mr *MockV2ResourceHandlerMockRecorder) GetAllServiceResources(ctx, project, stage, service, opts interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllServiceResources", reflect.TypeOf((*MockV2ResourceHandler)(nil).GetAllServiceResources), ctx, project, stage, service, opts) -} - -// GetResource mocks base method. -func (m *MockV2ResourceHandler) GetResource(ctx context.Context, scope v2.ResourceScope, opts v2.ResourcesGetResourceOptions) (*models.Resource, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetResource", ctx, scope, opts) - ret0, _ := ret[0].(*models.Resource) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetResource indicates an expected call of GetResource. -func (mr *MockV2ResourceHandlerMockRecorder) GetResource(ctx, scope, opts interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetResource", reflect.TypeOf((*MockV2ResourceHandler)(nil).GetResource), ctx, scope, opts) -} diff --git a/pkg/keptn/fake/keptn_resourcehandler_mock.go b/pkg/keptn/fake/keptn_resourcehandler_mock.go index e00aafd7..5db45f48 100644 --- a/pkg/keptn/fake/keptn_resourcehandler_mock.go +++ b/pkg/keptn/fake/keptn_resourcehandler_mock.go @@ -5,13 +5,269 @@ package fake import ( + context "context" reflect "reflect" gomock "github.com/golang/mock/gomock" models "github.com/keptn/go-utils/pkg/api/models" - api "github.com/keptn/go-utils/pkg/api/utils" + v2 "github.com/keptn/go-utils/pkg/api/utils/v2" ) +// MockResourceHandler is a mock of ResourceHandler interface. +type MockResourceHandler struct { + ctrl *gomock.Controller + recorder *MockResourceHandlerMockRecorder +} + +// MockResourceHandlerMockRecorder is the mock recorder for MockResourceHandler. +type MockResourceHandlerMockRecorder struct { + mock *MockResourceHandler +} + +// NewMockResourceHandler creates a new mock instance. +func NewMockResourceHandler(ctrl *gomock.Controller) *MockResourceHandler { + mock := &MockResourceHandler{ctrl: ctrl} + mock.recorder = &MockResourceHandlerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockResourceHandler) EXPECT() *MockResourceHandlerMockRecorder { + return m.recorder +} + +// GetAllKeptnResources mocks base method. +func (m *MockResourceHandler) GetAllKeptnResources(resource string) (map[string][]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAllKeptnResources", resource) + ret0, _ := ret[0].(map[string][]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAllKeptnResources indicates an expected call of GetAllKeptnResources. +func (mr *MockResourceHandlerMockRecorder) GetAllKeptnResources(resource interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllKeptnResources", reflect.TypeOf((*MockResourceHandler)(nil).GetAllKeptnResources), resource) +} + +// GetProjectResource mocks base method. +func (m *MockResourceHandler) GetProjectResource(resource, gitCommitID string) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetProjectResource", resource, gitCommitID) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetProjectResource indicates an expected call of GetProjectResource. +func (mr *MockResourceHandlerMockRecorder) GetProjectResource(resource, gitCommitID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProjectResource", reflect.TypeOf((*MockResourceHandler)(nil).GetProjectResource), resource, gitCommitID) +} + +// GetServiceResource mocks base method. +func (m *MockResourceHandler) GetServiceResource(resource, gitCommitID string) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetServiceResource", resource, gitCommitID) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetServiceResource indicates an expected call of GetServiceResource. +func (mr *MockResourceHandlerMockRecorder) GetServiceResource(resource, gitCommitID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServiceResource", reflect.TypeOf((*MockResourceHandler)(nil).GetServiceResource), resource, gitCommitID) +} + +// GetStageResource mocks base method. +func (m *MockResourceHandler) GetStageResource(resource, gitCommitID string) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetStageResource", resource, gitCommitID) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetStageResource indicates an expected call of GetStageResource. +func (mr *MockResourceHandlerMockRecorder) GetStageResource(resource, gitCommitID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStageResource", reflect.TypeOf((*MockResourceHandler)(nil).GetStageResource), resource, gitCommitID) +} + +// MockResourcesInterface is a mock of ResourcesInterface interface. +type MockResourcesInterface struct { + ctrl *gomock.Controller + recorder *MockResourcesInterfaceMockRecorder +} + +// MockResourcesInterfaceMockRecorder is the mock recorder for MockResourcesInterface. +type MockResourcesInterfaceMockRecorder struct { + mock *MockResourcesInterface +} + +// NewMockResourcesInterface creates a new mock instance. +func NewMockResourcesInterface(ctrl *gomock.Controller) *MockResourcesInterface { + mock := &MockResourcesInterface{ctrl: ctrl} + mock.recorder = &MockResourcesInterfaceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockResourcesInterface) EXPECT() *MockResourcesInterfaceMockRecorder { + return m.recorder +} + +// CreateProjectResources mocks base method. +func (m *MockResourcesInterface) CreateProjectResources(ctx context.Context, project string, resources []*models.Resource, opts v2.ResourcesCreateProjectResourcesOptions) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateProjectResources", ctx, project, resources, opts) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateProjectResources indicates an expected call of CreateProjectResources. +func (mr *MockResourcesInterfaceMockRecorder) CreateProjectResources(ctx, project, resources, opts interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateProjectResources", reflect.TypeOf((*MockResourcesInterface)(nil).CreateProjectResources), ctx, project, resources, opts) +} + +// CreateResource mocks base method. +func (m *MockResourcesInterface) CreateResource(ctx context.Context, resource []*models.Resource, scope v2.ResourceScope, opts v2.ResourcesCreateResourceOptions) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateResource", ctx, resource, scope, opts) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateResource indicates an expected call of CreateResource. +func (mr *MockResourcesInterfaceMockRecorder) CreateResource(ctx, resource, scope, opts interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateResource", reflect.TypeOf((*MockResourcesInterface)(nil).CreateResource), ctx, resource, scope, opts) +} + +// CreateResources mocks base method. +func (m *MockResourcesInterface) CreateResources(ctx context.Context, project, stage, service string, resources []*models.Resource, opts v2.ResourcesCreateResourcesOptions) (*models.EventContext, *models.Error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateResources", ctx, project, stage, service, resources, opts) + ret0, _ := ret[0].(*models.EventContext) + ret1, _ := ret[1].(*models.Error) + return ret0, ret1 +} + +// CreateResources indicates an expected call of CreateResources. +func (mr *MockResourcesInterfaceMockRecorder) CreateResources(ctx, project, stage, service, resources, opts interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateResources", reflect.TypeOf((*MockResourcesInterface)(nil).CreateResources), ctx, project, stage, service, resources, opts) +} + +// DeleteResource mocks base method. +func (m *MockResourcesInterface) DeleteResource(ctx context.Context, scope v2.ResourceScope, opts v2.ResourcesDeleteResourceOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteResource", ctx, scope, opts) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteResource indicates an expected call of DeleteResource. +func (mr *MockResourcesInterfaceMockRecorder) DeleteResource(ctx, scope, opts interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteResource", reflect.TypeOf((*MockResourcesInterface)(nil).DeleteResource), ctx, scope, opts) +} + +// GetAllServiceResources mocks base method. +func (m *MockResourcesInterface) GetAllServiceResources(ctx context.Context, project, stage, service string, opts v2.ResourcesGetAllServiceResourcesOptions) ([]*models.Resource, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAllServiceResources", ctx, project, stage, service, opts) + ret0, _ := ret[0].([]*models.Resource) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAllServiceResources indicates an expected call of GetAllServiceResources. +func (mr *MockResourcesInterfaceMockRecorder) GetAllServiceResources(ctx, project, stage, service, opts interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllServiceResources", reflect.TypeOf((*MockResourcesInterface)(nil).GetAllServiceResources), ctx, project, stage, service, opts) +} + +// GetAllStageResources mocks base method. +func (m *MockResourcesInterface) GetAllStageResources(ctx context.Context, project, stage string, opts v2.ResourcesGetAllStageResourcesOptions) ([]*models.Resource, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAllStageResources", ctx, project, stage, opts) + ret0, _ := ret[0].([]*models.Resource) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAllStageResources indicates an expected call of GetAllStageResources. +func (mr *MockResourcesInterfaceMockRecorder) GetAllStageResources(ctx, project, stage, opts interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllStageResources", reflect.TypeOf((*MockResourcesInterface)(nil).GetAllStageResources), ctx, project, stage, opts) +} + +// GetResource mocks base method. +func (m *MockResourcesInterface) GetResource(ctx context.Context, scope v2.ResourceScope, opts v2.ResourcesGetResourceOptions) (*models.Resource, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetResource", ctx, scope, opts) + ret0, _ := ret[0].(*models.Resource) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetResource indicates an expected call of GetResource. +func (mr *MockResourcesInterfaceMockRecorder) GetResource(ctx, scope, opts interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetResource", reflect.TypeOf((*MockResourcesInterface)(nil).GetResource), ctx, scope, opts) +} + +// UpdateProjectResources mocks base method. +func (m *MockResourcesInterface) UpdateProjectResources(ctx context.Context, project string, resources []*models.Resource, opts v2.ResourcesUpdateProjectResourcesOptions) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateProjectResources", ctx, project, resources, opts) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateProjectResources indicates an expected call of UpdateProjectResources. +func (mr *MockResourcesInterfaceMockRecorder) UpdateProjectResources(ctx, project, resources, opts interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateProjectResources", reflect.TypeOf((*MockResourcesInterface)(nil).UpdateProjectResources), ctx, project, resources, opts) +} + +// UpdateResource mocks base method. +func (m *MockResourcesInterface) UpdateResource(ctx context.Context, resource *models.Resource, scope v2.ResourceScope, opts v2.ResourcesUpdateResourceOptions) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateResource", ctx, resource, scope, opts) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateResource indicates an expected call of UpdateResource. +func (mr *MockResourcesInterfaceMockRecorder) UpdateResource(ctx, resource, scope, opts interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateResource", reflect.TypeOf((*MockResourcesInterface)(nil).UpdateResource), ctx, resource, scope, opts) +} + +// UpdateServiceResources mocks base method. +func (m *MockResourcesInterface) UpdateServiceResources(ctx context.Context, project, stage, service string, resources []*models.Resource, opts v2.ResourcesUpdateServiceResourcesOptions) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateServiceResources", ctx, project, stage, service, resources, opts) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateServiceResources indicates an expected call of UpdateServiceResources. +func (mr *MockResourcesInterfaceMockRecorder) UpdateServiceResources(ctx, project, stage, service, resources, opts interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateServiceResources", reflect.TypeOf((*MockResourcesInterface)(nil).UpdateServiceResources), ctx, project, stage, service, resources, opts) +} + // MockV1KeptnResourceHandler is a mock of V1KeptnResourceHandler interface. type MockV1KeptnResourceHandler struct { ctrl *gomock.Controller @@ -36,7 +292,7 @@ func (m *MockV1KeptnResourceHandler) EXPECT() *MockV1KeptnResourceHandlerMockRec } // GetResource mocks base method. -func (m *MockV1KeptnResourceHandler) GetResource(scope api.ResourceScope, options ...api.URIOption) (*models.Resource, error) { +func (m *MockV1KeptnResourceHandler) GetResource(scope v2.ResourceScope, options ...v2.URIOption) (*models.Resource, error) { m.ctrl.T.Helper() varargs := []interface{}{scope} for _, a := range options { diff --git a/pkg/keptn/resource_service.go b/pkg/keptn/resource_service.go index 2b80ac43..74e994e1 100644 --- a/pkg/keptn/resource_service.go +++ b/pkg/keptn/resource_service.go @@ -1,36 +1,61 @@ package keptn import ( + "context" "fmt" "github.com/keptn/go-utils/pkg/api/models" - api "github.com/keptn/go-utils/pkg/api/utils" - "github.com/keptn/go-utils/pkg/lib/keptn" + api "github.com/keptn/go-utils/pkg/api/utils/v2" + keptnv2 "github.com/keptn/go-utils/pkg/lib/v0_2_0" "net/url" + "strings" ) +// EventProperties represents a set of properties of a given cloud event +type EventProperties struct { + Project string + Stage string + Service string + GitCommitID string +} + // ResourceHandler is an interface that describes the functions for fetching resources from a service, stage or project level type ResourceHandler interface { GetServiceResource(resource string, gitCommitID string) ([]byte, error) GetStageResource(resource string, gitCommitID string) ([]byte, error) GetProjectResource(resource string, gitCommitID string) ([]byte, error) + GetAllKeptnResources(resource string) (map[string][]byte, error) +} + +// ResourcesInterface is an interface that describes the Keptn resource API +type ResourcesInterface interface { + CreateResources(ctx context.Context, project string, stage string, service string, resources []*models.Resource, opts api.ResourcesCreateResourcesOptions) (*models.EventContext, *models.Error) + CreateProjectResources(ctx context.Context, project string, resources []*models.Resource, opts api.ResourcesCreateProjectResourcesOptions) (string, error) + UpdateProjectResources(ctx context.Context, project string, resources []*models.Resource, opts api.ResourcesUpdateProjectResourcesOptions) (string, error) + UpdateServiceResources(ctx context.Context, project string, stage string, service string, resources []*models.Resource, opts api.ResourcesUpdateServiceResourcesOptions) (string, error) + GetAllStageResources(ctx context.Context, project string, stage string, opts api.ResourcesGetAllStageResourcesOptions) ([]*models.Resource, error) + GetAllServiceResources(ctx context.Context, project string, stage string, service string, opts api.ResourcesGetAllServiceResourcesOptions) ([]*models.Resource, error) + GetResource(ctx context.Context, scope api.ResourceScope, opts api.ResourcesGetResourceOptions) (*models.Resource, error) + DeleteResource(ctx context.Context, scope api.ResourceScope, opts api.ResourcesDeleteResourceOptions) error + UpdateResource(ctx context.Context, resource *models.Resource, scope api.ResourceScope, opts api.ResourcesUpdateResourceOptions) (string, error) + CreateResource(ctx context.Context, resource []*models.Resource, scope api.ResourceScope, opts api.ResourcesCreateResourceOptions) (string, error) } // V1ResourceHandler is a wrapper around the v1 ResourceHandler of the Keptn API to simplify the // getting of resources of a given event type V1ResourceHandler struct { - Event EventProperties - ResourceHandler V1KeptnResourceHandler + Event EventProperties + ResourceAPI ResourcesInterface } // NewV1ResourceHandler creates a new V1ResourceHandler from a given Keptn event and a V1KeptnResourceHandler -func NewV1ResourceHandler(event keptn.EventProperties, handler V1KeptnResourceHandler) ResourceHandler { +func NewV1ResourceHandler(event keptnv2.EventData, resourceAPI ResourcesInterface) ResourceHandler { return V1ResourceHandler{ Event: EventProperties{ Project: event.GetProject(), Stage: event.GetStage(), Service: event.GetService(), }, - ResourceHandler: handler, + ResourceAPI: resourceAPI, } } @@ -39,6 +64,7 @@ func NewV1ResourceHandler(event keptn.EventProperties, handler V1KeptnResourceHa // V1KeptnResourceHandler represents an interface for the api.ResourceHandler struct of the Keptn API type V1KeptnResourceHandler interface { GetResource(scope api.ResourceScope, options ...api.URIOption) (*models.Resource, error) + //GetAllServiceResources(project string, stage string, service string) ([]*models.Resource, error) } // buildResourceHandlerV1Options builds the URIOption list such that it contains a well formatted gitCommitID @@ -61,9 +87,12 @@ func (r V1ResourceHandler) GetServiceResource(resource string, gitCommitID strin scope.Service(r.Event.Service) scope.Project(r.Event.Project) scope.Stage(r.Event.Stage) - scope.Resource(resource) + scope.Resource(url.QueryEscape(resource)) - resourceContent, err := r.ResourceHandler.GetResource(*scope, buildResourceHandlerV1Options(gitCommitID)) + options := api.ResourcesGetResourceOptions{URIOptions: []api.URIOption{ + buildResourceHandlerV1Options(gitCommitID), + }} + resourceContent, err := r.ResourceAPI.GetResource(context.Background(), *scope, options) if err != nil { return nil, fmt.Errorf("unable to get resouce from keptn: %w", err) } @@ -75,9 +104,12 @@ func (r V1ResourceHandler) GetServiceResource(resource string, gitCommitID strin func (r V1ResourceHandler) GetProjectResource(resource string, gitCommitID string) ([]byte, error) { scope := api.NewResourceScope() scope.Project(r.Event.Project) - scope.Resource(resource) + scope.Resource(url.QueryEscape(resource)) - resourceContent, err := r.ResourceHandler.GetResource(*scope, buildResourceHandlerV1Options(gitCommitID)) + options := api.ResourcesGetResourceOptions{URIOptions: []api.URIOption{ + buildResourceHandlerV1Options(gitCommitID), + }} + resourceContent, err := r.ResourceAPI.GetResource(context.Background(), *scope, options) if err != nil { return nil, fmt.Errorf("unable to get resouce from keptn: %w", err) } @@ -90,12 +122,69 @@ func (r V1ResourceHandler) GetStageResource(resource string, gitCommitID string) scope := api.NewResourceScope() scope.Project(r.Event.Project) scope.Stage(r.Event.Stage) - scope.Resource(resource) + scope.Resource(url.QueryEscape(resource)) - resourceContent, err := r.ResourceHandler.GetResource(*scope, buildResourceHandlerV1Options(gitCommitID)) + options := api.ResourcesGetResourceOptions{URIOptions: []api.URIOption{ + buildResourceHandlerV1Options(gitCommitID), + }} + resourceContent, err := r.ResourceAPI.GetResource(context.Background(), *scope, options) if err != nil { return nil, fmt.Errorf("unable to get resouce from keptn: %w", err) } return []byte(resourceContent.ResourceContent), nil } + +// GetAllKeptnResources returns a map of keptn resources (key=URI, value=content) from the configuration repo with +// prefix 'resource' (matched with and without leading '/') +func (r V1ResourceHandler) GetAllKeptnResources(resource string) (map[string][]byte, error) { + keptnResources := make(map[string][]byte) + + // Check for an exact match in the resources - Resource is a file + keptnResourceContent, err := r.GetServiceResource(resource, "") + if err == nil { + keptnResources[resource] = keptnResourceContent + return keptnResources, nil + } + + // NOTE: + // Since no exact file has been found, we have to assume that the given resource is a directory. + // Directories don't really exist in the API, so we have to use a HasPrefix match here + + // Get all files from Keptn to enumerate what is in the directory + requestedResources, err := r.ResourceAPI.GetAllServiceResources(context.Background(), r.Event.Project, r.Event.Stage, r.Event.Service, api.ResourcesGetAllServiceResourcesOptions{}) + + if err != nil { + return nil, fmt.Errorf("unable to list all resources: %w", err) + } + + // Create a path from the / and append a / to the end to match only files in that directory + resourceDirectoryName := resource + "/" + if !strings.HasPrefix(resourceDirectoryName, "/") { + resourceDirectoryName = "/" + resourceDirectoryName + } + + for _, serviceResource := range requestedResources { + if strings.HasPrefix(*serviceResource.ResourceURI, resourceDirectoryName) { + + scope := api.NewResourceScope() + scope.Project(r.Event.Project) + scope.Stage(r.Event.Stage) + scope.Service(r.Event.Service) + scope.Resource(url.QueryEscape(*serviceResource.ResourceURI)) + + // Query resource with the specified git commit id: + options := api.ResourcesGetResourceOptions{URIOptions: []api.URIOption{ + buildResourceHandlerV1Options(r.Event.GitCommitID), + }} + keptnResource, err := r.ResourceAPI.GetResource(context.Background(), *scope, options) + if err != nil { + return nil, fmt.Errorf("unable to fetch resource %s: %w", *serviceResource.ResourceURI, err) + } + + keptnResources[*serviceResource.ResourceURI] = []byte(keptnResource.ResourceContent) + } + } + + return keptnResources, nil +} diff --git a/pkg/keptn/resource_service_test.go b/pkg/keptn/resource_service_test.go index 316e932a..d188b7b7 100644 --- a/pkg/keptn/resource_service_test.go +++ b/pkg/keptn/resource_service_test.go @@ -1,9 +1,10 @@ package keptn import ( + "context" "github.com/golang/mock/gomock" "github.com/keptn/go-utils/pkg/api/models" - api "github.com/keptn/go-utils/pkg/api/utils" + api "github.com/keptn/go-utils/pkg/api/utils/v2" "github.com/stretchr/testify/require" keptnfake "keptn-contrib/job-executor-service/pkg/keptn/fake" "testing" @@ -13,7 +14,7 @@ func TestV1ResourceHandler_GetResource(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() - mockResourceHandler := keptnfake.NewMockV1KeptnResourceHandler(mockCtrl) + mockResourceAPI := keptnfake.NewMockResourcesInterface(mockCtrl) handler := V1ResourceHandler{ Event: EventProperties{ @@ -21,7 +22,7 @@ func TestV1ResourceHandler_GetResource(t *testing.T) { Stage: "stage", Service: "service", }, - ResourceHandler: mockResourceHandler, + ResourceAPI: mockResourceAPI, } tests := []struct { @@ -48,7 +49,7 @@ func TestV1ResourceHandler_GetResource(t *testing.T) { scope.Service("service") scope.Stage("stage") - mockResourceHandler.EXPECT().GetResource(*scope, gomock.Len(1)).Times(1).Return(&models.Resource{ + mockResourceAPI.EXPECT().GetResource(context.Background(), *scope, gomock.Any()).Times(1).Return(&models.Resource{ Metadata: nil, ResourceContent: string(expectedBytes), ResourceURI: nil, @@ -67,7 +68,7 @@ func TestV1ResourceHandler_GetResource(t *testing.T) { scope.Resource("resource") scope.Stage("stage") - mockResourceHandler.EXPECT().GetResource(*scope, gomock.Len(1)).Times(1).Return(&models.Resource{ + mockResourceAPI.EXPECT().GetResource(context.Background(), *scope, gomock.Any()).Times(1).Return(&models.Resource{ Metadata: nil, ResourceContent: string(expectedBytes), ResourceURI: nil, @@ -85,7 +86,7 @@ func TestV1ResourceHandler_GetResource(t *testing.T) { scope.Project("project") scope.Resource("resource") - mockResourceHandler.EXPECT().GetResource(*scope, gomock.Len(1)).Times(1).Return(&models.Resource{ + mockResourceAPI.EXPECT().GetResource(context.Background(), *scope, gomock.Any()).Times(1).Return(&models.Resource{ Metadata: nil, ResourceContent: string(expectedBytes), ResourceURI: nil, diff --git a/test/e2e/gitcommitid_test.go b/test/e2e/gitcommitid_test.go index 1a9dbb21..933e1d61 100644 --- a/test/e2e/gitcommitid_test.go +++ b/test/e2e/gitcommitid_test.go @@ -86,9 +86,9 @@ func TestGitCommitID(t *testing.T) { responseEventData, err := parseKeptnEventData(event) require.NoError(t, err) - // If the log contains the Hello world output from the job, we assume that the log + // If the log contains the output from the job, we assume that the log // was correctly read from the job container and set it as expected message - if strings.Contains(responseEventData.Message, "Hello World") { + if strings.Contains(responseEventData.Message, "Greet the world") { expectedEventData.Message = responseEventData.Message } diff --git a/test/e2e/jobconfig_test.go b/test/e2e/jobconfig_test.go index 4ec417f3..d85a1518 100644 --- a/test/e2e/jobconfig_test.go +++ b/test/e2e/jobconfig_test.go @@ -1,8 +1,9 @@ package e2e import ( + "context" "github.com/keptn/go-utils/pkg/api/models" - api "github.com/keptn/go-utils/pkg/api/utils" + api "github.com/keptn/go-utils/pkg/api/utils/v2" "github.com/stretchr/testify/require" "os" "strings" @@ -40,12 +41,12 @@ func TestJobConfig(t *testing.T) { stageScope.Project(testEnv.EventData.Project) stageScope.Stage("dev") - _, err = testEnv.API.ResourceHandler.CreateResource([]*models.Resource{ + _, err = testEnv.API.ResourceHandler.CreateResource(context.Background(), []*models.Resource{ { ResourceContent: string(stageConfig), ResourceURI: &jobConfigURI, }, - }, *stageScope) + }, *stageScope, api.ResourcesCreateResourceOptions{}) require.NoError(t, err) // Upload the project configuration @@ -55,12 +56,12 @@ func TestJobConfig(t *testing.T) { projectScope := api.NewResourceScope() projectScope.Project(testEnv.EventData.Project) - _, err = testEnv.API.ResourceHandler.CreateResource([]*models.Resource{ + _, err = testEnv.API.ResourceHandler.CreateResource(context.Background(), []*models.Resource{ { ResourceContent: string(projectConfig), ResourceURI: &jobConfigURI, }, - }, *projectScope) + }, *projectScope, api.ResourcesCreateResourceOptions{}) require.NoError(t, err) tests := []struct { diff --git a/test/e2e/keptn.go b/test/e2e/keptn.go index 0d218655..ad5d88f0 100644 --- a/test/e2e/keptn.go +++ b/test/e2e/keptn.go @@ -1,10 +1,12 @@ package e2e import ( + "context" "encoding/base64" "fmt" "github.com/keptn/go-utils/pkg/api/models" - api "github.com/keptn/go-utils/pkg/api/utils" + api "github.com/keptn/go-utils/pkg/api/utils/v2" + "log" "net/http" "net/url" ) @@ -16,10 +18,10 @@ const jobResourceURI = "job/config.yaml" // KeptnAPI structure holds different api handlers for the keptn api such that they can be used more easily type KeptnAPI struct { httpClient *http.Client - APIHandler *api.APIHandler - ProjectHandler *api.ProjectHandler - ResourceHandler *api.ResourceHandler - EventHandler *api.EventHandler + APIHandler api.APIInterface + ProjectHandler api.ProjectsInterface + ResourceHandler api.ResourcesInterface + EventHandler api.EventsInterface } // NewKeptnAPI creates a KeptnAPI structure from KeptnConnectionDetails @@ -36,24 +38,41 @@ func NewKeptnAPI(details KeptnConnectionDetails) (*KeptnAPI, error) { endpointScheme = endpointURL.Scheme } + apiOptions := []func(*api.APISet){ + api.WithScheme(endpointScheme), + api.WithAuthToken(details.APIToken, "x-token"), + } + + // Create the API from the defined options and the URL + keptnAPI, err := api.New(endpointURL.String(), apiOptions...) + if err != nil { + log.Fatalf("unable to create keptn API: %s", err) + } + + apiHandler := keptnAPI.API() + projectHandler := keptnAPI.Projects() + resourceHandler := keptnAPI.Resources() + eventHandler := keptnAPI.Events() + return &KeptnAPI{ httpClient: &httpClient, - APIHandler: api.NewAuthenticatedAPIHandler(details.Endpoint, details.APIToken, authHeaderName, &httpClient, endpointScheme), - ProjectHandler: api.NewAuthenticatedProjectHandler(details.Endpoint, details.APIToken, authHeaderName, &httpClient, endpointScheme), - ResourceHandler: api.NewAuthenticatedResourceHandler(details.Endpoint, details.APIToken, authHeaderName, &httpClient, endpointScheme), - EventHandler: api.NewAuthenticatedEventHandler(details.Endpoint, details.APIToken, authHeaderName, &httpClient, endpointScheme), + APIHandler: apiHandler, + ProjectHandler: projectHandler, + ResourceHandler: resourceHandler, + EventHandler: eventHandler, }, nil } // CreateProject creates a keptn project from the contents of a shipyard yaml file func (k KeptnAPI) CreateProject(projectName string, shipyardYAML []byte) error { + ctx := context.Background() shipyardFileBase64 := base64.StdEncoding.EncodeToString(shipyardYAML) - _, err := k.APIHandler.CreateProject(models.CreateProject{ + _, err := k.APIHandler.CreateProject(ctx, models.CreateProject{ Name: &projectName, Shipyard: &shipyardFileBase64, - }) + }, api.APICreateProjectOptions{}) if err != nil { return fmt.Errorf("unable to create project: %s", convertKeptnModelToErrorString(err)) @@ -64,9 +83,9 @@ func (k KeptnAPI) CreateProject(projectName string, shipyardYAML []byte) error { // DeleteProject deletes a project by a given name func (k KeptnAPI) DeleteProject(projectName string) error { - _, err := k.APIHandler.DeleteProject(models.Project{ + _, err := k.APIHandler.DeleteProject(context.Background(), models.Project{ ProjectName: projectName, - }) + }, api.APIDeleteProjectOptions{}) if err != nil { return fmt.Errorf("unable to delete project: %s", convertKeptnModelToErrorString(err)) @@ -77,9 +96,9 @@ func (k KeptnAPI) DeleteProject(projectName string) error { // CreateService creates a service in a given project func (k KeptnAPI) CreateService(projectName string, serviceName string) error { - _, err := k.APIHandler.CreateService(projectName, models.CreateService{ + _, err := k.APIHandler.CreateService(context.Background(), projectName, models.CreateService{ ServiceName: &serviceName, - }) + }, api.APICreateServiceOptions{}) if err != nil { return fmt.Errorf("unable to create service %s in project %s: %s", serviceName, projectName, convertKeptnModelToErrorString(err)) @@ -95,16 +114,16 @@ func (k KeptnAPI) CreateJobConfig(projectName string, stageName string, serviceN // AddServiceResource uploads a resource to a specific service and stage func (k KeptnAPI) AddServiceResource(projectName string, stageName string, serviceName string, path string, data string) error { - _, err := k.ResourceHandler.CreateServiceResources(projectName, stageName, serviceName, []*models.Resource{ + _, err := k.ResourceHandler.CreateResources(context.Background(), projectName, stageName, serviceName, []*models.Resource{ { Metadata: nil, ResourceContent: data, ResourceURI: &path, }, - }) + }, api.ResourcesCreateResourcesOptions{}) if err != nil { - return fmt.Errorf("unable to create service resource for service %s in project %s: %s", serviceName, projectName, err) + return fmt.Errorf("unable to create service resource for service %s in project %s: %s", serviceName, projectName, *err.Message) } return nil @@ -112,7 +131,7 @@ func (k KeptnAPI) AddServiceResource(projectName string, stageName string, servi // SendEvent sends an event to Keptn func (k KeptnAPI) SendEvent(keptnEvent *models.KeptnContextExtendedCE) (*models.EventContext, error) { - keptnContext, err := k.APIHandler.SendEvent(*keptnEvent) + keptnContext, err := k.APIHandler.SendEvent(context.Background(), *keptnEvent, api.APISendEventOptions{}) if err != nil { return nil, fmt.Errorf("unable to send event: %s", convertKeptnModelToErrorString(err)) @@ -127,7 +146,7 @@ func (k KeptnAPI) GetEvents(keptnContext *string) ([]*models.KeptnContextExtende KeptnContext: *keptnContext, } - events, err := k.EventHandler.GetEvents(&eventFilter) + events, err := k.EventHandler.GetEvents(context.Background(), &eventFilter, api.EventsGetEventsOptions{}) if err != nil { return nil, fmt.Errorf("unable to get events: %s", convertKeptnModelToErrorString(err)) } diff --git a/test/e2e/noingress_test.go b/test/e2e/noingress_test.go index c6de65b0..ef8d1466 100644 --- a/test/e2e/noingress_test.go +++ b/test/e2e/noingress_test.go @@ -100,6 +100,7 @@ func TestJobExecutorServiceNoIngress(t *testing.T) { require.NoError(t, err) // exit code 7 from curl signals that the connection to the host has failed + t.Logf("Container termination logs : %s", completedPod.Status.ContainerStatuses[0].State.Terminated.String()) assert.Equal(t, int32(7), completedPod.Status.ContainerStatuses[0].State.Terminated.ExitCode) } diff --git a/test/e2e/utils.go b/test/e2e/utils.go index d1257fab..385f0d25 100644 --- a/test/e2e/utils.go +++ b/test/e2e/utils.go @@ -14,6 +14,7 @@ import ( "github.com/Masterminds/semver/v3" "github.com/keptn/go-utils/pkg/api/models" + api "github.com/keptn/go-utils/pkg/api/utils/v2" "github.com/mitchellh/mapstructure" "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" @@ -248,7 +249,7 @@ func (env testEnvironment) Cleanup() error { // GetKeptnVersion returns the current version of the Keptn server as semver func (env testEnvironment) GetKeptnVersion() (*semver.Version, error) { - metadata, errModel := env.API.APIHandler.GetMetadata() + metadata, errModel := env.API.APIHandler.GetMetadata(context.Background(), api.APIGetMetadataOptions{}) if errModel != nil { return nil, fmt.Errorf("unable to query keptn metadata: %s", convertKeptnModelToErrorString(errModel)) }