Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RHCLOUD-22813] Handle provided context.host_url in integration templates #3221

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,27 @@ public class PagerDutyTransformer implements Processor {

public static final String ACCOUNT_ID = "account_id";
public static final String APPLICATION = "application";
public static final String APPLICATION_URL = "application_url";
public static final String BUNDLE = "bundle";
public static final String CLIENT = "client";
public static final String CLIENT_URL = "client_url";
public static final String CONTEXT = "context";
public static final String CUSTOM_DETAILS = "custom_details";
public static final String DISPLAY_NAME = "display_name";
public static final String ENVIRONMENT_URL = "environment_url";
public static final String EVENT_ACTION = "event_action";
public static final String EVENT_TYPE = "event_type";
public static final String EVENTS = "events";
public static final String GROUP = "group";
public static final String HREF = "href";
public static final String INVENTORY_URL = "inventory_url";
public static final String LINKS = "links";
jessicarod7 marked this conversation as resolved.
Show resolved Hide resolved
public static final String ORG_ID = "org_id";
public static final String SEVERITY = "severity";
public static final String SOURCE = "source";
public static final String SOURCE_NAMES = "source_names";
public static final String SUMMARY = "summary";
public static final String TIMESTAMP = "timestamp";
public static final String TEXT = "text";

public static final DateTimeFormatter PD_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS+0000");

Expand All @@ -52,7 +56,7 @@ public void process(Exchange exchange) {

JsonObject message = new JsonObject();
message.put(EVENT_ACTION, PagerDutyEventAction.TRIGGER);
message.mergeIn(getClientLink(cloudEventPayload, cloudEventPayload.getString(ENVIRONMENT_URL)));
message.mergeIn(getClientLinks(cloudEventPayload));

JsonObject messagePayload = new JsonObject();
messagePayload.put(SUMMARY, cloudEventPayload.getString(EVENT_TYPE));
Expand Down Expand Up @@ -92,7 +96,9 @@ public void process(Exchange exchange) {
exchange.getIn().setBody(message.encode());
}

/** Validates that the inputs for the required Alert Event fields are present */
/**
* Validates that the inputs for the required Alert Event fields are present
*/
private void validatePayload(final JsonObject cloudEventPayload) {
String summary = cloudEventPayload.getString(EVENT_TYPE);
if (summary == null || summary.isEmpty()) {
Expand All @@ -117,45 +123,33 @@ private void validatePayload(final JsonObject cloudEventPayload) {
}

/**
* Adapted from CamelProcessor template for Teams, with some changes to more gracefully handle missing fields
* <br>
* TODO update to work more consistently and with other platforms
*
* @return {@link #CLIENT} and {@link #CLIENT_URL}
* Performs the following link conversions:
* <ul>
* <li>{@link #APPLICATION} integrated into {@link #CLIENT}</li>
* <li>{@link #APPLICATION_URL} becomes {@link #CLIENT_URL}</li>
* <li>{@link #INVENTORY_URL}, if present, creates an entry in the {@link #LINKS} object</li>
* </ul>
* <p>
* The result is similar to the links provided in Microsoft Teams notifications.
*/
private JsonObject getClientLink(final JsonObject cloudEventPayload, String environmentUrl) {
JsonObject clientLink = new JsonObject();

String contextName = cloudEventPayload.containsKey(CONTEXT)
? cloudEventPayload.getJsonObject(CONTEXT).getString(DISPLAY_NAME)
: null;

if (contextName != null) {
clientLink.put(CLIENT, contextName);

String inventoryId = cloudEventPayload.getJsonObject(CONTEXT).getString("inventory_id");
if (environmentUrl != null && !environmentUrl.isEmpty() && inventoryId != null && !inventoryId.isEmpty()) {
clientLink.put(CLIENT_URL, String.format("%s/insights/inventory/%s",
environmentUrl,
cloudEventPayload.getJsonObject(CONTEXT).getString("inventory_id")
));
}
} else {
if (environmentUrl != null && !environmentUrl.isEmpty()) {
clientLink.put(CLIENT, String.format("Open %s", cloudEventPayload.getString(APPLICATION)));
clientLink.put(CLIENT_URL, String.format("%s/insights/%s",
environmentUrl,
cloudEventPayload.getString(APPLICATION)
));
} else {
clientLink.put(CLIENT, cloudEventPayload.getString(APPLICATION));
}
static JsonObject getClientLinks(final JsonObject cloudEventPayload) {
JsonObject clientLinks = new JsonObject();

clientLinks.put(CLIENT, String.format("Open %s", cloudEventPayload.getString(APPLICATION)));
clientLinks.put(CLIENT_URL, cloudEventPayload.getString(APPLICATION_URL));

String inventoryUrl = cloudEventPayload.getString(INVENTORY_URL, "");
if (!inventoryUrl.isEmpty()) {
clientLinks.put(LINKS, JsonObject.of(
HREF, inventoryUrl,
TEXT, "Host"
));
}

return clientLink;
return clientLinks;
}

private JsonObject getSourceNames(final JsonObject cloudSource) {
static JsonObject getSourceNames(final JsonObject cloudSource) {
if (cloudSource != null) {
JsonObject sourceNames = new JsonObject();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
package com.redhat.cloud.notifications.connector.pagerduty;

import com.redhat.cloud.notifications.ingress.Action;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;

import java.time.DateTimeException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Optional;

import static com.redhat.cloud.notifications.TestConstants.DEFAULT_ACCOUNT_ID;
import static com.redhat.cloud.notifications.TestConstants.DEFAULT_ORG_ID;
import static com.redhat.cloud.notifications.connector.authentication.AuthenticationType.SECRET_TOKEN;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyCloudEventDataExtractor.AUTHENTICATION;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.ACCOUNT_ID;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.APPLICATION;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.APPLICATION_URL;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.BUNDLE;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.CLIENT;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.CLIENT_URL;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.CONTEXT;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.CUSTOM_DETAILS;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.DISPLAY_NAME;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.ENVIRONMENT_URL;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.EVENTS;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.EVENT_ACTION;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.EVENT_TYPE;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.GROUP;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.INVENTORY_URL;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.ORG_ID;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.PAYLOAD;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.PD_DATE_TIME_FORMATTER;
Expand All @@ -31,9 +33,13 @@
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.SOURCE_NAMES;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.SUMMARY;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.TIMESTAMP;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.getClientLinks;
import static com.redhat.cloud.notifications.connector.pagerduty.PagerDutyTransformer.getSourceNames;

public class PagerDutyTestUtils {

static final String DEFAULT_ENVIRONMENT_URL = "https://console.redhat.com";

static JsonObject createCloudEventData(String url) {
JsonObject authentication = new JsonObject();
authentication.put("type", SECRET_TOKEN.name());
Expand All @@ -56,6 +62,10 @@ static JsonObject createIncomingPayload(JsonObject cloudEventData) {
payload.put(ACCOUNT_ID, DEFAULT_ACCOUNT_ID);
payload.put(APPLICATION, "default-application");
payload.put(BUNDLE, "default-bundle");
payload.put(CONTEXT, JsonObject.of(
DISPLAY_NAME, "console",
"inventory_id", "8a4a4f75-5319-4255-9eb5-1ee5a92efd7f"
));
payload.put(EVENT_TYPE, "default-event-type");
payload.put(EVENTS, JsonArray.of(
JsonObject.of("event-1-key", "event-1-value"),
Expand All @@ -76,7 +86,9 @@ static JsonObject createIncomingPayload(JsonObject cloudEventData) {
);

payload.put(SOURCE, source);
payload.put(ENVIRONMENT_URL, "https://console.redhat.com");
InsightsUrlsBuilder.buildInventoryUrl(payload)
.ifPresent(url -> payload.put(INVENTORY_URL, url));
payload.put(APPLICATION_URL, InsightsUrlsBuilder.buildApplicationUrl(payload));
payload.put(SEVERITY, PagerDutySeverity.WARNING);
cloudEventData.put(PAYLOAD, payload);

Expand All @@ -90,7 +102,7 @@ static JsonObject buildExpectedOutgoingPayload(final JsonObject incoming) {

JsonObject oldInnerPayload = expected.getJsonObject(PAYLOAD);
expected.put(EVENT_ACTION, PagerDutyEventAction.TRIGGER);
expected.mergeIn(getClientLink(oldInnerPayload, oldInnerPayload.getString(ENVIRONMENT_URL)));
expected.mergeIn(getClientLinks(oldInnerPayload));

JsonObject newInnerPayload = new JsonObject();
newInnerPayload.put(SUMMARY, oldInnerPayload.getString(EVENT_TYPE));
Expand Down Expand Up @@ -127,61 +139,97 @@ static JsonObject buildExpectedOutgoingPayload(final JsonObject incoming) {
expected.put(PAYLOAD, newInnerPayload);
return expected;
}
}

private static JsonObject getClientLink(final JsonObject oldInnerPayload, String environmentUrl) {
JsonObject clientLink = new JsonObject();
/**
* This class emulates the functionality of the same class within notifications-engine.
*/
class InsightsUrlsBuilder {
/**
* <p>Constructs an Insights URL corresponding to the specific inventory item which generated the notification.</p>
*
* <p>An inventory URL will only be generated if fields from one of these two formats are present:</p>
*
* <ul>
* <li>{@code { "context": { "host_url": "non_empty_string" }}}</li>
* <li>{@code { "context": { "inventory_id": "non_empty_string" }}}</li>
* <li>{@code { "context": { "display_name": "non_empty_string" } }}</li>
* </ul>
*
* <p>If neither field is present, an {@link Optional#empty()} will be returned. If expected fields of
* {@link Action#getBundle()} or {@link Action#getApplication()} are missing, an inaccurate URL may be returned.</p>
*
* @param data a payload converted by {@code BaseTransformer#toJsonObject(Event)}
* @return URL to the generating inventory item, if required fields are present
*/
static Optional<String> buildInventoryUrl(JsonObject data) {
String path;
ArrayList<String> queryParamParts = new ArrayList<>();
JsonObject context = data.getJsonObject("context");
if (context == null) {
return Optional.empty();
}

String contextName = oldInnerPayload.containsKey(CONTEXT)
? oldInnerPayload.getJsonObject(CONTEXT).getString(DISPLAY_NAME)
: null;
// A provided host url does not need to be modified
String host_url = context.getString("host_url", "");
if (!host_url.isEmpty()) {
return Optional.of(host_url);
}

if (contextName != null) {
clientLink.put(CLIENT, contextName);
String inventoryId = context.getString("inventory_id", "");
String displayName = context.getString("display_name", "");

String inventoryId = oldInnerPayload.getJsonObject(CONTEXT).getString("inventory_id");
if (environmentUrl != null && !environmentUrl.isEmpty() && inventoryId != null && !inventoryId.isEmpty()) {
clientLink.put(CLIENT_URL, String.format("%s/insights/inventory/%s",
environmentUrl,
oldInnerPayload.getJsonObject(CONTEXT).getString("inventory_id")
));
}
} else {
if (environmentUrl != null && !environmentUrl.isEmpty()) {
clientLink.put(CLIENT, String.format("Open %s", oldInnerPayload.getString(APPLICATION)));
clientLink.put(CLIENT_URL, String.format("%s/insights/%s",
environmentUrl,
oldInnerPayload.getString(APPLICATION)
));
if (!displayName.isEmpty()) {
if (data.getString("bundle", "").equals("openshift")
&& data.getString("application", "").equals("advisor")) {
path = String.format("/openshift/insights/advisor/clusters/%s", displayName);
} else {
clientLink.put(CLIENT, oldInnerPayload.getString(APPLICATION));
path = "/insights/inventory/";
if (!inventoryId.isEmpty()) {
path += inventoryId;
} else {
queryParamParts.add(String.format("hostname_or_id=%s", displayName));
}
}
} else {
return Optional.empty();
}

return clientLink;
}
if (!queryParamParts.isEmpty()) {
String queryParams = "?" + String.join("&", queryParamParts);
path += queryParams;
}

private static JsonObject getSourceNames(final JsonObject oldInnerSourceNames) {
if (oldInnerSourceNames != null) {
JsonObject newInnerSourceNames = new JsonObject();
return Optional.of(PagerDutyTestUtils.DEFAULT_ENVIRONMENT_URL + path);
}

JsonObject application = oldInnerSourceNames.getJsonObject(APPLICATION);
if (application != null) {
newInnerSourceNames.put(APPLICATION, application.getString(DISPLAY_NAME));
}
JsonObject bundle = oldInnerSourceNames.getJsonObject(BUNDLE);
if (bundle != null) {
newInnerSourceNames.put(BUNDLE, bundle.getString(DISPLAY_NAME));
}
JsonObject eventType = oldInnerSourceNames.getJsonObject(EVENT_TYPE);
if (eventType != null) {
newInnerSourceNames.put(EVENT_TYPE, eventType.getString(DISPLAY_NAME));
}
/**
* <p>Constructs an Insights URL corresponding to the specific inventory item which generated the notification.</p>
*
* <p>If the expected fields {@link Action#getApplication()} and {@link Action#getBundle()} are not present, an
* inaccurate URL may be returned.</p>
*
* @param data a payload converted by {@code BaseTransformer#toJsonObject(Event)}
* @return URL to the generating application
*/
static String buildApplicationUrl(JsonObject data) {
String path = "";

String bundle = data.getString("bundle", "");
String application = data.getString("application", "");

if (bundle.equals("openshift")) {
path = "openshift/";
}

if (!newInnerSourceNames.isEmpty()) {
return newInnerSourceNames;
}
if (application.equals("integrations")) {
path += "settings/";
} else {
path += "insights/";
}

return null;
path += application;

return String.format("%s/%s", PagerDutyTestUtils.DEFAULT_ENVIRONMENT_URL, path);
}
}
Loading
Loading