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

DRAFT: SWATCH-1924: Support querying prometheus/rhelemeter when "product" label has engIds #2747

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ public static Event createMetricEvent(
MetricId measuredMetric,
Double measuredValue,
String productTag,
UUID meteringBatchId) {
UUID meteringBatchId,
List<String> productIds) {
Event event = new Event();
updateMetricEvent(
event,
Expand All @@ -93,7 +94,8 @@ public static Event createMetricEvent(
measuredMetric,
measuredValue,
productTag,
meteringBatchId);
meteringBatchId,
productIds);
return event;
}

Expand Down Expand Up @@ -143,7 +145,8 @@ public static void updateMetricEvent(
MetricId measuredMetric,
Double measuredValue,
String productTag,
UUID meteringBatchId) {
UUID meteringBatchId,
List<String> productIds) {
toUpdate
.withServiceType(serviceType)
.withTimestamp(measuredTime)
Expand All @@ -160,7 +163,8 @@ public static void updateMetricEvent(
.withEventType(MeteringEventFactory.getEventType(measuredMetric.getValue(), productTag))
.withOrgId(orgId)
.withInstanceId(instanceId)
.withMeteringBatchId(meteringBatchId);
.withMeteringBatchId(meteringBatchId)
.withProductIds(productIds);
}

public static String getEventType(String metricId, String productTag) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,12 @@
import com.redhat.swatch.configuration.registry.MetricId;
import com.redhat.swatch.configuration.registry.SubscriptionDefinition;
import io.micrometer.core.annotation.Timed;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.BadRequestException;
import java.math.BigDecimal;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -197,11 +200,15 @@ private void sendEventFromData(
String product = labels.get("product");
String resourceName = labels.get("resource_name");

// TODO update this note
// NOTE: Role comes from the product label despite its name. The values set
// here are NOT engineering or swatch product IDs. They map to the roles in
// the swatch-product-configuration library. For openshift, the values will
// be 'ocp' or 'osd'.
String role = product == null ? resourceName : product;

List<String> productIds = extractProductIdsFromProductLabel(product);

String billingProvider = labels.get("billing_marketplace");
String billingAccountId = labels.get("billing_marketplace_account");

Expand All @@ -221,7 +228,7 @@ private void sendEventFromData(
Event event =
createOrUpdateEvent(
orgId,
tagMetric.getId(),
productIds,
clusterId,
sla,
usage,
Expand All @@ -243,6 +250,41 @@ private void sendEventFromData(
}
}

@NotNull
protected List<String> extractProductIdsFromProductLabel(String product) {
List<String> productIds = new ArrayList<>();

/*
The regular expression pattern matches a sequence of numbers separated by commas with optional spaces in between.

Explanation:
^ : Asserts the start of the line.
\d+ : Matches one or more digits (0-9).
( : Starts a group that contains the following sequence:
, : Matches a comma.
\s* : Matches zero or more whitespace characters.
\d+ : Matches one or more digits (0-9).
)*+ : The whole group can repeat zero or more times (including the comma followed by digits),
and the possessive quantifier (*+) prevents excessive backtracking.

Example:
- 123,456,789: Matches a sequence of numbers separated by commas and optional spaces: 123, 456, 789.
- 1,23,4: Matches a sequence of numbers separated by commas and optional spaces: 1, 23, 4.
- 100: Matches a single number: 100.

Note: This pattern may lead to catastrophic backtracking for extremely large inputs due to its repetitive nature.
*/

String pattern = "^\\d+(,\\s*\\d+)*+";

boolean isEngIdList = product != null && product.matches(pattern);

if (isEngIdList) {
productIds = Arrays.asList(product.split(","));
}
return productIds;
}

private void sendCleanUpEvent(
String productTag,
String orgId,
Expand All @@ -263,7 +305,7 @@ private void sendCleanUpEvent(
@SuppressWarnings("java:S107")
private Event createOrUpdateEvent(
String orgId,
String metricId,
List<String> productIds,
String instanceId,
String sla,
String usage,
Expand Down Expand Up @@ -294,7 +336,8 @@ private Event createOrUpdateEvent(
metric,
value.doubleValue(),
productTag,
meteringBatchId);
meteringBatchId,
productIds);
return event;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,8 @@ private Set<String> getProductIds(Event event) {
.ifPresent(productIds::add);
}

// TODO bookmark

var engIds = Optional.ofNullable(event.getProductIds()).orElse(Collections.emptyList());
for (String engId : engIds) {
productIds.addAll(
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/application-metrics-rhel.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ rhsm-subscriptions:
default: >-
max(#{metric.prometheus.queryParams[metric]}) by (#{metric.prometheus.queryParams[instanceKey]})
* on(#{metric.prometheus.queryParams[instanceKey]}) group_right
min_over_time(#{metric.prometheus.queryParams[metadataMetric]}{product="#{metric.prometheus.queryParams[product]}", external_organization="#{runtime[orgId]}", billing_model="marketplace", support=~"Premium|Standard|Self-Support|None"}[1h])
min_over_time(#{metric.prometheus.queryParams[metadataMetric]}{product=~"#{metric.prometheus.queryParams[product]}", external_organization="#{runtime[orgId]}", billing_model="marketplace", support=~"Premium|Standard|Self-Support|None"}[1h])
addonSamples: >-
max(#{metric.prometheus.queryParams[metric]}) by (#{metric.prometheus.queryParams[instanceKey]})
* on(#{metric.prometheus.queryParams[instanceKey]}) group_right
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ rhsm-subscriptions:
default: >-
max(#{metric.prometheus.queryParams[metric]}) by (#{metric.prometheus.queryParams[instanceKey]})
* on(#{metric.prometheus.queryParams[instanceKey]}) group_right
min_over_time(#{metric.prometheus.queryParams[metadataMetric]}{product="#{metric.prometheus.queryParams[product]}", external_organization="#{runtime[orgId]}", billing_model="marketplace", support=~"Premium|Standard|Self-Support|None"}[1h])
min_over_time(#{metric.prometheus.queryParams[metadataMetric]}{product=~"#{metric.prometheus.queryParams[product]}", external_organization="#{runtime[orgId]}", billing_model="marketplace", support=~"Premium|Standard|Self-Support|None"}[1h])
addonSamples: >-
max(#{metric.prometheus.queryParams[metric]}) by (#{metric.prometheus.queryParams[instanceKey]})
* on(#{metric.prometheus.queryParams[instanceKey]}) group_right
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ rhsm-subscriptions:
metric:
accountQueryTemplates:
default: >-
${OPENSHIFT_ENABLED_ACCOUNT_PROMQL:group(min_over_time(#{metric.prometheus.queryParams[metadataMetric]}{product='#{metric.prometheus.queryParams[product]}', external_organization != '', billing_model='marketplace'}[1h]))
${OPENSHIFT_ENABLED_ACCOUNT_PROMQL:group(min_over_time(#{metric.prometheus.queryParams[metadataMetric]}{product=~'#{metric.prometheus.queryParams[product]}', external_organization != '', billing_model='marketplace'}[1h]))
by (external_organization)}
addonSamples: >-
${OPENSHIFT_ENABLED_ACCOUNT_PROMQL:group(min_over_time(#{metric.prometheus.queryParams[metadataMetric]}{resource_type="addon", resource_name='#{metric.prometheus.queryParams[resourceName]}', external_organization != '', billing_model='marketplace'}[1h]))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.redhat.swatch.configuration.registry.MetricId;
import com.redhat.swatch.configuration.util.MetricIdUtils;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.candlepin.subscriptions.json.Event;
Expand Down Expand Up @@ -73,7 +74,8 @@ void testOpenShiftClusterCoresEventCreation() {
uom,
measuredValue,
productTag,
meteringBatchId);
meteringBatchId,
List.of());

assertEquals(orgId, event.getOrgId());
assertEquals(measuredTime, event.getTimestamp());
Expand Down Expand Up @@ -111,7 +113,8 @@ void testOpenShiftClusterCoresHandlesNullServiceLevel() {
MetricIdUtils.getCores(),
12.5,
productTag,
UUID.randomUUID());
UUID.randomUUID(),
List.of());
assertNull(event.getSla());
}

Expand All @@ -133,7 +136,8 @@ void testOpenShiftClusterCoresSlaSetToEmptyForSlaValueNone() {
MetricIdUtils.getCores(),
12.5,
productTag,
UUID.randomUUID());
UUID.randomUUID(),
List.of());
assertEquals(Sla.__EMPTY__, event.getSla());
}

Expand All @@ -155,7 +159,8 @@ void testOpenShiftClusterCoresInvalidSlaWillNotBeSetOnEvent() {
MetricIdUtils.getCores(),
12.5,
productTag,
UUID.randomUUID());
UUID.randomUUID(),
List.of());
assertNull(event.getSla());
}

Expand All @@ -177,7 +182,8 @@ void testOpenShiftClusterCoresInvalidUsageSetsNullValue() {
MetricIdUtils.getCores(),
12.5,
productTag,
UUID.randomUUID());
UUID.randomUUID(),
List.of());
assertNull(event.getUsage());
}

Expand All @@ -199,7 +205,8 @@ void testOpenShiftClusterCoresHandlesNullUsage() {
MetricIdUtils.getCores(),
12.5,
productTag,
UUID.randomUUID());
UUID.randomUUID(),
List.of());
assertNull(event.getUsage());
}

Expand All @@ -221,7 +228,8 @@ void testOpenShiftClusterCoresInvalidRoleSetsNullValue() {
MetricIdUtils.getCores(),
12.5,
productTag,
UUID.randomUUID());
UUID.randomUUID(),
List.of());
assertNull(event.getRole());
}

Expand All @@ -243,7 +251,8 @@ void testOpenShiftClusterCoresHandlesNullRole() {
MetricIdUtils.getCores(),
12.5,
productTag,
UUID.randomUUID());
UUID.randomUUID(),
List.of());
assertNull(event.getRole());
}

Expand All @@ -265,7 +274,8 @@ void testHandlesValidBillingData() {
MetricIdUtils.getCores(),
12.5,
productTag,
UUID.randomUUID());
UUID.randomUUID(),
List.of());
assertEquals(BillingProvider.AWS, event.getBillingProvider());
assertTrue(event.getBillingAccountId().isPresent());
assertEquals("aws_account_123", event.getBillingAccountId().get());
Expand All @@ -289,7 +299,8 @@ void testHandlesNullBillingData() {
MetricIdUtils.getCores(),
12.5,
productTag,
UUID.randomUUID());
UUID.randomUUID(),
List.of());
assertEquals(BillingProvider.RED_HAT, event.getBillingProvider());
assertTrue(event.getBillingAccountId().isEmpty());
}
Expand All @@ -312,7 +323,8 @@ void testBillingProviderEmptyForBillingProviderValueNoneToDefaultRedHat() {
MetricIdUtils.getCores(),
12.5,
productTag,
UUID.randomUUID());
UUID.randomUUID(),
List.of());
assertEquals(BillingProvider.RED_HAT, event.getBillingProvider());
}

Expand All @@ -334,7 +346,8 @@ void testInvalidBillingProviderWillNotBeSetOnEvent() {
MetricIdUtils.getCores(),
12.5,
productTag,
UUID.randomUUID());
UUID.randomUUID(),
List.of());
assertNull(event.getBillingProvider());
}

Expand All @@ -356,7 +369,8 @@ void testEventTypeGeneratedOnEventCreation() {
MetricIdUtils.getCores(),
12.5,
productTag,
UUID.randomUUID());
UUID.randomUUID(),
List.of());
assertEquals("snapshot_openshift-dedicated-metrics_cores", event.getEventType());
}

Expand Down Expand Up @@ -386,7 +400,8 @@ void testRhmNormalizedToRedHat() {
MetricIdUtils.getCores(),
12.5,
productTag,
UUID.randomUUID());
UUID.randomUUID(),
List.of());
assertEquals(BillingProvider.RED_HAT, event.getBillingProvider());
}
}