From 483a461aaade2dcf32abd3cb6e2553ba6f69d718 Mon Sep 17 00:00:00 2001 From: Jalander Ramagiri Date: Mon, 15 May 2023 16:28:55 +0100 Subject: [PATCH 01/14] feat(cdevents-notification): Implementing produce CDEvents using Notification agent --- echo-notifications/echo-notifications.gradle | 1 + .../echo/cdevents/CDEventsBuilderService.java | 198 ++++++++++++++++++ .../echo/cdevents/CDEventsSenderService.java | 82 ++++++++ .../CDEventsNotificationAgent.java | 84 ++++++++ 4 files changed, 365 insertions(+) create mode 100644 echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java create mode 100644 echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java create mode 100644 echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java diff --git a/echo-notifications/echo-notifications.gradle b/echo-notifications/echo-notifications.gradle index d3f6ae944..b0070b7bf 100644 --- a/echo-notifications/echo-notifications.gradle +++ b/echo-notifications/echo-notifications.gradle @@ -34,6 +34,7 @@ dependencies { implementation "org.jsoup:jsoup:1.8.3" implementation "com.atlassian.commonmark:commonmark:0.9.0" implementation "org.codehaus.groovy:groovy-json" + implementation ("dev.cdevents:cdevents-sdk-java:0.1.2-SNAPSHOT") testImplementation("com.icegreen:greenmail:1.5.14") { exclude group: "com.sun.mail", module: "javax.mail" } diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java new file mode 100644 index 000000000..daf0494f2 --- /dev/null +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java @@ -0,0 +1,198 @@ +/* + Copyright (C) 2023 Nordix Foundation. + For a full list of individual contributors, please see the commit history. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + SPDX-License-Identifier: Apache-2.0 +*/ + +package com.netflix.spinnaker.echo.cdevents; + +import com.netflix.spinnaker.echo.api.events.Event; +import dev.cdevents.CDEvents; +import dev.cdevents.constants.CDEventConstants; +import dev.cdevents.events.*; +import dev.cdevents.exception.CDEventsException; +import io.cloudevents.CloudEvent; +import java.net.URI; +import java.util.Map; +import java.util.Optional; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class CDEventsBuilderService { + + public CloudEvent createCDEvent( + Map preference, + String application, + Event event, + Map config, + String status, + String spinnakerUrl) { + + String configType = Optional.ofNullable(config).map(c -> (String) c.get("type")).orElse(null); + String configLink = Optional.ofNullable(config).map(c -> (String) c.get("link")).orElse(null); + + String executionId = + Optional.ofNullable(event.content) + .map(e -> (Map) e.get("execution")) + .map(e -> (String) e.get("id")) + .orElse(null); + + String executionUrl = + String.format( + "%s/#/applications/%s/%s/%s", + spinnakerUrl, + application, + configType == "stage" ? "executions/details" : configLink, + executionId); + + String executionName = + Optional.ofNullable(event.content) + .map(e -> (Map) e.get("execution")) + .map(e -> (String) e.get("name")) + .orElse(null); + + String cdEventType = + Optional.ofNullable(preference).map(p -> (String) p.get("cdEventType")).orElse(null); + + CloudEvent ceToSend = + buildCloudEventWithCDEventType( + cdEventType, executionId, executionUrl, executionName, spinnakerUrl, status); + if (ceToSend == null) { + log.error("Failed to created CDEvent with type {} as CloudEvent", cdEventType); + throw new CDEventsException("Failed to created CDEvent as CloudEvent"); + } + return ceToSend; + } + + private CloudEvent buildCloudEventWithCDEventType( + String cdEventType, + String executionId, + String executionUrl, + String executionName, + String spinnakerUrl, + String status) { + CloudEvent ceToSend = null; + switch (cdEventType) { + case "dev.cdevents.pipelinerun.queued": + ceToSend = + createPipelineRunQueuedEvent(executionId, executionUrl, executionName, spinnakerUrl); + break; + case "dev.cdevents.pipelinerun.started": + ceToSend = + createPipelineRunStartedEvent(executionId, executionUrl, executionName, spinnakerUrl); + break; + case "dev.cdevents.pipelinerun.finished": + ceToSend = + createPipelineRunFinishedEvent( + executionId, executionUrl, executionName, spinnakerUrl, status); + break; + case "dev.cdevents.taskrun.started": + ceToSend = + createTaskRunStartedEvent(executionId, executionUrl, executionName, spinnakerUrl); + break; + case "dev.cdevents.taskrun.finished": + ceToSend = + createTaskRunFinishedEvent( + executionId, executionUrl, executionName, spinnakerUrl, status); + break; + default: + throw new CDEventsException( + "Invalid CDEvent Type " + cdEventType + " provided to create CDEvent"); + } + return ceToSend; + } + + private CloudEvent createTaskRunFinishedEvent( + String executionId, + String executionUrl, + String executionName, + String spinnakerUrl, + String status) { + TaskRunFinishedCDEvent cdEvent = new TaskRunFinishedCDEvent(); + cdEvent.setSource(URI.create(spinnakerUrl)); + + cdEvent.setSubjectId(executionId); + cdEvent.setSubjectSource(URI.create(spinnakerUrl)); + cdEvent.setSubjectTaskName(executionName); + cdEvent.setSubjectUrl(URI.create(executionUrl)); + cdEvent.setSubjectErrors(status); + if (status.equals("complete")) { + cdEvent.setSubjectOutcome(CDEventConstants.Outcome.SUCCESS); + } else if (status.equals("failed")) { + cdEvent.setSubjectOutcome(CDEventConstants.Outcome.FAILURE); + } + return CDEvents.cdEventAsCloudEvent(cdEvent); + } + + private CloudEvent createTaskRunStartedEvent( + String executionId, String executionUrl, String executionName, String spinnakerUrl) { + TaskRunStartedCDEvent cdEvent = new TaskRunStartedCDEvent(); + cdEvent.setSource(URI.create(spinnakerUrl)); + + cdEvent.setSubjectId(executionId); + cdEvent.setSubjectSource(URI.create(spinnakerUrl)); + cdEvent.setSubjectTaskName(executionName); + cdEvent.setSubjectUrl(URI.create(executionUrl)); + + return CDEvents.cdEventAsCloudEvent(cdEvent); + } + + private CloudEvent createPipelineRunFinishedEvent( + String executionId, + String executionUrl, + String executionName, + String spinnakerUrl, + String status) { + PipelineRunFinishedCDEvent cdEvent = new PipelineRunFinishedCDEvent(); + cdEvent.setSource(URI.create(spinnakerUrl)); + cdEvent.setSubjectId(executionId); + cdEvent.setSubjectSource(URI.create(spinnakerUrl)); + cdEvent.setSubjectPipelineName(executionName); + cdEvent.setSubjectUrl(URI.create(executionUrl)); + cdEvent.setSubjectErrors(status); + + if (status.equals("complete")) { + cdEvent.setSubjectOutcome(CDEventConstants.Outcome.SUCCESS); + } else if (status.equals("failed")) { + cdEvent.setSubjectOutcome(CDEventConstants.Outcome.FAILURE); + } + + return CDEvents.cdEventAsCloudEvent(cdEvent); + } + + private CloudEvent createPipelineRunStartedEvent( + String executionId, String executionUrl, String executionName, String spinnakerUrl) { + PipelineRunStartedCDEvent cdEvent = new PipelineRunStartedCDEvent(); + cdEvent.setSource(URI.create(spinnakerUrl)); + cdEvent.setSubjectId(executionId); + cdEvent.setSubjectSource(URI.create(spinnakerUrl)); + cdEvent.setSubjectPipelineName(executionName); + cdEvent.setSubjectUrl(URI.create(executionUrl)); + + return CDEvents.cdEventAsCloudEvent(cdEvent); + } + + private CloudEvent createPipelineRunQueuedEvent( + String executionId, String executionUrl, String executionName, String spinnakerUrl) { + PipelineRunQueuedCDEvent cdEvent = new PipelineRunQueuedCDEvent(); + cdEvent.setSource(URI.create(spinnakerUrl)); + cdEvent.setSubjectId(executionId); + cdEvent.setSubjectSource(URI.create(spinnakerUrl)); + cdEvent.setSubjectPipelineName(executionName); + cdEvent.setSubjectUrl(URI.create(executionUrl)); + + return CDEvents.cdEventAsCloudEvent(cdEvent); + } +} diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java new file mode 100644 index 000000000..0e6466cdf --- /dev/null +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java @@ -0,0 +1,82 @@ +/* + Copyright (C) 2023 Nordix Foundation. + For a full list of individual contributors, please see the commit history. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + SPDX-License-Identifier: Apache-2.0 +*/ +package com.netflix.spinnaker.echo.cdevents; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.message.MessageWriter; +import io.cloudevents.http.HttpMessageFactory; +import java.io.IOException; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.net.HttpURLConnection; +import java.net.URL; +import org.springframework.stereotype.Component; + +@Component +public class CDEventsSenderService { + + /** + * Sends CDEvent to the Configured ClouEvent broker URL. + * + * @param ceToSend + * @param url + * @return HttpURLConnection + * @throws IOException + */ + public HttpURLConnection sendCDEvent(CloudEvent ceToSend, URL url) throws IOException { + HttpURLConnection httpUrlConnection = createConnection(url); + MessageWriter messageWriter = createMessageWriter(httpUrlConnection); + messageWriter.writeBinary(ceToSend); + + return httpUrlConnection; + } + + /** + * @param url + * @return httpUrlConnection + * @throws IOException + */ + private HttpURLConnection createConnection(URL url) throws IOException { + HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection(); + httpUrlConnection.setRequestMethod("POST"); + httpUrlConnection.setDoOutput(true); + httpUrlConnection.setDoInput(true); + return httpUrlConnection; + } + + /** + * @param httpUrlConnection + * @return messageWriter + */ + private MessageWriter createMessageWriter(HttpURLConnection httpUrlConnection) { + return HttpMessageFactory.createWriter( + httpUrlConnection::setRequestProperty, + body -> { + try { + if (body != null) { + httpUrlConnection.setRequestProperty("content-length", String.valueOf(body.length)); + try (OutputStream outputStream = httpUrlConnection.getOutputStream()) { + outputStream.write(body); + } + } else { + httpUrlConnection.setRequestProperty("content-length", "0"); + } + } catch (IOException t) { + throw new UncheckedIOException(t); + } + }); + } +} diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java new file mode 100644 index 000000000..07dc473ea --- /dev/null +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java @@ -0,0 +1,84 @@ +/* + * Copyright 2020 Cerner Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.echo.notification; + +import com.netflix.spinnaker.echo.api.events.Event; +import com.netflix.spinnaker.echo.cdevents.CDEventsBuilderService; +import com.netflix.spinnaker.echo.cdevents.CDEventsSenderService; +import dev.cdevents.exception.CDEventsException; +import io.cloudevents.CloudEvent; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Map; +import java.util.Optional; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; +import retrofit.mime.TypedByteArray; + +@Slf4j +@ConditionalOnProperty("cdevents.enabled") +@Service +public class CDEventsNotificationAgent extends AbstractEventNotificationAgent { + @Autowired CDEventsBuilderService cdEventsBuilderService; + @Autowired CDEventsSenderService cdEventsSenderService; + + @Override + public String getNotificationType() { + return "cdevents"; + } + + @Override + public void sendNotifications( + Map preference, + String application, + Event event, + Map config, + String status) { + log.info("Sending CDEvents notification.."); + + String executionId = + Optional.ofNullable(event.content) + .map(e -> (Map) e.get("execution")) + .map(e -> (String) e.get("id")) + .orElse(null); + String cdEventType = + Optional.ofNullable(preference).map(p -> (String) p.get("cdEventType")).orElse(null); + String eventsBrokerUrl = + Optional.ofNullable(preference).map(p -> (String) p.get("address")).orElse(null); + + try { + CloudEvent ceToSend = + cdEventsBuilderService.createCDEvent( + preference, application, event, config, status, getSpinnakerUrl()); + log.info( + "Sending CDEvent {} notification to events broker url {}", cdEventType, eventsBrokerUrl); + HttpURLConnection response = + cdEventsSenderService.sendCDEvent(ceToSend, new URL(eventsBrokerUrl)); + log.info( + "Received response from events broker : {} {} for execution id {}. {}", + response.getResponseCode(), + response.getResponseMessage(), + executionId, + new String(((TypedByteArray) response.getContent()).getBytes())); + } catch (Exception e) { + log.error("Exception occurred while sending CDEvent {}", e); + throw new CDEventsException("Exception occurred while sending CDEvent", e); + } + } +} From 3b759eeef62c5981934ff259b2b94dc1cf59b16f Mon Sep 17 00:00:00 2001 From: Jalander Ramagiri Date: Tue, 16 May 2023 09:13:23 +0100 Subject: [PATCH 02/14] feat(cdevents-notification): unit tests to produce CDEvents using Notification --- echo-notifications/echo-notifications.gradle | 1 + .../CDEventsNotificationAgent.java | 15 +++-- .../CDEventsNotificationAgentSpec.groovy | 66 +++++++++++++++++++ 3 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 echo-notifications/src/test/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgentSpec.groovy diff --git a/echo-notifications/echo-notifications.gradle b/echo-notifications/echo-notifications.gradle index b0070b7bf..99f829580 100644 --- a/echo-notifications/echo-notifications.gradle +++ b/echo-notifications/echo-notifications.gradle @@ -34,6 +34,7 @@ dependencies { implementation "org.jsoup:jsoup:1.8.3" implementation "com.atlassian.commonmark:commonmark:0.9.0" implementation "org.codehaus.groovy:groovy-json" + implementation "io.cloudevents:cloudevents-http-basic:2.3.0" implementation ("dev.cdevents:cdevents-sdk-java:0.1.2-SNAPSHOT") testImplementation("com.icegreen:greenmail:1.5.14") { exclude group: "com.sun.mail", module: "javax.mail" diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java index 07dc473ea..39cdd215b 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java @@ -70,12 +70,15 @@ public void sendNotifications( "Sending CDEvent {} notification to events broker url {}", cdEventType, eventsBrokerUrl); HttpURLConnection response = cdEventsSenderService.sendCDEvent(ceToSend, new URL(eventsBrokerUrl)); - log.info( - "Received response from events broker : {} {} for execution id {}. {}", - response.getResponseCode(), - response.getResponseMessage(), - executionId, - new String(((TypedByteArray) response.getContent()).getBytes())); + if (response != null) { + log.info( + "Received response from events broker : {} {} for execution id {}. {}", + response.getResponseCode(), + response.getResponseMessage(), + executionId, + new String(((TypedByteArray) response.getContent()).getBytes())); + } + } catch (Exception e) { log.error("Exception occurred while sending CDEvent {}", e); throw new CDEventsException("Exception occurred while sending CDEvent", e); diff --git a/echo-notifications/src/test/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgentSpec.groovy b/echo-notifications/src/test/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgentSpec.groovy new file mode 100644 index 000000000..5b31ef189 --- /dev/null +++ b/echo-notifications/src/test/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgentSpec.groovy @@ -0,0 +1,66 @@ +/* + * Copyright 2016 Google, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.echo.notification + +import com.netflix.spinnaker.echo.api.events.Event +import com.netflix.spinnaker.echo.cdevents.CDEventsBuilderService +import com.netflix.spinnaker.echo.cdevents.CDEventsSenderService +import io.cloudevents.CloudEvent +import spock.lang.Specification +import spock.lang.Subject +import spock.lang.Unroll +import spock.util.concurrent.BlockingVariable + +class CDEventsNotificationAgentSpec extends Specification { + + def cdEventsBuilder = new CDEventsBuilderService(); + + def cdeventsSender = Mock(CDEventsSenderService) + @Subject + def agent = new CDEventsNotificationAgent(cdEventsSenderService: cdeventsSender, cdEventsBuilderService: cdEventsBuilder, spinnakerUrl: 'http://spinnaker') + + @Unroll + def "sends CDEvent of type #cdEventType when pipeline status has #status"() { + given: + def cdevent = new BlockingVariable() + cdeventsSender.sendCDEvent(*_) >> { ceToSend, eventsBrokerURL -> + cdevent.set(ceToSend) + } + + when: + agent.sendNotifications([address: brokerURL, cdEventType: cdEventType], application, event, [type: type, link: "link"], status) + + then: + cdevent.get().getType() ==~ expectedType + + where: + cdEventType || expectedType || status + "dev.cdevents.pipelinerun.queued" || /dev.cdevents.pipelinerun.queued.0.1.0/ || /starting/ + "dev.cdevents.pipelinerun.started" || /dev.cdevents.pipelinerun.started.0.1.0/ || /started/ + "dev.cdevents.pipelinerun.finished" || /dev.cdevents.pipelinerun.finished.0.1.0/ || /complete/ + "dev.cdevents.taskrun.started" || /dev.cdevents.taskrun.started.0.1.0/ || /started/ + "dev.cdevents.taskrun.finished" || /dev.cdevents.taskrun.finished.0.1.0/ || /complete/ + + + brokerURL = "http://dev.cdevents.server/default/events-broker" + application = "whatever" + event = new Event(content: [ + execution: [id: "1", name: "foo-pipeline"] + ]) + type = "pipeline" + } +} From 576e7d145ab9bf6fae2346a9aad1ee8ad22d82e1 Mon Sep 17 00:00:00 2001 From: Jalander Ramagiri Date: Tue, 16 May 2023 11:04:21 +0100 Subject: [PATCH 03/14] feat(cdevents-notification): update variable name to cdEventsType --- .../echo/cdevents/CDEventsBuilderService.java | 14 +++++++------- .../notification/CDEventsNotificationAgent.java | 6 +++--- .../CDEventsNotificationAgentSpec.groovy | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java index daf0494f2..29220313f 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java @@ -63,28 +63,28 @@ public CloudEvent createCDEvent( .map(e -> (String) e.get("name")) .orElse(null); - String cdEventType = - Optional.ofNullable(preference).map(p -> (String) p.get("cdEventType")).orElse(null); + String cdEventsType = + Optional.ofNullable(preference).map(p -> (String) p.get("cdEventsType")).orElse(null); CloudEvent ceToSend = buildCloudEventWithCDEventType( - cdEventType, executionId, executionUrl, executionName, spinnakerUrl, status); + cdEventsType, executionId, executionUrl, executionName, spinnakerUrl, status); if (ceToSend == null) { - log.error("Failed to created CDEvent with type {} as CloudEvent", cdEventType); + log.error("Failed to created CDEvent with type {} as CloudEvent", cdEventsType); throw new CDEventsException("Failed to created CDEvent as CloudEvent"); } return ceToSend; } private CloudEvent buildCloudEventWithCDEventType( - String cdEventType, + String cdEventsType, String executionId, String executionUrl, String executionName, String spinnakerUrl, String status) { CloudEvent ceToSend = null; - switch (cdEventType) { + switch (cdEventsType) { case "dev.cdevents.pipelinerun.queued": ceToSend = createPipelineRunQueuedEvent(executionId, executionUrl, executionName, spinnakerUrl); @@ -109,7 +109,7 @@ private CloudEvent buildCloudEventWithCDEventType( break; default: throw new CDEventsException( - "Invalid CDEvent Type " + cdEventType + " provided to create CDEvent"); + "Invalid CDEvents Type " + cdEventsType + " provided to create CDEvent"); } return ceToSend; } diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java index 39cdd215b..dafde6d38 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java @@ -57,8 +57,8 @@ public void sendNotifications( .map(e -> (Map) e.get("execution")) .map(e -> (String) e.get("id")) .orElse(null); - String cdEventType = - Optional.ofNullable(preference).map(p -> (String) p.get("cdEventType")).orElse(null); + String cdEventsType = + Optional.ofNullable(preference).map(p -> (String) p.get("cdEventsType")).orElse(null); String eventsBrokerUrl = Optional.ofNullable(preference).map(p -> (String) p.get("address")).orElse(null); @@ -67,7 +67,7 @@ public void sendNotifications( cdEventsBuilderService.createCDEvent( preference, application, event, config, status, getSpinnakerUrl()); log.info( - "Sending CDEvent {} notification to events broker url {}", cdEventType, eventsBrokerUrl); + "Sending CDEvent {} notification to events broker url {}", cdEventsType, eventsBrokerUrl); HttpURLConnection response = cdEventsSenderService.sendCDEvent(ceToSend, new URL(eventsBrokerUrl)); if (response != null) { diff --git a/echo-notifications/src/test/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgentSpec.groovy b/echo-notifications/src/test/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgentSpec.groovy index 5b31ef189..77dd4e97a 100644 --- a/echo-notifications/src/test/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgentSpec.groovy +++ b/echo-notifications/src/test/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgentSpec.groovy @@ -34,7 +34,7 @@ class CDEventsNotificationAgentSpec extends Specification { def agent = new CDEventsNotificationAgent(cdEventsSenderService: cdeventsSender, cdEventsBuilderService: cdEventsBuilder, spinnakerUrl: 'http://spinnaker') @Unroll - def "sends CDEvent of type #cdEventType when pipeline status has #status"() { + def "sends CDEvent of type #cdEventsType when pipeline status has #status"() { given: def cdevent = new BlockingVariable() cdeventsSender.sendCDEvent(*_) >> { ceToSend, eventsBrokerURL -> @@ -42,13 +42,13 @@ class CDEventsNotificationAgentSpec extends Specification { } when: - agent.sendNotifications([address: brokerURL, cdEventType: cdEventType], application, event, [type: type, link: "link"], status) + agent.sendNotifications([address: brokerURL, cdEventsType: cdEventsType], application, event, [type: type, link: "link"], status) then: cdevent.get().getType() ==~ expectedType where: - cdEventType || expectedType || status + cdEventsType || expectedType || status "dev.cdevents.pipelinerun.queued" || /dev.cdevents.pipelinerun.queued.0.1.0/ || /starting/ "dev.cdevents.pipelinerun.started" || /dev.cdevents.pipelinerun.started.0.1.0/ || /started/ "dev.cdevents.pipelinerun.finished" || /dev.cdevents.pipelinerun.finished.0.1.0/ || /complete/ From de76a8c659363acf7e974a039284f78a2987be69 Mon Sep 17 00:00:00 2001 From: Jalander Ramagiri Date: Wed, 26 Jul 2023 09:59:36 +0100 Subject: [PATCH 04/14] Updating cdevents-sdk-java dependency version Signed-off-by: Jalander Ramagiri --- echo-notifications/echo-notifications.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/echo-notifications/echo-notifications.gradle b/echo-notifications/echo-notifications.gradle index 99f829580..4a43e8193 100644 --- a/echo-notifications/echo-notifications.gradle +++ b/echo-notifications/echo-notifications.gradle @@ -35,7 +35,7 @@ dependencies { implementation "com.atlassian.commonmark:commonmark:0.9.0" implementation "org.codehaus.groovy:groovy-json" implementation "io.cloudevents:cloudevents-http-basic:2.3.0" - implementation ("dev.cdevents:cdevents-sdk-java:0.1.2-SNAPSHOT") + implementation ("dev.cdevents:cdevents-sdk-java:0.1.2") testImplementation("com.icegreen:greenmail:1.5.14") { exclude group: "com.sun.mail", module: "javax.mail" } From 02a661082aaa1f740f791f53eb730efce635342d Mon Sep 17 00:00:00 2001 From: Jalander Ramagiri Date: Wed, 26 Jul 2023 16:51:08 +0100 Subject: [PATCH 05/14] fix: unit test failure with sdk --- .../netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java index 29220313f..d1caa6b55 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java @@ -128,6 +128,7 @@ private CloudEvent createTaskRunFinishedEvent( cdEvent.setSubjectTaskName(executionName); cdEvent.setSubjectUrl(URI.create(executionUrl)); cdEvent.setSubjectErrors(status); + cdEvent.setSubjectPipelineRunId(executionId); if (status.equals("complete")) { cdEvent.setSubjectOutcome(CDEventConstants.Outcome.SUCCESS); } else if (status.equals("failed")) { @@ -145,6 +146,7 @@ private CloudEvent createTaskRunStartedEvent( cdEvent.setSubjectSource(URI.create(spinnakerUrl)); cdEvent.setSubjectTaskName(executionName); cdEvent.setSubjectUrl(URI.create(executionUrl)); + cdEvent.setSubjectPipelineRunId(executionId); return CDEvents.cdEventAsCloudEvent(cdEvent); } From 64705463a0854b090ce08606c7e1c62e06e02920 Mon Sep 17 00:00:00 2001 From: Jalander Ramagiri Date: Thu, 12 Oct 2023 15:26:57 +0100 Subject: [PATCH 06/14] using retrofit to send cdevent --- echo-notifications/echo-notifications.gradle | 3 +- .../CDEventsHTTPMessageConverter.java | 91 ++++++++++++ .../echo/cdevents/CDEventsSenderClient.java | 27 ++++ .../echo/cdevents/CDEventsSenderService.java | 130 +++++++++++------- .../CDEventsNotificationAgent.java | 23 ++-- 5 files changed, 210 insertions(+), 64 deletions(-) create mode 100644 echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsHTTPMessageConverter.java create mode 100644 echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderClient.java diff --git a/echo-notifications/echo-notifications.gradle b/echo-notifications/echo-notifications.gradle index 4a43e8193..d52921dda 100644 --- a/echo-notifications/echo-notifications.gradle +++ b/echo-notifications/echo-notifications.gradle @@ -34,7 +34,8 @@ dependencies { implementation "org.jsoup:jsoup:1.8.3" implementation "com.atlassian.commonmark:commonmark:0.9.0" implementation "org.codehaus.groovy:groovy-json" - implementation "io.cloudevents:cloudevents-http-basic:2.3.0" + implementation "io.cloudevents:cloudevents-http-basic:2.5.0" + implementation "io.cloudevents:cloudevents-json-jackson:2.5.0" implementation ("dev.cdevents:cdevents-sdk-java:0.1.2") testImplementation("com.icegreen:greenmail:1.5.14") { exclude group: "com.sun.mail", module: "javax.mail" diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsHTTPMessageConverter.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsHTTPMessageConverter.java new file mode 100644 index 000000000..1b19078bf --- /dev/null +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsHTTPMessageConverter.java @@ -0,0 +1,91 @@ +/* + Copyright (C) 2023 Nordix Foundation. + For a full list of individual contributors, please see the commit history. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + SPDX-License-Identifier: Apache-2.0 +*/ + +package com.netflix.spinnaker.echo.cdevents; + + +import com.netflix.spinnaker.kork.web.exceptions.InvalidRequestException; +import io.cloudevents.CloudEvent; +import io.cloudevents.jackson.JsonFormat; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import retrofit.converter.ConversionException; +import retrofit.converter.Converter; +import retrofit.mime.TypedByteArray; +import retrofit.mime.TypedInput; +import retrofit.mime.TypedOutput; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Type; + +import static com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_EMPTY_BEANS; + +public class CDEventsHTTPMessageConverter implements Converter { + + private final ObjectMapper objectMapper; + + private static final String MIME_TYPE = "application/json"; + public CDEventsHTTPMessageConverter(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + public static CDEventsHTTPMessageConverter create() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(JsonFormat.getCloudEventJacksonModule()); + objectMapper.disable(FAIL_ON_EMPTY_BEANS); + return new CDEventsHTTPMessageConverter(objectMapper); + } + + public String convertCDEventToJson(CloudEvent cdEvent) { + try { + return objectMapper.writeValueAsString(cdEvent); + } catch (JsonProcessingException e) { + throw new InvalidRequestException( + "Unable to convert CDEvent to Json format.", e); + } + } + @Override public Object fromBody(TypedInput body, Type type) throws ConversionException { + try { + JavaType javaType = objectMapper.getTypeFactory().constructType(type); + return objectMapper.readValue(body.in(), javaType); + } catch (JsonParseException e) { + throw new ConversionException(e); + } catch (JsonMappingException e) { + throw new ConversionException(e); + } catch (IOException e) { + throw new ConversionException(e); + } + } + + @Override public TypedOutput toBody(Object object) { + try { + String json = objectMapper.writeValueAsString(object); + return new TypedByteArray(MIME_TYPE, json.getBytes("UTF-8")); + } catch (JsonProcessingException e) { + throw new AssertionError(e); + } catch (UnsupportedEncodingException e) { + throw new AssertionError(e); + } + } +} + + + + diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderClient.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderClient.java new file mode 100644 index 000000000..acd4921eb --- /dev/null +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderClient.java @@ -0,0 +1,27 @@ +/* + Copyright (C) 2023 Nordix Foundation. + For a full list of individual contributors, please see the commit history. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + SPDX-License-Identifier: Apache-2.0 +*/ + +package com.netflix.spinnaker.echo.cdevents; + +import retrofit.client.Response; +import retrofit.http.*; + +public interface CDEventsSenderClient { + @POST("/{brokerUrl}") + Response sendCDEvent( + @Body String cdEvent, + @Path(value = "brokerUrl", encode = false) String brokerUrl); +} diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java index 0e6466cdf..5d275c909 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java @@ -13,70 +13,96 @@ SPDX-License-Identifier: Apache-2.0 */ + package com.netflix.spinnaker.echo.cdevents; +import com.netflix.spinnaker.kork.web.exceptions.InvalidRequestException; +import com.netflix.spinnaker.retrofit.Slf4jRetrofitLogger; import io.cloudevents.CloudEvent; -import io.cloudevents.core.message.MessageWriter; -import io.cloudevents.http.HttpMessageFactory; -import java.io.IOException; -import java.io.OutputStream; -import java.io.UncheckedIOException; -import java.net.HttpURLConnection; -import java.net.URL; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; +import retrofit.RequestInterceptor; +import retrofit.RestAdapter; +import retrofit.client.Client; +import retrofit.client.Response; +import io.cloudevents.jackson.JsonFormat; +import java.net.MalformedURLException; +import java.net.URL; + +@Slf4j @Component public class CDEventsSenderService { + private Client retrofitClient; + private RestAdapter.LogLevel retrofitLogLevel; + + public CDEventsSenderService(Client retrofitClient, RestAdapter.LogLevel retrofitLogLevel) { + this.retrofitClient = retrofitClient; + this.retrofitLogLevel = retrofitLogLevel; + } - /** - * Sends CDEvent to the Configured ClouEvent broker URL. - * - * @param ceToSend - * @param url - * @return HttpURLConnection - * @throws IOException - */ - public HttpURLConnection sendCDEvent(CloudEvent ceToSend, URL url) throws IOException { - HttpURLConnection httpUrlConnection = createConnection(url); - MessageWriter messageWriter = createMessageWriter(httpUrlConnection); - messageWriter.writeBinary(ceToSend); + public Response sendCDEvent(CloudEvent cdEvent, String eventsBrokerUrl) { + CDEventsHTTPMessageConverter converterFactory = CDEventsHTTPMessageConverter.create(); + RequestInterceptor authInterceptor = new RequestInterceptor() { + @Override + public void intercept(RequestInterceptor.RequestFacade request) { + request.addHeader("Ce-Id", cdEvent.getId()); + request.addHeader("Ce-Specversion", cdEvent.getSpecVersion().V1.toString()); + request.addHeader("Ce-Source", cdEvent.getSource().toString()); + request.addHeader("Ce-Type", cdEvent.getType()); + request.addHeader("Content-Type", "application/json"); + } + }; - return httpUrlConnection; + CDEventsSenderClient cdEventsSenderClient = + new RestAdapter.Builder() + .setConverter(converterFactory) + .setClient(retrofitClient) + .setEndpoint(getEndpointUrl(eventsBrokerUrl)) + .setRequestInterceptor(authInterceptor) + .setLogLevel(retrofitLogLevel) + .setLog(new Slf4jRetrofitLogger(CDEventsSenderClient.class)) + .build() + .create(CDEventsSenderClient.class); + String jsonEvent = converterFactory.convertCDEventToJson(cdEvent); + log.info("Sending CDEvent Json {} ", jsonEvent); + return cdEventsSenderClient.sendCDEvent(jsonEvent, getRelativePath(eventsBrokerUrl)); } - /** - * @param url - * @return httpUrlConnection - * @throws IOException - */ - private HttpURLConnection createConnection(URL url) throws IOException { - HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection(); - httpUrlConnection.setRequestMethod("POST"); - httpUrlConnection.setDoOutput(true); - httpUrlConnection.setDoInput(true); - return httpUrlConnection; + private String getEndpointUrl(String webhookUrl) { + try { + URL url = new URL(webhookUrl); + String endPointURL = url.getPort() != -1 ? url.getProtocol() + "://" + url.getHost() + ":" + url.getPort() + : url.getProtocol() + "://" + url.getHost(); + log.info("endpoint Url to send CDEvent {} ", endPointURL); + return endPointURL; + } catch (MalformedURLException e) { + throw new InvalidRequestException( + "Unable to determine base URL from Microsoft Teams webhook URL.", e); + } } - /** - * @param httpUrlConnection - * @return messageWriter - */ - private MessageWriter createMessageWriter(HttpURLConnection httpUrlConnection) { - return HttpMessageFactory.createWriter( - httpUrlConnection::setRequestProperty, - body -> { - try { - if (body != null) { - httpUrlConnection.setRequestProperty("content-length", String.valueOf(body.length)); - try (OutputStream outputStream = httpUrlConnection.getOutputStream()) { - outputStream.write(body); - } - } else { - httpUrlConnection.setRequestProperty("content-length", "0"); - } - } catch (IOException t) { - throw new UncheckedIOException(t); - } - }); + private String getRelativePath(String webhookUrl) { + String relativePath = ""; + + try { + URL url = new URL(webhookUrl); + relativePath = url.getPath(); + + if (StringUtils.isEmpty(relativePath)) { + throw new MalformedURLException(); + } + } catch (MalformedURLException e) { + throw new InvalidRequestException( + "Unable to determine relative path from Microsoft Teams webhook URL.", e); + } + + // Remove slash from beginning of path as the client will prefix the string with a slash + if (relativePath.charAt(0) == '/') { + relativePath = relativePath.substring(1); + } + + return relativePath; } } diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java index dafde6d38..d690b9798 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java @@ -21,22 +21,23 @@ import com.netflix.spinnaker.echo.cdevents.CDEventsSenderService; import dev.cdevents.exception.CDEventsException; import io.cloudevents.CloudEvent; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.Map; -import java.util.Optional; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; +import retrofit.client.Response; import retrofit.mime.TypedByteArray; +import java.util.Map; +import java.util.Optional; + @Slf4j @ConditionalOnProperty("cdevents.enabled") @Service public class CDEventsNotificationAgent extends AbstractEventNotificationAgent { @Autowired CDEventsBuilderService cdEventsBuilderService; - @Autowired CDEventsSenderService cdEventsSenderService; + @Autowired + CDEventsSenderService cdEventsSenderService; @Override public String getNotificationType() { @@ -63,20 +64,20 @@ public void sendNotifications( Optional.ofNullable(preference).map(p -> (String) p.get("address")).orElse(null); try { - CloudEvent ceToSend = + CloudEvent cdEvent = cdEventsBuilderService.createCDEvent( preference, application, event, config, status, getSpinnakerUrl()); log.info( "Sending CDEvent {} notification to events broker url {}", cdEventsType, eventsBrokerUrl); - HttpURLConnection response = - cdEventsSenderService.sendCDEvent(ceToSend, new URL(eventsBrokerUrl)); + Response response = + cdEventsSenderService.sendCDEvent(cdEvent, eventsBrokerUrl); if (response != null) { log.info( "Received response from events broker : {} {} for execution id {}. {}", - response.getResponseCode(), - response.getResponseMessage(), + response.getStatus(), + response.getReason(), executionId, - new String(((TypedByteArray) response.getContent()).getBytes())); + response.getBody() != null ? new String(((TypedByteArray) response.getBody()).getBytes()) : ""); } } catch (Exception e) { From 65e8b338971e647992db78854d664a6003b54ca6 Mon Sep 17 00:00:00 2001 From: Jalander Ramagiri Date: Thu, 12 Oct 2023 16:14:30 +0100 Subject: [PATCH 07/14] fixing format violations --- .../CDEventsHTTPMessageConverter.java | 31 ++++++++--------- .../echo/cdevents/CDEventsSenderClient.java | 3 +- .../echo/cdevents/CDEventsSenderService.java | 33 ++++++++++--------- .../CDEventsNotificationAgent.java | 15 ++++----- 4 files changed, 39 insertions(+), 43 deletions(-) diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsHTTPMessageConverter.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsHTTPMessageConverter.java index 1b19078bf..40998c198 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsHTTPMessageConverter.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsHTTPMessageConverter.java @@ -16,32 +16,31 @@ package com.netflix.spinnaker.echo.cdevents; +import static com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_EMPTY_BEANS; -import com.netflix.spinnaker.kork.web.exceptions.InvalidRequestException; -import io.cloudevents.CloudEvent; -import io.cloudevents.jackson.JsonFormat; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.netflix.spinnaker.kork.web.exceptions.InvalidRequestException; +import io.cloudevents.CloudEvent; +import io.cloudevents.jackson.JsonFormat; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Type; import retrofit.converter.ConversionException; import retrofit.converter.Converter; import retrofit.mime.TypedByteArray; import retrofit.mime.TypedInput; import retrofit.mime.TypedOutput; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.Type; - -import static com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_EMPTY_BEANS; - public class CDEventsHTTPMessageConverter implements Converter { private final ObjectMapper objectMapper; private static final String MIME_TYPE = "application/json"; + public CDEventsHTTPMessageConverter(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @@ -57,11 +56,12 @@ public String convertCDEventToJson(CloudEvent cdEvent) { try { return objectMapper.writeValueAsString(cdEvent); } catch (JsonProcessingException e) { - throw new InvalidRequestException( - "Unable to convert CDEvent to Json format.", e); + throw new InvalidRequestException("Unable to convert CDEvent to Json format.", e); } } - @Override public Object fromBody(TypedInput body, Type type) throws ConversionException { + + @Override + public Object fromBody(TypedInput body, Type type) throws ConversionException { try { JavaType javaType = objectMapper.getTypeFactory().constructType(type); return objectMapper.readValue(body.in(), javaType); @@ -74,7 +74,8 @@ public String convertCDEventToJson(CloudEvent cdEvent) { } } - @Override public TypedOutput toBody(Object object) { + @Override + public TypedOutput toBody(Object object) { try { String json = objectMapper.writeValueAsString(object); return new TypedByteArray(MIME_TYPE, json.getBytes("UTF-8")); @@ -85,7 +86,3 @@ public String convertCDEventToJson(CloudEvent cdEvent) { } } } - - - - diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderClient.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderClient.java index acd4921eb..33b7b51cc 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderClient.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderClient.java @@ -22,6 +22,5 @@ public interface CDEventsSenderClient { @POST("/{brokerUrl}") Response sendCDEvent( - @Body String cdEvent, - @Path(value = "brokerUrl", encode = false) String brokerUrl); + @Body String cdEvent, @Path(value = "brokerUrl", encode = false) String brokerUrl); } diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java index 5d275c909..9009b27b0 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java @@ -19,6 +19,8 @@ import com.netflix.spinnaker.kork.web.exceptions.InvalidRequestException; import com.netflix.spinnaker.retrofit.Slf4jRetrofitLogger; import io.cloudevents.CloudEvent; +import java.net.MalformedURLException; +import java.net.URL; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; @@ -26,10 +28,6 @@ import retrofit.RestAdapter; import retrofit.client.Client; import retrofit.client.Response; -import io.cloudevents.jackson.JsonFormat; - -import java.net.MalformedURLException; -import java.net.URL; @Slf4j @Component @@ -44,16 +42,17 @@ public CDEventsSenderService(Client retrofitClient, RestAdapter.LogLevel retrofi public Response sendCDEvent(CloudEvent cdEvent, String eventsBrokerUrl) { CDEventsHTTPMessageConverter converterFactory = CDEventsHTTPMessageConverter.create(); - RequestInterceptor authInterceptor = new RequestInterceptor() { - @Override - public void intercept(RequestInterceptor.RequestFacade request) { - request.addHeader("Ce-Id", cdEvent.getId()); - request.addHeader("Ce-Specversion", cdEvent.getSpecVersion().V1.toString()); - request.addHeader("Ce-Source", cdEvent.getSource().toString()); - request.addHeader("Ce-Type", cdEvent.getType()); - request.addHeader("Content-Type", "application/json"); - } - }; + RequestInterceptor authInterceptor = + new RequestInterceptor() { + @Override + public void intercept(RequestInterceptor.RequestFacade request) { + request.addHeader("Ce-Id", cdEvent.getId()); + request.addHeader("Ce-Specversion", cdEvent.getSpecVersion().V1.toString()); + request.addHeader("Ce-Source", cdEvent.getSource().toString()); + request.addHeader("Ce-Type", cdEvent.getType()); + request.addHeader("Content-Type", "application/json"); + } + }; CDEventsSenderClient cdEventsSenderClient = new RestAdapter.Builder() @@ -73,8 +72,10 @@ public void intercept(RequestInterceptor.RequestFacade request) { private String getEndpointUrl(String webhookUrl) { try { URL url = new URL(webhookUrl); - String endPointURL = url.getPort() != -1 ? url.getProtocol() + "://" + url.getHost() + ":" + url.getPort() - : url.getProtocol() + "://" + url.getHost(); + String endPointURL = + url.getPort() != -1 + ? url.getProtocol() + "://" + url.getHost() + ":" + url.getPort() + : url.getProtocol() + "://" + url.getHost(); log.info("endpoint Url to send CDEvent {} ", endPointURL); return endPointURL; } catch (MalformedURLException e) { diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java index d690b9798..5e5c74556 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java @@ -21,6 +21,8 @@ import com.netflix.spinnaker.echo.cdevents.CDEventsSenderService; import dev.cdevents.exception.CDEventsException; import io.cloudevents.CloudEvent; +import java.util.Map; +import java.util.Optional; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -28,16 +30,12 @@ import retrofit.client.Response; import retrofit.mime.TypedByteArray; -import java.util.Map; -import java.util.Optional; - @Slf4j @ConditionalOnProperty("cdevents.enabled") @Service public class CDEventsNotificationAgent extends AbstractEventNotificationAgent { @Autowired CDEventsBuilderService cdEventsBuilderService; - @Autowired - CDEventsSenderService cdEventsSenderService; + @Autowired CDEventsSenderService cdEventsSenderService; @Override public String getNotificationType() { @@ -69,15 +67,16 @@ public void sendNotifications( preference, application, event, config, status, getSpinnakerUrl()); log.info( "Sending CDEvent {} notification to events broker url {}", cdEventsType, eventsBrokerUrl); - Response response = - cdEventsSenderService.sendCDEvent(cdEvent, eventsBrokerUrl); + Response response = cdEventsSenderService.sendCDEvent(cdEvent, eventsBrokerUrl); if (response != null) { log.info( "Received response from events broker : {} {} for execution id {}. {}", response.getStatus(), response.getReason(), executionId, - response.getBody() != null ? new String(((TypedByteArray) response.getBody()).getBytes()) : ""); + response.getBody() != null + ? new String(((TypedByteArray) response.getBody()).getBytes()) + : ""); } } catch (Exception e) { From f57384495f27234b3c1e4e3ede4e40d1c3a06911 Mon Sep 17 00:00:00 2001 From: Jalander Ramagiri Date: Fri, 13 Oct 2023 14:12:33 +0100 Subject: [PATCH 08/14] addressing review comments --- .../echo/cdevents/CDEventsBuilderService.java | 21 ++++++++--- .../CDEventsNotificationAgent.java | 35 ++++++++----------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java index d1caa6b55..3341240ef 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java @@ -17,9 +17,14 @@ package com.netflix.spinnaker.echo.cdevents; import com.netflix.spinnaker.echo.api.events.Event; +import com.netflix.spinnaker.echo.exceptions.FieldNotFoundException; import dev.cdevents.CDEvents; import dev.cdevents.constants.CDEventConstants; -import dev.cdevents.events.*; +import dev.cdevents.events.PipelineRunFinishedCDEvent; +import dev.cdevents.events.PipelineRunQueuedCDEvent; +import dev.cdevents.events.PipelineRunStartedCDEvent; +import dev.cdevents.events.TaskRunFinishedCDEvent; +import dev.cdevents.events.TaskRunStartedCDEvent; import dev.cdevents.exception.CDEventsException; import io.cloudevents.CloudEvent; import java.net.URI; @@ -40,8 +45,14 @@ public CloudEvent createCDEvent( String status, String spinnakerUrl) { - String configType = Optional.ofNullable(config).map(c -> (String) c.get("type")).orElse(null); - String configLink = Optional.ofNullable(config).map(c -> (String) c.get("link")).orElse(null); + String configType = + Optional.ofNullable(config) + .map(c -> (String) c.get("type")) + .orElseThrow(FieldNotFoundException::new); + String configLink = + Optional.ofNullable(config) + .map(c -> (String) c.get("link")) + .orElseThrow(FieldNotFoundException::new); String executionId = Optional.ofNullable(event.content) @@ -64,7 +75,9 @@ public CloudEvent createCDEvent( .orElse(null); String cdEventsType = - Optional.ofNullable(preference).map(p -> (String) p.get("cdEventsType")).orElse(null); + Optional.ofNullable(preference) + .map(p -> (String) p.get("cdEventsType")) + .orElseThrow(FieldNotFoundException::new); CloudEvent ceToSend = buildCloudEventWithCDEventType( diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java index 5e5c74556..e8bb553e8 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java @@ -19,7 +19,6 @@ import com.netflix.spinnaker.echo.api.events.Event; import com.netflix.spinnaker.echo.cdevents.CDEventsBuilderService; import com.netflix.spinnaker.echo.cdevents.CDEventsSenderService; -import dev.cdevents.exception.CDEventsException; import io.cloudevents.CloudEvent; import java.util.Map; import java.util.Optional; @@ -61,27 +60,21 @@ public void sendNotifications( String eventsBrokerUrl = Optional.ofNullable(preference).map(p -> (String) p.get("address")).orElse(null); - try { - CloudEvent cdEvent = - cdEventsBuilderService.createCDEvent( - preference, application, event, config, status, getSpinnakerUrl()); + CloudEvent cdEvent = + cdEventsBuilderService.createCDEvent( + preference, application, event, config, status, getSpinnakerUrl()); + log.info( + "Sending CDEvent {} notification to events broker url {}", cdEventsType, eventsBrokerUrl); + Response response = cdEventsSenderService.sendCDEvent(cdEvent, eventsBrokerUrl); + if (response != null) { log.info( - "Sending CDEvent {} notification to events broker url {}", cdEventsType, eventsBrokerUrl); - Response response = cdEventsSenderService.sendCDEvent(cdEvent, eventsBrokerUrl); - if (response != null) { - log.info( - "Received response from events broker : {} {} for execution id {}. {}", - response.getStatus(), - response.getReason(), - executionId, - response.getBody() != null - ? new String(((TypedByteArray) response.getBody()).getBytes()) - : ""); - } - - } catch (Exception e) { - log.error("Exception occurred while sending CDEvent {}", e); - throw new CDEventsException("Exception occurred while sending CDEvent", e); + "Received response from events broker : {} {} for execution id {}. {}", + response.getStatus(), + response.getReason(), + executionId, + response.getBody() != null + ? new String(((TypedByteArray) response.getBody()).getBytes()) + : ""); } } } From a24cabd11bf13d1973fb821dc29f2f05e6db61b3 Mon Sep 17 00:00:00 2001 From: Jalander Ramagiri Date: Mon, 16 Oct 2023 16:48:33 +0100 Subject: [PATCH 09/14] Interface to create CDEvents --- .../echo/cdevents/CDEventCreator.java | 23 +++ .../cdevents/CDEventPipelineRunFinished.java | 67 +++++++ .../cdevents/CDEventPipelineRunQueued.java | 52 ++++++ .../cdevents/CDEventPipelineRunStarted.java | 52 ++++++ .../echo/cdevents/CDEventTaskRunFinished.java | 69 +++++++ .../echo/cdevents/CDEventTaskRunStarted.java | 56 ++++++ .../echo/cdevents/CDEventsBuilderService.java | 170 ++++-------------- .../CDEventsNotificationAgent.java | 11 +- 8 files changed, 361 insertions(+), 139 deletions(-) create mode 100644 echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventCreator.java create mode 100644 echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java create mode 100644 echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunQueued.java create mode 100644 echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunStarted.java create mode 100644 echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java create mode 100644 echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunStarted.java diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventCreator.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventCreator.java new file mode 100644 index 000000000..17525c18f --- /dev/null +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventCreator.java @@ -0,0 +1,23 @@ +/* + * Copyright 2023 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.echo.cdevents; + +import io.cloudevents.CloudEvent; + +public interface CDEventCreator { + CloudEvent createCDEvent(); +} diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java new file mode 100644 index 000000000..e45c31e21 --- /dev/null +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java @@ -0,0 +1,67 @@ +/* + * Copyright 2023 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.echo.cdevents; + +import dev.cdevents.CDEvents; +import dev.cdevents.constants.CDEventConstants; +import dev.cdevents.events.PipelineRunFinishedCDEvent; +import io.cloudevents.CloudEvent; +import java.net.URI; + +public class CDEventPipelineRunFinished implements CDEventCreator { + + private String source; + private String subjectId; + private String subjectSource; + private String subjectPipelineName; + private String subjectUrl; + + private String subjectError; + + public CDEventPipelineRunFinished( + String executionId, + String executionUrl, + String executionName, + String spinnakerUrl, + String status) { + this.source = spinnakerUrl; + this.subjectId = executionId; + this.subjectSource = spinnakerUrl; + this.subjectPipelineName = executionName; + this.subjectUrl = executionUrl; + this.subjectError = status; + } + + @Override + public CloudEvent createCDEvent() { + PipelineRunFinishedCDEvent cdEvent = new PipelineRunFinishedCDEvent(); + cdEvent.setSource(URI.create(source)); + cdEvent.setSubjectId(subjectId); + cdEvent.setSubjectSource(URI.create(subjectSource)); + cdEvent.setSubjectPipelineName(subjectSource); + cdEvent.setSubjectUrl(URI.create(subjectUrl)); + cdEvent.setSubjectErrors(subjectError); + + if (subjectError.equals("complete")) { + cdEvent.setSubjectOutcome(CDEventConstants.Outcome.SUCCESS); + } else if (subjectError.equals("failed")) { + cdEvent.setSubjectOutcome(CDEventConstants.Outcome.FAILURE); + } + + return CDEvents.cdEventAsCloudEvent(cdEvent); + } +} diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunQueued.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunQueued.java new file mode 100644 index 000000000..831250797 --- /dev/null +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunQueued.java @@ -0,0 +1,52 @@ +/* + * Copyright 2023 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.echo.cdevents; + +import dev.cdevents.CDEvents; +import dev.cdevents.events.PipelineRunQueuedCDEvent; +import io.cloudevents.CloudEvent; +import java.net.URI; + +public class CDEventPipelineRunQueued implements CDEventCreator { + + private String source; + private String subjectId; + private String subjectSource; + private String subjectPipelineName; + private String subjectUrl; + + public CDEventPipelineRunQueued( + String executionId, String executionUrl, String executionName, String spinnakerUrl) { + this.source = spinnakerUrl; + this.subjectId = executionId; + this.subjectSource = spinnakerUrl; + this.subjectPipelineName = executionName; + this.subjectUrl = executionUrl; + } + + @Override + public CloudEvent createCDEvent() { + PipelineRunQueuedCDEvent cdEvent = new PipelineRunQueuedCDEvent(); + cdEvent.setSource(URI.create(source)); + cdEvent.setSubjectId(subjectId); + cdEvent.setSubjectSource(URI.create(subjectSource)); + cdEvent.setSubjectPipelineName(subjectPipelineName); + cdEvent.setSubjectUrl(URI.create(subjectUrl)); + + return CDEvents.cdEventAsCloudEvent(cdEvent); + } +} diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunStarted.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunStarted.java new file mode 100644 index 000000000..914d41a46 --- /dev/null +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunStarted.java @@ -0,0 +1,52 @@ +/* + * Copyright 2023 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.echo.cdevents; + +import dev.cdevents.CDEvents; +import dev.cdevents.events.PipelineRunStartedCDEvent; +import io.cloudevents.CloudEvent; +import java.net.URI; + +public class CDEventPipelineRunStarted implements CDEventCreator { + + private String source; + private String subjectId; + private String subjectSource; + private String subjectPipelineName; + private String subjectUrl; + + public CDEventPipelineRunStarted( + String executionId, String executionUrl, String executionName, String spinnakerUrl) { + this.source = spinnakerUrl; + this.subjectId = executionId; + this.subjectSource = spinnakerUrl; + this.subjectPipelineName = executionName; + this.subjectUrl = executionUrl; + } + + @Override + public CloudEvent createCDEvent() { + PipelineRunStartedCDEvent cdEvent = new PipelineRunStartedCDEvent(); + cdEvent.setSource(URI.create(source)); + cdEvent.setSubjectId(subjectId); + cdEvent.setSubjectSource(URI.create(subjectSource)); + cdEvent.setSubjectPipelineName(subjectPipelineName); + cdEvent.setSubjectUrl(URI.create(subjectUrl)); + + return CDEvents.cdEventAsCloudEvent(cdEvent); + } +} diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java new file mode 100644 index 000000000..43309c8ee --- /dev/null +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java @@ -0,0 +1,69 @@ +/* + * Copyright 2023 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.echo.cdevents; + +import dev.cdevents.CDEvents; +import dev.cdevents.constants.CDEventConstants; +import dev.cdevents.events.TaskRunFinishedCDEvent; +import io.cloudevents.CloudEvent; +import java.net.URI; + +public class CDEventTaskRunFinished implements CDEventCreator { + + private String source; + private String subjectId; + private String subjectSource; + private String subjectTaskName; + private String subjectUrl; + private String subjectPipelineRunId; + private String subjectError; + + public CDEventTaskRunFinished( + String executionId, + String executionUrl, + String executionName, + String spinnakerUrl, + String status) { + this.source = spinnakerUrl; + this.subjectId = executionId; + this.subjectSource = spinnakerUrl; + this.subjectTaskName = executionName; + this.subjectUrl = executionUrl; + this.subjectPipelineRunId = executionId; + this.subjectError = status; + } + + @Override + public CloudEvent createCDEvent() { + TaskRunFinishedCDEvent cdEvent = new TaskRunFinishedCDEvent(); + cdEvent.setSource(URI.create(source)); + + cdEvent.setSubjectId(subjectId); + cdEvent.setSubjectSource(URI.create(source)); + cdEvent.setSubjectTaskName(subjectTaskName); + cdEvent.setSubjectUrl(URI.create(subjectUrl)); + cdEvent.setSubjectErrors(subjectError); + cdEvent.setSubjectPipelineRunId(subjectPipelineRunId); + if (subjectError.equals("complete")) { + cdEvent.setSubjectOutcome(CDEventConstants.Outcome.SUCCESS); + } else if (subjectError.equals("failed")) { + cdEvent.setSubjectOutcome(CDEventConstants.Outcome.FAILURE); + } + + return CDEvents.cdEventAsCloudEvent(cdEvent); + } +} diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunStarted.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunStarted.java new file mode 100644 index 000000000..2bf3df89e --- /dev/null +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunStarted.java @@ -0,0 +1,56 @@ +/* + * Copyright 2023 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.echo.cdevents; + +import dev.cdevents.CDEvents; +import dev.cdevents.events.TaskRunStartedCDEvent; +import io.cloudevents.CloudEvent; +import java.net.URI; + +public class CDEventTaskRunStarted implements CDEventCreator { + + private String source; + private String subjectId; + private String subjectSource; + private String subjectTaskName; + private String subjectUrl; + private String subjectPipelineRunId; + + public CDEventTaskRunStarted( + String executionId, String executionUrl, String executionName, String spinnakerUrl) { + this.source = spinnakerUrl; + this.subjectId = executionId; + this.subjectSource = spinnakerUrl; + this.subjectTaskName = executionName; + this.subjectUrl = executionUrl; + this.subjectPipelineRunId = executionId; + } + + @Override + public CloudEvent createCDEvent() { + TaskRunStartedCDEvent cdEvent = new TaskRunStartedCDEvent(); + cdEvent.setSource(URI.create(source)); + + cdEvent.setSubjectId(subjectId); + cdEvent.setSubjectSource(URI.create(subjectSource)); + cdEvent.setSubjectTaskName(subjectTaskName); + cdEvent.setSubjectUrl(URI.create(subjectUrl)); + cdEvent.setSubjectPipelineRunId(subjectPipelineRunId); + + return CDEvents.cdEventAsCloudEvent(cdEvent); + } +} diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java index 3341240ef..e6940b538 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java @@ -18,16 +18,9 @@ import com.netflix.spinnaker.echo.api.events.Event; import com.netflix.spinnaker.echo.exceptions.FieldNotFoundException; -import dev.cdevents.CDEvents; -import dev.cdevents.constants.CDEventConstants; -import dev.cdevents.events.PipelineRunFinishedCDEvent; -import dev.cdevents.events.PipelineRunQueuedCDEvent; -import dev.cdevents.events.PipelineRunStartedCDEvent; -import dev.cdevents.events.TaskRunFinishedCDEvent; -import dev.cdevents.events.TaskRunStartedCDEvent; +import dev.cdevents.constants.CDEventConstants.CDEventTypes; import dev.cdevents.exception.CDEventsException; import io.cloudevents.CloudEvent; -import java.net.URI; import java.util.Map; import java.util.Optional; import lombok.extern.slf4j.Slf4j; @@ -58,7 +51,7 @@ public CloudEvent createCDEvent( Optional.ofNullable(event.content) .map(e -> (Map) e.get("execution")) .map(e -> (String) e.get("id")) - .orElse(null); + .orElseThrow(FieldNotFoundException::new); String executionUrl = String.format( @@ -72,142 +65,47 @@ public CloudEvent createCDEvent( Optional.ofNullable(event.content) .map(e -> (Map) e.get("execution")) .map(e -> (String) e.get("name")) - .orElse(null); + .orElseThrow(FieldNotFoundException::new); String cdEventsType = Optional.ofNullable(preference) .map(p -> (String) p.get("cdEventsType")) .orElseThrow(FieldNotFoundException::new); - CloudEvent ceToSend = - buildCloudEventWithCDEventType( - cdEventsType, executionId, executionUrl, executionName, spinnakerUrl, status); - if (ceToSend == null) { - log.error("Failed to created CDEvent with type {} as CloudEvent", cdEventsType); - throw new CDEventsException("Failed to created CDEvent as CloudEvent"); - } - return ceToSend; - } - - private CloudEvent buildCloudEventWithCDEventType( - String cdEventsType, - String executionId, - String executionUrl, - String executionName, - String spinnakerUrl, - String status) { - CloudEvent ceToSend = null; - switch (cdEventsType) { - case "dev.cdevents.pipelinerun.queued": - ceToSend = - createPipelineRunQueuedEvent(executionId, executionUrl, executionName, spinnakerUrl); - break; - case "dev.cdevents.pipelinerun.started": - ceToSend = - createPipelineRunStartedEvent(executionId, executionUrl, executionName, spinnakerUrl); - break; - case "dev.cdevents.pipelinerun.finished": - ceToSend = - createPipelineRunFinishedEvent( - executionId, executionUrl, executionName, spinnakerUrl, status); + log.info("Event type {} received to create CDEvent.", cdEventsType); + CDEventCreator cdEventCreator = null; + // This map can be added with more event types that Spinnaker needs to send + Map cdEventsMap = + Map.of( + CDEventTypes.PipelineRunQueuedEvent.getEventType(), + new CDEventPipelineRunQueued( + executionId, executionUrl, executionName, spinnakerUrl), + CDEventTypes.PipelineRunStartedEvent.getEventType(), + new CDEventPipelineRunStarted( + executionId, executionUrl, executionName, spinnakerUrl), + CDEventTypes.PipelineRunFinishedEvent.getEventType(), + new CDEventPipelineRunFinished( + executionId, executionUrl, executionName, spinnakerUrl, status), + CDEventTypes.TaskRunStartedEvent.getEventType(), + new CDEventTaskRunStarted(executionId, executionUrl, executionName, spinnakerUrl), + CDEventTypes.TaskRunFinishedEvent.getEventType(), + new CDEventTaskRunFinished( + executionId, executionUrl, executionName, spinnakerUrl, status)); + for (String keyType : cdEventsMap.keySet()) { + if (keyType.contains(cdEventsType)) { + cdEventCreator = cdEventsMap.get(keyType); break; - case "dev.cdevents.taskrun.started": - ceToSend = - createTaskRunStartedEvent(executionId, executionUrl, executionName, spinnakerUrl); - break; - case "dev.cdevents.taskrun.finished": - ceToSend = - createTaskRunFinishedEvent( - executionId, executionUrl, executionName, spinnakerUrl, status); - break; - default: - throw new CDEventsException( - "Invalid CDEvents Type " + cdEventsType + " provided to create CDEvent"); - } - return ceToSend; - } - - private CloudEvent createTaskRunFinishedEvent( - String executionId, - String executionUrl, - String executionName, - String spinnakerUrl, - String status) { - TaskRunFinishedCDEvent cdEvent = new TaskRunFinishedCDEvent(); - cdEvent.setSource(URI.create(spinnakerUrl)); - - cdEvent.setSubjectId(executionId); - cdEvent.setSubjectSource(URI.create(spinnakerUrl)); - cdEvent.setSubjectTaskName(executionName); - cdEvent.setSubjectUrl(URI.create(executionUrl)); - cdEvent.setSubjectErrors(status); - cdEvent.setSubjectPipelineRunId(executionId); - if (status.equals("complete")) { - cdEvent.setSubjectOutcome(CDEventConstants.Outcome.SUCCESS); - } else if (status.equals("failed")) { - cdEvent.setSubjectOutcome(CDEventConstants.Outcome.FAILURE); + } } - return CDEvents.cdEventAsCloudEvent(cdEvent); - } - - private CloudEvent createTaskRunStartedEvent( - String executionId, String executionUrl, String executionName, String spinnakerUrl) { - TaskRunStartedCDEvent cdEvent = new TaskRunStartedCDEvent(); - cdEvent.setSource(URI.create(spinnakerUrl)); - cdEvent.setSubjectId(executionId); - cdEvent.setSubjectSource(URI.create(spinnakerUrl)); - cdEvent.setSubjectTaskName(executionName); - cdEvent.setSubjectUrl(URI.create(executionUrl)); - cdEvent.setSubjectPipelineRunId(executionId); - - return CDEvents.cdEventAsCloudEvent(cdEvent); - } - - private CloudEvent createPipelineRunFinishedEvent( - String executionId, - String executionUrl, - String executionName, - String spinnakerUrl, - String status) { - PipelineRunFinishedCDEvent cdEvent = new PipelineRunFinishedCDEvent(); - cdEvent.setSource(URI.create(spinnakerUrl)); - cdEvent.setSubjectId(executionId); - cdEvent.setSubjectSource(URI.create(spinnakerUrl)); - cdEvent.setSubjectPipelineName(executionName); - cdEvent.setSubjectUrl(URI.create(executionUrl)); - cdEvent.setSubjectErrors(status); - - if (status.equals("complete")) { - cdEvent.setSubjectOutcome(CDEventConstants.Outcome.SUCCESS); - } else if (status.equals("failed")) { - cdEvent.setSubjectOutcome(CDEventConstants.Outcome.FAILURE); + if (cdEventCreator == null) { + log.error("No mapping event type found for {}", cdEventsType); + log.error( + "The event type should be an event or substring of an event from the list of event types {}", + cdEventsMap.keySet()); + throw new CDEventsException("No mapping eventType found to create CDEvent"); + } else { + return cdEventCreator.createCDEvent(); } - - return CDEvents.cdEventAsCloudEvent(cdEvent); - } - - private CloudEvent createPipelineRunStartedEvent( - String executionId, String executionUrl, String executionName, String spinnakerUrl) { - PipelineRunStartedCDEvent cdEvent = new PipelineRunStartedCDEvent(); - cdEvent.setSource(URI.create(spinnakerUrl)); - cdEvent.setSubjectId(executionId); - cdEvent.setSubjectSource(URI.create(spinnakerUrl)); - cdEvent.setSubjectPipelineName(executionName); - cdEvent.setSubjectUrl(URI.create(executionUrl)); - - return CDEvents.cdEventAsCloudEvent(cdEvent); - } - - private CloudEvent createPipelineRunQueuedEvent( - String executionId, String executionUrl, String executionName, String spinnakerUrl) { - PipelineRunQueuedCDEvent cdEvent = new PipelineRunQueuedCDEvent(); - cdEvent.setSource(URI.create(spinnakerUrl)); - cdEvent.setSubjectId(executionId); - cdEvent.setSubjectSource(URI.create(spinnakerUrl)); - cdEvent.setSubjectPipelineName(executionName); - cdEvent.setSubjectUrl(URI.create(executionUrl)); - - return CDEvents.cdEventAsCloudEvent(cdEvent); } } diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java index e8bb553e8..f5debb04c 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java @@ -19,6 +19,7 @@ import com.netflix.spinnaker.echo.api.events.Event; import com.netflix.spinnaker.echo.cdevents.CDEventsBuilderService; import com.netflix.spinnaker.echo.cdevents.CDEventsSenderService; +import com.netflix.spinnaker.echo.exceptions.FieldNotFoundException; import io.cloudevents.CloudEvent; import java.util.Map; import java.util.Optional; @@ -54,11 +55,15 @@ public void sendNotifications( Optional.ofNullable(event.content) .map(e -> (Map) e.get("execution")) .map(e -> (String) e.get("id")) - .orElse(null); + .orElseThrow(FieldNotFoundException::new); String cdEventsType = - Optional.ofNullable(preference).map(p -> (String) p.get("cdEventsType")).orElse(null); + Optional.ofNullable(preference) + .map(p -> (String) p.get("cdEventsType")) + .orElseThrow(FieldNotFoundException::new); String eventsBrokerUrl = - Optional.ofNullable(preference).map(p -> (String) p.get("address")).orElse(null); + Optional.ofNullable(preference) + .map(p -> (String) p.get("address")) + .orElseThrow(FieldNotFoundException::new); CloudEvent cdEvent = cdEventsBuilderService.createCDEvent( From f9fa0518f4552b0fd402bd4bf17f9890e11f5a6e Mon Sep 17 00:00:00 2001 From: Jalander Ramagiri Date: Mon, 16 Oct 2023 17:18:41 +0100 Subject: [PATCH 10/14] update Copyright information --- .../echo/cdevents/CDEventCreator.java | 28 +++++++++---------- .../cdevents/CDEventPipelineRunFinished.java | 28 +++++++++---------- .../cdevents/CDEventPipelineRunQueued.java | 27 +++++++++--------- .../cdevents/CDEventPipelineRunStarted.java | 28 +++++++++---------- .../echo/cdevents/CDEventTaskRunFinished.java | 28 +++++++++---------- .../echo/cdevents/CDEventTaskRunStarted.java | 28 +++++++++---------- 6 files changed, 83 insertions(+), 84 deletions(-) diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventCreator.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventCreator.java index 17525c18f..8eb454b4b 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventCreator.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventCreator.java @@ -1,18 +1,18 @@ /* - * Copyright 2023 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ + Copyright (C) 2023 Nordix Foundation. + For a full list of individual contributors, please see the commit history. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + SPDX-License-Identifier: Apache-2.0 +*/ package com.netflix.spinnaker.echo.cdevents; diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java index e45c31e21..7af5483aa 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java @@ -1,18 +1,18 @@ /* - * Copyright 2023 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ + Copyright (C) 2023 Nordix Foundation. + For a full list of individual contributors, please see the commit history. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + SPDX-License-Identifier: Apache-2.0 +*/ package com.netflix.spinnaker.echo.cdevents; diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunQueued.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunQueued.java index 831250797..8a23781dd 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunQueued.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunQueued.java @@ -1,19 +1,18 @@ /* - * Copyright 2023 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ + Copyright (C) 2023 Nordix Foundation. + For a full list of individual contributors, please see the commit history. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + SPDX-License-Identifier: Apache-2.0 +*/ package com.netflix.spinnaker.echo.cdevents; import dev.cdevents.CDEvents; diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunStarted.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunStarted.java index 914d41a46..642e83e18 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunStarted.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunStarted.java @@ -1,18 +1,18 @@ /* - * Copyright 2023 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ + Copyright (C) 2023 Nordix Foundation. + For a full list of individual contributors, please see the commit history. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + SPDX-License-Identifier: Apache-2.0 +*/ package com.netflix.spinnaker.echo.cdevents; diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java index 43309c8ee..9ad40eb42 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java @@ -1,18 +1,18 @@ /* - * Copyright 2023 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ + Copyright (C) 2023 Nordix Foundation. + For a full list of individual contributors, please see the commit history. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + SPDX-License-Identifier: Apache-2.0 +*/ package com.netflix.spinnaker.echo.cdevents; diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunStarted.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunStarted.java index 2bf3df89e..2c8624151 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunStarted.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunStarted.java @@ -1,18 +1,18 @@ /* - * Copyright 2023 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ + Copyright (C) 2023 Nordix Foundation. + For a full list of individual contributors, please see the commit history. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + SPDX-License-Identifier: Apache-2.0 +*/ package com.netflix.spinnaker.echo.cdevents; From 2eecfe0fe6e8e2f11c9f767624270d37dd9d0c16 Mon Sep 17 00:00:00 2001 From: Jalander Ramagiri Date: Wed, 18 Oct 2023 13:19:21 +0100 Subject: [PATCH 11/14] Making CDEventCreator as an abstract --- .../echo/cdevents/CDEventCreator.java | 48 ++++++++++++++++- .../cdevents/CDEventPipelineRunFinished.java | 40 ++++++++------ .../cdevents/CDEventPipelineRunQueued.java | 29 +++++----- .../cdevents/CDEventPipelineRunStarted.java | 29 +++++----- .../echo/cdevents/CDEventTaskRunFinished.java | 54 ++++++++++++------- .../echo/cdevents/CDEventTaskRunStarted.java | 39 ++++++++------ .../echo/cdevents/CDEventsBuilderService.java | 1 - 7 files changed, 159 insertions(+), 81 deletions(-) diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventCreator.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventCreator.java index 8eb454b4b..9277fcb9c 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventCreator.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventCreator.java @@ -18,6 +18,50 @@ import io.cloudevents.CloudEvent; -public interface CDEventCreator { - CloudEvent createCDEvent(); +public abstract class CDEventCreator { + abstract CloudEvent createCDEvent(); + + private String source; + private String subjectId; + private String subjectSource; + private String subjectUrl; + + public CDEventCreator(String source, String subjectId, String subjectSource, String subjectUrl) { + this.source = source; + this.subjectId = subjectId; + this.subjectSource = subjectSource; + this.subjectUrl = subjectUrl; + } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } + + public String getSubjectId() { + return subjectId; + } + + public void setSubjectId(String subjectId) { + this.subjectId = subjectId; + } + + public String getSubjectSource() { + return subjectSource; + } + + public void setSubjectSource(String subjectSource) { + this.subjectSource = subjectSource; + } + + public String getSubjectUrl() { + return subjectUrl; + } + + public void setSubjectUrl(String subjectUrl) { + this.subjectUrl = subjectUrl; + } } diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java index 7af5483aa..200c18225 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java @@ -22,14 +22,9 @@ import io.cloudevents.CloudEvent; import java.net.URI; -public class CDEventPipelineRunFinished implements CDEventCreator { +public class CDEventPipelineRunFinished extends CDEventCreator { - private String source; - private String subjectId; - private String subjectSource; private String subjectPipelineName; - private String subjectUrl; - private String subjectError; public CDEventPipelineRunFinished( @@ -38,23 +33,36 @@ public CDEventPipelineRunFinished( String executionName, String spinnakerUrl, String status) { - this.source = spinnakerUrl; - this.subjectId = executionId; - this.subjectSource = spinnakerUrl; + super(spinnakerUrl, executionId, spinnakerUrl, executionUrl); this.subjectPipelineName = executionName; - this.subjectUrl = executionUrl; this.subjectError = status; } + public String getSubjectPipelineName() { + return subjectPipelineName; + } + + public void setSubjectPipelineName(String subjectPipelineName) { + this.subjectPipelineName = subjectPipelineName; + } + + public String getSubjectError() { + return subjectError; + } + + public void setSubjectError(String subjectError) { + this.subjectError = subjectError; + } + @Override public CloudEvent createCDEvent() { PipelineRunFinishedCDEvent cdEvent = new PipelineRunFinishedCDEvent(); - cdEvent.setSource(URI.create(source)); - cdEvent.setSubjectId(subjectId); - cdEvent.setSubjectSource(URI.create(subjectSource)); - cdEvent.setSubjectPipelineName(subjectSource); - cdEvent.setSubjectUrl(URI.create(subjectUrl)); - cdEvent.setSubjectErrors(subjectError); + cdEvent.setSource(URI.create(getSource())); + cdEvent.setSubjectId(getSubjectId()); + cdEvent.setSubjectSource(URI.create(getSubjectSource())); + cdEvent.setSubjectPipelineName(getSubjectPipelineName()); + cdEvent.setSubjectUrl(URI.create(getSubjectUrl())); + cdEvent.setSubjectErrors(getSubjectError()); if (subjectError.equals("complete")) { cdEvent.setSubjectOutcome(CDEventConstants.Outcome.SUCCESS); diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunQueued.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunQueued.java index 8a23781dd..0e95dd817 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunQueued.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunQueued.java @@ -20,31 +20,32 @@ import io.cloudevents.CloudEvent; import java.net.URI; -public class CDEventPipelineRunQueued implements CDEventCreator { +public class CDEventPipelineRunQueued extends CDEventCreator { - private String source; - private String subjectId; - private String subjectSource; private String subjectPipelineName; - private String subjectUrl; public CDEventPipelineRunQueued( String executionId, String executionUrl, String executionName, String spinnakerUrl) { - this.source = spinnakerUrl; - this.subjectId = executionId; - this.subjectSource = spinnakerUrl; + super(spinnakerUrl, executionId, spinnakerUrl, executionUrl); this.subjectPipelineName = executionName; - this.subjectUrl = executionUrl; + } + + public String getSubjectPipelineName() { + return subjectPipelineName; + } + + public void setSubjectPipelineName(String subjectPipelineName) { + this.subjectPipelineName = subjectPipelineName; } @Override public CloudEvent createCDEvent() { PipelineRunQueuedCDEvent cdEvent = new PipelineRunQueuedCDEvent(); - cdEvent.setSource(URI.create(source)); - cdEvent.setSubjectId(subjectId); - cdEvent.setSubjectSource(URI.create(subjectSource)); - cdEvent.setSubjectPipelineName(subjectPipelineName); - cdEvent.setSubjectUrl(URI.create(subjectUrl)); + cdEvent.setSource(URI.create(getSource())); + cdEvent.setSubjectId(getSubjectId()); + cdEvent.setSubjectSource(URI.create(getSubjectSource())); + cdEvent.setSubjectPipelineName(getSubjectPipelineName()); + cdEvent.setSubjectUrl(URI.create(getSubjectUrl())); return CDEvents.cdEventAsCloudEvent(cdEvent); } diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunStarted.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunStarted.java index 642e83e18..b08074f35 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunStarted.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunStarted.java @@ -21,31 +21,32 @@ import io.cloudevents.CloudEvent; import java.net.URI; -public class CDEventPipelineRunStarted implements CDEventCreator { +public class CDEventPipelineRunStarted extends CDEventCreator { - private String source; - private String subjectId; - private String subjectSource; private String subjectPipelineName; - private String subjectUrl; public CDEventPipelineRunStarted( String executionId, String executionUrl, String executionName, String spinnakerUrl) { - this.source = spinnakerUrl; - this.subjectId = executionId; - this.subjectSource = spinnakerUrl; + super(spinnakerUrl, executionId, spinnakerUrl, executionUrl); this.subjectPipelineName = executionName; - this.subjectUrl = executionUrl; + } + + public String getSubjectPipelineName() { + return subjectPipelineName; + } + + public void setSubjectPipelineName(String subjectPipelineName) { + this.subjectPipelineName = subjectPipelineName; } @Override public CloudEvent createCDEvent() { PipelineRunStartedCDEvent cdEvent = new PipelineRunStartedCDEvent(); - cdEvent.setSource(URI.create(source)); - cdEvent.setSubjectId(subjectId); - cdEvent.setSubjectSource(URI.create(subjectSource)); - cdEvent.setSubjectPipelineName(subjectPipelineName); - cdEvent.setSubjectUrl(URI.create(subjectUrl)); + cdEvent.setSource(URI.create(getSource())); + cdEvent.setSubjectId(getSubjectId()); + cdEvent.setSubjectSource(URI.create(getSubjectSource())); + cdEvent.setSubjectPipelineName(getSubjectPipelineName()); + cdEvent.setSubjectUrl(URI.create(getSubjectUrl())); return CDEvents.cdEventAsCloudEvent(cdEvent); } diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java index 9ad40eb42..48a0f12cc 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java @@ -22,13 +22,9 @@ import io.cloudevents.CloudEvent; import java.net.URI; -public class CDEventTaskRunFinished implements CDEventCreator { +public class CDEventTaskRunFinished extends CDEventCreator { - private String source; - private String subjectId; - private String subjectSource; private String subjectTaskName; - private String subjectUrl; private String subjectPipelineRunId; private String subjectError; @@ -38,29 +34,49 @@ public CDEventTaskRunFinished( String executionName, String spinnakerUrl, String status) { - this.source = spinnakerUrl; - this.subjectId = executionId; - this.subjectSource = spinnakerUrl; + super(spinnakerUrl, executionId, spinnakerUrl, executionUrl); this.subjectTaskName = executionName; - this.subjectUrl = executionUrl; this.subjectPipelineRunId = executionId; this.subjectError = status; } + public String getSubjectTaskName() { + return subjectTaskName; + } + + public void setSubjectTaskName(String subjectTaskName) { + this.subjectTaskName = subjectTaskName; + } + + public String getSubjectPipelineRunId() { + return subjectPipelineRunId; + } + + public void setSubjectPipelineRunId(String subjectPipelineRunId) { + this.subjectPipelineRunId = subjectPipelineRunId; + } + + public String getSubjectError() { + return subjectError; + } + + public void setSubjectError(String subjectError) { + this.subjectError = subjectError; + } + @Override public CloudEvent createCDEvent() { TaskRunFinishedCDEvent cdEvent = new TaskRunFinishedCDEvent(); - cdEvent.setSource(URI.create(source)); - - cdEvent.setSubjectId(subjectId); - cdEvent.setSubjectSource(URI.create(source)); - cdEvent.setSubjectTaskName(subjectTaskName); - cdEvent.setSubjectUrl(URI.create(subjectUrl)); - cdEvent.setSubjectErrors(subjectError); - cdEvent.setSubjectPipelineRunId(subjectPipelineRunId); - if (subjectError.equals("complete")) { + cdEvent.setSource(URI.create(getSource())); + cdEvent.setSubjectId(getSubjectId()); + cdEvent.setSubjectSource(URI.create(getSubjectSource())); + cdEvent.setSubjectTaskName(getSubjectTaskName()); + cdEvent.setSubjectUrl(URI.create(getSubjectUrl())); + cdEvent.setSubjectErrors(getSubjectError()); + cdEvent.setSubjectPipelineRunId(getSubjectPipelineRunId()); + if (getSubjectError().equals("complete")) { cdEvent.setSubjectOutcome(CDEventConstants.Outcome.SUCCESS); - } else if (subjectError.equals("failed")) { + } else if (getSubjectError().equals("failed")) { cdEvent.setSubjectOutcome(CDEventConstants.Outcome.FAILURE); } diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunStarted.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunStarted.java index 2c8624151..a854507fd 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunStarted.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunStarted.java @@ -21,35 +21,44 @@ import io.cloudevents.CloudEvent; import java.net.URI; -public class CDEventTaskRunStarted implements CDEventCreator { +public class CDEventTaskRunStarted extends CDEventCreator { - private String source; - private String subjectId; - private String subjectSource; private String subjectTaskName; - private String subjectUrl; private String subjectPipelineRunId; public CDEventTaskRunStarted( String executionId, String executionUrl, String executionName, String spinnakerUrl) { - this.source = spinnakerUrl; - this.subjectId = executionId; - this.subjectSource = spinnakerUrl; + super(spinnakerUrl, executionId, spinnakerUrl, executionUrl); this.subjectTaskName = executionName; - this.subjectUrl = executionUrl; this.subjectPipelineRunId = executionId; } + public String getSubjectTaskName() { + return subjectTaskName; + } + + public void setSubjectTaskName(String subjectTaskName) { + this.subjectTaskName = subjectTaskName; + } + + public String getSubjectPipelineRunId() { + return subjectPipelineRunId; + } + + public void setSubjectPipelineRunId(String subjectPipelineRunId) { + this.subjectPipelineRunId = subjectPipelineRunId; + } + @Override public CloudEvent createCDEvent() { TaskRunStartedCDEvent cdEvent = new TaskRunStartedCDEvent(); - cdEvent.setSource(URI.create(source)); + cdEvent.setSource(URI.create(getSource())); - cdEvent.setSubjectId(subjectId); - cdEvent.setSubjectSource(URI.create(subjectSource)); - cdEvent.setSubjectTaskName(subjectTaskName); - cdEvent.setSubjectUrl(URI.create(subjectUrl)); - cdEvent.setSubjectPipelineRunId(subjectPipelineRunId); + cdEvent.setSubjectId(getSubjectId()); + cdEvent.setSubjectSource(URI.create(getSubjectSource())); + cdEvent.setSubjectTaskName(getSubjectTaskName()); + cdEvent.setSubjectUrl(URI.create(getSubjectUrl())); + cdEvent.setSubjectPipelineRunId(getSubjectPipelineRunId()); return CDEvents.cdEventAsCloudEvent(cdEvent); } diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java index e6940b538..df5e042c8 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java @@ -71,7 +71,6 @@ public CloudEvent createCDEvent( Optional.ofNullable(preference) .map(p -> (String) p.get("cdEventsType")) .orElseThrow(FieldNotFoundException::new); - log.info("Event type {} received to create CDEvent.", cdEventsType); CDEventCreator cdEventCreator = null; // This map can be added with more event types that Spinnaker needs to send From fc319635a6ba0940b0c45cbf882d4f094a09cdce Mon Sep 17 00:00:00 2001 From: Jalander Ramagiri Date: Tue, 24 Oct 2023 10:30:25 +0100 Subject: [PATCH 12/14] Class name changed to BaseCDEvent and uing lombok.Getter --- .../{CDEventCreator.java => BaseCDEvent.java} | 45 +++---------------- .../cdevents/CDEventPipelineRunFinished.java | 23 ++-------- .../cdevents/CDEventPipelineRunQueued.java | 13 ++---- .../cdevents/CDEventPipelineRunStarted.java | 13 ++---- .../echo/cdevents/CDEventTaskRunFinished.java | 33 +++----------- .../echo/cdevents/CDEventTaskRunStarted.java | 23 ++-------- .../echo/cdevents/CDEventsBuilderService.java | 12 ++--- 7 files changed, 32 insertions(+), 130 deletions(-) rename echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/{CDEventCreator.java => BaseCDEvent.java} (54%) diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventCreator.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/BaseCDEvent.java similarity index 54% rename from echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventCreator.java rename to echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/BaseCDEvent.java index 9277fcb9c..6739b8675 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventCreator.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/BaseCDEvent.java @@ -17,51 +17,20 @@ package com.netflix.spinnaker.echo.cdevents; import io.cloudevents.CloudEvent; +import lombok.Getter; -public abstract class CDEventCreator { +public abstract class BaseCDEvent { abstract CloudEvent createCDEvent(); - private String source; - private String subjectId; - private String subjectSource; - private String subjectUrl; + @Getter private String source; + @Getter private String subjectId; + @Getter private String subjectSource; + @Getter private String subjectUrl; - public CDEventCreator(String source, String subjectId, String subjectSource, String subjectUrl) { + public BaseCDEvent(String source, String subjectId, String subjectSource, String subjectUrl) { this.source = source; this.subjectId = subjectId; this.subjectSource = subjectSource; this.subjectUrl = subjectUrl; } - - public String getSource() { - return source; - } - - public void setSource(String source) { - this.source = source; - } - - public String getSubjectId() { - return subjectId; - } - - public void setSubjectId(String subjectId) { - this.subjectId = subjectId; - } - - public String getSubjectSource() { - return subjectSource; - } - - public void setSubjectSource(String subjectSource) { - this.subjectSource = subjectSource; - } - - public String getSubjectUrl() { - return subjectUrl; - } - - public void setSubjectUrl(String subjectUrl) { - this.subjectUrl = subjectUrl; - } } diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java index 200c18225..803756575 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java @@ -21,11 +21,12 @@ import dev.cdevents.events.PipelineRunFinishedCDEvent; import io.cloudevents.CloudEvent; import java.net.URI; +import lombok.Getter; -public class CDEventPipelineRunFinished extends CDEventCreator { +public class CDEventPipelineRunFinished extends BaseCDEvent { - private String subjectPipelineName; - private String subjectError; + @Getter private String subjectPipelineName; + @Getter private String subjectError; public CDEventPipelineRunFinished( String executionId, @@ -38,22 +39,6 @@ public CDEventPipelineRunFinished( this.subjectError = status; } - public String getSubjectPipelineName() { - return subjectPipelineName; - } - - public void setSubjectPipelineName(String subjectPipelineName) { - this.subjectPipelineName = subjectPipelineName; - } - - public String getSubjectError() { - return subjectError; - } - - public void setSubjectError(String subjectError) { - this.subjectError = subjectError; - } - @Override public CloudEvent createCDEvent() { PipelineRunFinishedCDEvent cdEvent = new PipelineRunFinishedCDEvent(); diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunQueued.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunQueued.java index 0e95dd817..5e3f5d45a 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunQueued.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunQueued.java @@ -19,10 +19,11 @@ import dev.cdevents.events.PipelineRunQueuedCDEvent; import io.cloudevents.CloudEvent; import java.net.URI; +import lombok.Getter; -public class CDEventPipelineRunQueued extends CDEventCreator { +public class CDEventPipelineRunQueued extends BaseCDEvent { - private String subjectPipelineName; + @Getter private String subjectPipelineName; public CDEventPipelineRunQueued( String executionId, String executionUrl, String executionName, String spinnakerUrl) { @@ -30,14 +31,6 @@ public CDEventPipelineRunQueued( this.subjectPipelineName = executionName; } - public String getSubjectPipelineName() { - return subjectPipelineName; - } - - public void setSubjectPipelineName(String subjectPipelineName) { - this.subjectPipelineName = subjectPipelineName; - } - @Override public CloudEvent createCDEvent() { PipelineRunQueuedCDEvent cdEvent = new PipelineRunQueuedCDEvent(); diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunStarted.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunStarted.java index b08074f35..6733aa381 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunStarted.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunStarted.java @@ -20,10 +20,11 @@ import dev.cdevents.events.PipelineRunStartedCDEvent; import io.cloudevents.CloudEvent; import java.net.URI; +import lombok.Getter; -public class CDEventPipelineRunStarted extends CDEventCreator { +public class CDEventPipelineRunStarted extends BaseCDEvent { - private String subjectPipelineName; + @Getter private String subjectPipelineName; public CDEventPipelineRunStarted( String executionId, String executionUrl, String executionName, String spinnakerUrl) { @@ -31,14 +32,6 @@ public CDEventPipelineRunStarted( this.subjectPipelineName = executionName; } - public String getSubjectPipelineName() { - return subjectPipelineName; - } - - public void setSubjectPipelineName(String subjectPipelineName) { - this.subjectPipelineName = subjectPipelineName; - } - @Override public CloudEvent createCDEvent() { PipelineRunStartedCDEvent cdEvent = new PipelineRunStartedCDEvent(); diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java index 48a0f12cc..96dca3179 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java @@ -21,12 +21,13 @@ import dev.cdevents.events.TaskRunFinishedCDEvent; import io.cloudevents.CloudEvent; import java.net.URI; +import lombok.Getter; -public class CDEventTaskRunFinished extends CDEventCreator { +public class CDEventTaskRunFinished extends BaseCDEvent { - private String subjectTaskName; - private String subjectPipelineRunId; - private String subjectError; + @Getter private String subjectTaskName; + @Getter private String subjectPipelineRunId; + @Getter private String subjectError; public CDEventTaskRunFinished( String executionId, @@ -40,30 +41,6 @@ public CDEventTaskRunFinished( this.subjectError = status; } - public String getSubjectTaskName() { - return subjectTaskName; - } - - public void setSubjectTaskName(String subjectTaskName) { - this.subjectTaskName = subjectTaskName; - } - - public String getSubjectPipelineRunId() { - return subjectPipelineRunId; - } - - public void setSubjectPipelineRunId(String subjectPipelineRunId) { - this.subjectPipelineRunId = subjectPipelineRunId; - } - - public String getSubjectError() { - return subjectError; - } - - public void setSubjectError(String subjectError) { - this.subjectError = subjectError; - } - @Override public CloudEvent createCDEvent() { TaskRunFinishedCDEvent cdEvent = new TaskRunFinishedCDEvent(); diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunStarted.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunStarted.java index a854507fd..f6857ffff 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunStarted.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunStarted.java @@ -20,11 +20,12 @@ import dev.cdevents.events.TaskRunStartedCDEvent; import io.cloudevents.CloudEvent; import java.net.URI; +import lombok.Getter; -public class CDEventTaskRunStarted extends CDEventCreator { +public class CDEventTaskRunStarted extends BaseCDEvent { - private String subjectTaskName; - private String subjectPipelineRunId; + @Getter private String subjectTaskName; + @Getter private String subjectPipelineRunId; public CDEventTaskRunStarted( String executionId, String executionUrl, String executionName, String spinnakerUrl) { @@ -33,22 +34,6 @@ public CDEventTaskRunStarted( this.subjectPipelineRunId = executionId; } - public String getSubjectTaskName() { - return subjectTaskName; - } - - public void setSubjectTaskName(String subjectTaskName) { - this.subjectTaskName = subjectTaskName; - } - - public String getSubjectPipelineRunId() { - return subjectPipelineRunId; - } - - public void setSubjectPipelineRunId(String subjectPipelineRunId) { - this.subjectPipelineRunId = subjectPipelineRunId; - } - @Override public CloudEvent createCDEvent() { TaskRunStartedCDEvent cdEvent = new TaskRunStartedCDEvent(); diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java index df5e042c8..6c8b40682 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java @@ -72,9 +72,9 @@ public CloudEvent createCDEvent( .map(p -> (String) p.get("cdEventsType")) .orElseThrow(FieldNotFoundException::new); log.info("Event type {} received to create CDEvent.", cdEventsType); - CDEventCreator cdEventCreator = null; - // This map can be added with more event types that Spinnaker needs to send - Map cdEventsMap = + BaseCDEvent cdEvent = null; + // This map will be updated to add more event types that Spinnaker needs to send + Map cdEventsMap = Map.of( CDEventTypes.PipelineRunQueuedEvent.getEventType(), new CDEventPipelineRunQueued( @@ -92,19 +92,19 @@ public CloudEvent createCDEvent( executionId, executionUrl, executionName, spinnakerUrl, status)); for (String keyType : cdEventsMap.keySet()) { if (keyType.contains(cdEventsType)) { - cdEventCreator = cdEventsMap.get(keyType); + cdEvent = cdEventsMap.get(keyType); break; } } - if (cdEventCreator == null) { + if (cdEvent == null) { log.error("No mapping event type found for {}", cdEventsType); log.error( "The event type should be an event or substring of an event from the list of event types {}", cdEventsMap.keySet()); throw new CDEventsException("No mapping eventType found to create CDEvent"); } else { - return cdEventCreator.createCDEvent(); + return cdEvent.createCDEvent(); } } } From 1f783f6209b4bb16c15d60536f710d30128e0f51 Mon Sep 17 00:00:00 2001 From: Jalander Ramagiri Date: Tue, 24 Oct 2023 11:58:38 +0100 Subject: [PATCH 13/14] addressing review comments --- .../spinnaker/echo/cdevents/BaseCDEvent.java | 9 ++++ .../echo/cdevents/CDEventsBuilderService.java | 41 +++++++++---------- .../CDEventsHTTPMessageConverter.java | 9 ++-- .../echo/cdevents/CDEventsSenderClient.java | 4 +- .../echo/cdevents/CDEventsSenderService.java | 3 +- .../CDEventsNotificationAgent.java | 6 +-- 6 files changed, 40 insertions(+), 32 deletions(-) diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/BaseCDEvent.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/BaseCDEvent.java index 6739b8675..ab166d400 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/BaseCDEvent.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/BaseCDEvent.java @@ -20,9 +20,18 @@ import lombok.Getter; public abstract class BaseCDEvent { + /** + * This method can be implemented to create various types of CDEvents that can return a specific + * type of CDEvents in a CloudEvent format, more details on CDEvent types can be found in + * Documentation at https://cdevents.dev + * + * @return cdEvent + */ abstract CloudEvent createCDEvent(); + /** Common properties used in most of the CDEvents */ @Getter private String source; + @Getter private String subjectId; @Getter private String subjectSource; @Getter private String subjectUrl; diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java index 6c8b40682..6c01ac81c 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsBuilderService.java @@ -41,17 +41,17 @@ public CloudEvent createCDEvent( String configType = Optional.ofNullable(config) .map(c -> (String) c.get("type")) - .orElseThrow(FieldNotFoundException::new); + .orElseThrow(() -> new FieldNotFoundException("type")); String configLink = Optional.ofNullable(config) .map(c -> (String) c.get("link")) - .orElseThrow(FieldNotFoundException::new); + .orElseThrow(() -> new FieldNotFoundException("link")); String executionId = Optional.ofNullable(event.content) .map(e -> (Map) e.get("execution")) .map(e -> (String) e.get("id")) - .orElseThrow(FieldNotFoundException::new); + .orElseThrow(() -> new FieldNotFoundException("execution.id")); String executionUrl = String.format( @@ -65,14 +65,13 @@ public CloudEvent createCDEvent( Optional.ofNullable(event.content) .map(e -> (Map) e.get("execution")) .map(e -> (String) e.get("name")) - .orElseThrow(FieldNotFoundException::new); + .orElseThrow(() -> new FieldNotFoundException("execution.name")); String cdEventsType = Optional.ofNullable(preference) .map(p -> (String) p.get("cdEventsType")) - .orElseThrow(FieldNotFoundException::new); + .orElseThrow(() -> new FieldNotFoundException("notifications.cdEventsType")); log.info("Event type {} received to create CDEvent.", cdEventsType); - BaseCDEvent cdEvent = null; // This map will be updated to add more event types that Spinnaker needs to send Map cdEventsMap = Map.of( @@ -90,21 +89,21 @@ public CloudEvent createCDEvent( CDEventTypes.TaskRunFinishedEvent.getEventType(), new CDEventTaskRunFinished( executionId, executionUrl, executionName, spinnakerUrl, status)); - for (String keyType : cdEventsMap.keySet()) { - if (keyType.contains(cdEventsType)) { - cdEvent = cdEventsMap.get(keyType); - break; - } - } - if (cdEvent == null) { - log.error("No mapping event type found for {}", cdEventsType); - log.error( - "The event type should be an event or substring of an event from the list of event types {}", - cdEventsMap.keySet()); - throw new CDEventsException("No mapping eventType found to create CDEvent"); - } else { - return cdEvent.createCDEvent(); - } + BaseCDEvent cdEvent = + cdEventsMap.keySet().stream() + .filter(keyType -> keyType.contains(cdEventsType)) + .map(cdEventsMap::get) + .findFirst() + .orElseThrow( + () -> { + log.error("No mapping event type found for {}", cdEventsType); + log.error( + "The event type should be an event or substring of an event from the list of event types {}", + cdEventsMap.keySet()); + return new CDEventsException("No mapping eventType found to create CDEvent"); + }); + + return cdEvent.createCDEvent(); } } diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsHTTPMessageConverter.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsHTTPMessageConverter.java index 40998c198..5cb251560 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsHTTPMessageConverter.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsHTTPMessageConverter.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.lang.reflect.Type; +import org.springframework.http.MediaType; import retrofit.converter.ConversionException; import retrofit.converter.Converter; import retrofit.mime.TypedByteArray; @@ -39,8 +40,6 @@ public class CDEventsHTTPMessageConverter implements Converter { private final ObjectMapper objectMapper; - private static final String MIME_TYPE = "application/json"; - public CDEventsHTTPMessageConverter(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @@ -65,9 +64,7 @@ public Object fromBody(TypedInput body, Type type) throws ConversionException { try { JavaType javaType = objectMapper.getTypeFactory().constructType(type); return objectMapper.readValue(body.in(), javaType); - } catch (JsonParseException e) { - throw new ConversionException(e); - } catch (JsonMappingException e) { + } catch (JsonParseException | JsonMappingException e) { throw new ConversionException(e); } catch (IOException e) { throw new ConversionException(e); @@ -78,7 +75,7 @@ public Object fromBody(TypedInput body, Type type) throws ConversionException { public TypedOutput toBody(Object object) { try { String json = objectMapper.writeValueAsString(object); - return new TypedByteArray(MIME_TYPE, json.getBytes("UTF-8")); + return new TypedByteArray(MediaType.APPLICATION_JSON_VALUE, json.getBytes("UTF-8")); } catch (JsonProcessingException e) { throw new AssertionError(e); } catch (UnsupportedEncodingException e) { diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderClient.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderClient.java index 33b7b51cc..1739f08bd 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderClient.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderClient.java @@ -17,7 +17,9 @@ package com.netflix.spinnaker.echo.cdevents; import retrofit.client.Response; -import retrofit.http.*; +import retrofit.http.Body; +import retrofit.http.POST; +import retrofit.http.Path; public interface CDEventsSenderClient { @POST("/{brokerUrl}") diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java index 9009b27b0..38c340981 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java @@ -23,6 +23,7 @@ import java.net.URL; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import retrofit.RequestInterceptor; import retrofit.RestAdapter; @@ -50,7 +51,7 @@ public void intercept(RequestInterceptor.RequestFacade request) { request.addHeader("Ce-Specversion", cdEvent.getSpecVersion().V1.toString()); request.addHeader("Ce-Source", cdEvent.getSource().toString()); request.addHeader("Ce-Type", cdEvent.getType()); - request.addHeader("Content-Type", "application/json"); + request.addHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE); } }; diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java index f5debb04c..1f67b771f 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java @@ -55,15 +55,15 @@ public void sendNotifications( Optional.ofNullable(event.content) .map(e -> (Map) e.get("execution")) .map(e -> (String) e.get("id")) - .orElseThrow(FieldNotFoundException::new); + .orElseThrow(() -> new FieldNotFoundException("execution.id")); String cdEventsType = Optional.ofNullable(preference) .map(p -> (String) p.get("cdEventsType")) - .orElseThrow(FieldNotFoundException::new); + .orElseThrow(() -> new FieldNotFoundException("notifications.cdEventsType")); String eventsBrokerUrl = Optional.ofNullable(preference) .map(p -> (String) p.get("address")) - .orElseThrow(FieldNotFoundException::new); + .orElseThrow(() -> new FieldNotFoundException("notifications.address")); CloudEvent cdEvent = cdEventsBuilderService.createCDEvent( From 621da6b9a1172ed39a6a9cbf94632138666b043d Mon Sep 17 00:00:00 2001 From: Jalander Ramagiri Date: Tue, 24 Oct 2023 16:51:59 +0100 Subject: [PATCH 14/14] addressing minor review comments --- .../cdevents/CDEventPipelineRunFinished.java | 4 +-- .../echo/cdevents/CDEventTaskRunFinished.java | 4 +-- .../echo/cdevents/CDEventsSenderService.java | 7 ++--- .../CDEventsNotificationAgent.java | 28 +++++++++---------- .../CDEventsNotificationAgentSpec.groovy | 28 +++++++++---------- 5 files changed, 35 insertions(+), 36 deletions(-) diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java index 803756575..d609179ac 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventPipelineRunFinished.java @@ -49,9 +49,9 @@ public CloudEvent createCDEvent() { cdEvent.setSubjectUrl(URI.create(getSubjectUrl())); cdEvent.setSubjectErrors(getSubjectError()); - if (subjectError.equals("complete")) { + if ("complete".equals(getSubjectError())) { cdEvent.setSubjectOutcome(CDEventConstants.Outcome.SUCCESS); - } else if (subjectError.equals("failed")) { + } else if ("failed".equals(getSubjectError())) { cdEvent.setSubjectOutcome(CDEventConstants.Outcome.FAILURE); } diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java index 96dca3179..a72dff0d2 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventTaskRunFinished.java @@ -51,9 +51,9 @@ public CloudEvent createCDEvent() { cdEvent.setSubjectUrl(URI.create(getSubjectUrl())); cdEvent.setSubjectErrors(getSubjectError()); cdEvent.setSubjectPipelineRunId(getSubjectPipelineRunId()); - if (getSubjectError().equals("complete")) { + if ("complete".equals(getSubjectError())) { cdEvent.setSubjectOutcome(CDEventConstants.Outcome.SUCCESS); - } else if (getSubjectError().equals("failed")) { + } else if ("failed".equals(getSubjectError())) { cdEvent.setSubjectOutcome(CDEventConstants.Outcome.FAILURE); } diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java index 38c340981..4b71cae27 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/cdevents/CDEventsSenderService.java @@ -77,11 +77,10 @@ private String getEndpointUrl(String webhookUrl) { url.getPort() != -1 ? url.getProtocol() + "://" + url.getHost() + ":" + url.getPort() : url.getProtocol() + "://" + url.getHost(); - log.info("endpoint Url to send CDEvent {} ", endPointURL); + log.info("Endpoint Url to send CDEvent {} ", endPointURL); return endPointURL; } catch (MalformedURLException e) { - throw new InvalidRequestException( - "Unable to determine base URL from Microsoft Teams webhook URL.", e); + throw new InvalidRequestException("Unable to determine CloudEvents broker address.", e); } } @@ -97,7 +96,7 @@ private String getRelativePath(String webhookUrl) { } } catch (MalformedURLException e) { throw new InvalidRequestException( - "Unable to determine relative path from Microsoft Teams webhook URL.", e); + "Unable to determine URL from CloudEvents broker address.", e); } // Remove slash from beginning of path as the client will prefix the string with a slash diff --git a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java index 1f67b771f..a6cd43172 100644 --- a/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java +++ b/echo-notifications/src/main/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgent.java @@ -1,18 +1,18 @@ /* - * Copyright 2020 Cerner Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ + Copyright (C) 2023 Nordix Foundation. + For a full list of individual contributors, please see the commit history. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + SPDX-License-Identifier: Apache-2.0 +*/ package com.netflix.spinnaker.echo.notification; diff --git a/echo-notifications/src/test/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgentSpec.groovy b/echo-notifications/src/test/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgentSpec.groovy index 77dd4e97a..868216c67 100644 --- a/echo-notifications/src/test/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgentSpec.groovy +++ b/echo-notifications/src/test/groovy/com/netflix/spinnaker/echo/notification/CDEventsNotificationAgentSpec.groovy @@ -1,18 +1,18 @@ /* - * Copyright 2016 Google, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License") - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ + Copyright (C) 2023 Nordix Foundation. + For a full list of individual contributors, please see the commit history. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + SPDX-License-Identifier: Apache-2.0 +*/ package com.netflix.spinnaker.echo.notification