From eaa1569067d8371f4d10895da57a2ff3aae0480d Mon Sep 17 00:00:00 2001 From: Guillaume Duval <117720964+g-duval@users.noreply.github.com> Date: Tue, 24 Dec 2024 16:07:08 +0100 Subject: [PATCH] [RHCLOUD-36917] add Kessel error details into notifications history (#3224) --- .../email/CloudEventHistoryBuilder.java | 13 ++++++++ .../email/EmailExceptionProcessor.java | 24 ++++++++++++++ .../email/constants/ExchangeProperty.java | 2 ++ .../resolver/kessel/KesselService.java | 6 ++-- .../rest/RecipientsResolverResource.java | 22 +++++++++---- .../rest/WebApplicationExceptionMapper.java | 32 +++++++++++++++++++ 6 files changed, 89 insertions(+), 10 deletions(-) create mode 100644 connector-email/src/main/java/com/redhat/cloud/notifications/connector/email/EmailExceptionProcessor.java create mode 100644 recipients-resolver/src/main/java/com/redhat/cloud/notifications/recipients/rest/WebApplicationExceptionMapper.java diff --git a/connector-email/src/main/java/com/redhat/cloud/notifications/connector/email/CloudEventHistoryBuilder.java b/connector-email/src/main/java/com/redhat/cloud/notifications/connector/email/CloudEventHistoryBuilder.java index f5f055b6ca..e2b1628790 100644 --- a/connector-email/src/main/java/com/redhat/cloud/notifications/connector/email/CloudEventHistoryBuilder.java +++ b/connector-email/src/main/java/com/redhat/cloud/notifications/connector/email/CloudEventHistoryBuilder.java @@ -8,6 +8,8 @@ import org.apache.camel.Exchange; import org.apache.camel.Message; +import static com.redhat.cloud.notifications.connector.email.constants.ExchangeProperty.ADDITIONAL_ERROR_DETAILS; + @ApplicationScoped @Alternative @Priority(0) // The value doesn't matter. @@ -25,7 +27,18 @@ public void process(Exchange exchange) throws Exception { JsonObject data = new JsonObject(cloudEvent.getString("data")); data.getJsonObject("details").put(TOTAL_RECIPIENTS_KEY, totalRecipients); + if (exchange.getProperties().containsKey(ADDITIONAL_ERROR_DETAILS)) { + data.getJsonObject("details").put(ADDITIONAL_ERROR_DETAILS, getErrorDetail(exchange)); + } cloudEvent.put("data", data.encode()); in.setBody(cloudEvent.encode()); } + + private Object getErrorDetail(final Exchange exchange) { + try { + return new JsonObject(exchange.getProperty(ADDITIONAL_ERROR_DETAILS, String.class)); + } catch (Exception e) { + return exchange.getProperty(ADDITIONAL_ERROR_DETAILS, String.class); + } + } } diff --git a/connector-email/src/main/java/com/redhat/cloud/notifications/connector/email/EmailExceptionProcessor.java b/connector-email/src/main/java/com/redhat/cloud/notifications/connector/email/EmailExceptionProcessor.java new file mode 100644 index 0000000000..df4fc50502 --- /dev/null +++ b/connector-email/src/main/java/com/redhat/cloud/notifications/connector/email/EmailExceptionProcessor.java @@ -0,0 +1,24 @@ +package com.redhat.cloud.notifications.connector.email; + +import com.redhat.cloud.notifications.connector.http.HttpExceptionProcessor; +import jakarta.annotation.Priority; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Alternative; +import org.apache.camel.Exchange; +import org.apache.camel.http.base.HttpOperationFailedException; + +import static com.redhat.cloud.notifications.connector.email.constants.ExchangeProperty.ADDITIONAL_ERROR_DETAILS; + +@ApplicationScoped +@Alternative +@Priority(0) // The value doesn't matter. +public class EmailExceptionProcessor extends HttpExceptionProcessor { + + @Override + protected void process(Throwable t, Exchange exchange) { + super.process(t, exchange); + if (t instanceof HttpOperationFailedException e) { + exchange.setProperty(ADDITIONAL_ERROR_DETAILS, e.getResponseBody()); + } + } +} diff --git a/connector-email/src/main/java/com/redhat/cloud/notifications/connector/email/constants/ExchangeProperty.java b/connector-email/src/main/java/com/redhat/cloud/notifications/connector/email/constants/ExchangeProperty.java index edc6cafad4..b765f9ceb8 100644 --- a/connector-email/src/main/java/com/redhat/cloud/notifications/connector/email/constants/ExchangeProperty.java +++ b/connector-email/src/main/java/com/redhat/cloud/notifications/connector/email/constants/ExchangeProperty.java @@ -50,4 +50,6 @@ public class ExchangeProperty { public static final String USE_EMAIL_BOP_V1_SSL = "use_email_bop_V1_ssl"; public static final String RECIPIENTS_AUTHORIZATION_CRITERION = "recipients_authorization_criterion"; + + public static final String ADDITIONAL_ERROR_DETAILS = "additionalErrorDetails"; } diff --git a/recipients-resolver/src/main/java/com/redhat/cloud/notifications/recipients/resolver/kessel/KesselService.java b/recipients-resolver/src/main/java/com/redhat/cloud/notifications/recipients/resolver/kessel/KesselService.java index de487c0503..fdba08d068 100644 --- a/recipients-resolver/src/main/java/com/redhat/cloud/notifications/recipients/resolver/kessel/KesselService.java +++ b/recipients-resolver/src/main/java/com/redhat/cloud/notifications/recipients/resolver/kessel/KesselService.java @@ -103,12 +103,12 @@ public Set lookupSubjects(RecipientsAuthorizationCriterion recipientsAut Set userIds = new HashSet<>(); LookupSubjectsRequest request = getLookupSubjectsRequest(recipientsAuthorizationCriterion); + final String kesselAdditionalDomainName = String.format("%s/", recipientsResolverConfig.getKesselDomain()); for (Iterator it = lookupClient.lookupSubjects(request); it.hasNext();) { LookupSubjectsResponse response = it.next(); - Log.infof("Kessel response: %s", response); - - userIds.add(response.getSubject().getSubject().getId().replaceAll(recipientsResolverConfig.getKesselDomain(), "")); + userIds.add(response.getSubject().getSubject().getId().replaceAll(kesselAdditionalDomainName, "")); } + Log.infof("Kessel returned %d user(s) for request %s", userIds.size(), request); return userIds; } diff --git a/recipients-resolver/src/main/java/com/redhat/cloud/notifications/recipients/rest/RecipientsResolverResource.java b/recipients-resolver/src/main/java/com/redhat/cloud/notifications/recipients/rest/RecipientsResolverResource.java index 7048225ea0..ec1a3a5a6e 100644 --- a/recipients-resolver/src/main/java/com/redhat/cloud/notifications/recipients/rest/RecipientsResolverResource.java +++ b/recipients-resolver/src/main/java/com/redhat/cloud/notifications/recipients/rest/RecipientsResolverResource.java @@ -3,6 +3,7 @@ import com.redhat.cloud.notifications.recipients.model.User; import com.redhat.cloud.notifications.recipients.resolver.RecipientsResolver; import com.redhat.cloud.notifications.recipients.rest.pojo.RecipientsQuery; +import io.grpc.StatusRuntimeException; import jakarta.inject.Inject; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; @@ -10,6 +11,7 @@ import jakarta.ws.rs.PUT; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; +import jakarta.ws.rs.WebApplicationException; import java.util.Set; @@ -25,12 +27,18 @@ public class RecipientsResolverResource { @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) public Set getRecipients(@NotNull @Valid RecipientsQuery recipientsQuery) { - return recipientsResolver.findRecipients( - recipientsQuery.orgId, - recipientsQuery.recipientSettings, - recipientsQuery.subscribers, - recipientsQuery.unsubscribers, - recipientsQuery.subscribedByDefault, - recipientsQuery.recipientsAuthorizationCriterion); + try { + return recipientsResolver.findRecipients( + recipientsQuery.orgId, + recipientsQuery.recipientSettings, + recipientsQuery.subscribers, + recipientsQuery.unsubscribers, + recipientsQuery.subscribedByDefault, + recipientsQuery.recipientsAuthorizationCriterion); + } catch (StatusRuntimeException e) { + throw new WebApplicationException(String.format("Kessel error: %s", e.getMessage())); + } catch (Exception e) { + throw new WebApplicationException(e.getMessage()); + } } } diff --git a/recipients-resolver/src/main/java/com/redhat/cloud/notifications/recipients/rest/WebApplicationExceptionMapper.java b/recipients-resolver/src/main/java/com/redhat/cloud/notifications/recipients/rest/WebApplicationExceptionMapper.java new file mode 100644 index 0000000000..f99ef6bbef --- /dev/null +++ b/recipients-resolver/src/main/java/com/redhat/cloud/notifications/recipients/rest/WebApplicationExceptionMapper.java @@ -0,0 +1,32 @@ +package com.redhat.cloud.notifications.recipients.rest; + +import com.fasterxml.jackson.core.JsonParseException; +import io.quarkus.logging.Log; +import jakarta.ws.rs.BadRequestException; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; +import jakarta.ws.rs.ext.Provider; + +import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST; + +@Provider +public class WebApplicationExceptionMapper implements ExceptionMapper { + + + /** + * Map thrown Exceptions to Responses with appropriate status codes + */ + @Override + public Response toResponse(WebApplicationException exception) { + Log.error(exception); + if (exception instanceof BadRequestException) { + return Response.status(BAD_REQUEST).entity(exception.getMessage()).build(); + } + if (exception.getCause() != null && exception.getCause() instanceof JsonParseException) { + JsonParseException jsonParseException = (JsonParseException) exception.getCause(); + return Response.status(BAD_REQUEST).entity(jsonParseException.getMessage()).build(); + } + return Response.status(exception.getResponse().getStatus()).entity(exception.getMessage()).build(); + } +}