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-35690] Add Kessel successes and Failures metrics #3236

Merged
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 @@ -26,6 +26,12 @@ public class KesselAssets {
*/
private static final String KESSEL_METRICS_INVENTORY_INTEGRATION_TIMER_NAME = "notifications.kessel.inventory.resources";

protected static final String KESSEL_METRICS_INVENTORY_INTEGRATION_COUNTER_NAME = "notifications.kessel.inventory.integration.count";

protected static final String COUNTER_TAG_FAILURES = "failures";
protected static final String COUNTER_TAG_REQUEST_RESULT = "result";
protected static final String COUNTER_TAG_SUCCESSES = "successes";

@Inject
BackendConfig backendConfig;

Expand Down Expand Up @@ -63,12 +69,13 @@ public void createIntegration(final SecurityContext securityContext, final Strin
"[identity: %s][workspace_id: %s][integration_id: %s] Unable to create integration in Kessel's inventory",
SecurityContextUtil.extractRhIdentity(securityContext), workspaceId, integrationId, request
);

meterRegistry.counter(KESSEL_METRICS_INVENTORY_INTEGRATION_COUNTER_NAME, Tags.of(COUNTER_TAG_REQUEST_RESULT, COUNTER_TAG_FAILURES)).increment();
throw e;
} finally {
// Stop the timer.
createIntegrationTimer.stop(this.meterRegistry.timer(KESSEL_METRICS_INVENTORY_INTEGRATION_TIMER_NAME, Tags.of(Constants.KESSEL_METRICS_TAG_RESOURCE_TYPE_KEY, ResourceType.INTEGRATION.name())));
}

// Stop the timer.
createIntegrationTimer.stop(this.meterRegistry.timer(KESSEL_METRICS_INVENTORY_INTEGRATION_TIMER_NAME, Tags.of(Constants.KESSEL_METRICS_TAG_RESOURCE_TYPE_KEY, ResourceType.INTEGRATION.name())));
meterRegistry.counter(KESSEL_METRICS_INVENTORY_INTEGRATION_COUNTER_NAME, Tags.of(COUNTER_TAG_REQUEST_RESULT, COUNTER_TAG_SUCCESSES)).increment();

Log.tracef("[identity: %s][workspace_id: %s][integration_id: %s] Received payload for the integration creation in Kessel's inventory: %s", SecurityContextUtil.extractRhIdentity(securityContext), workspaceId, integrationId, response);
Log.debugf("[identity: %s][workspace_id: %s][integration_id: %s] Integration created in Kessel's inventory", SecurityContextUtil.extractRhIdentity(securityContext), workspaceId, integrationId);
Expand Down Expand Up @@ -102,12 +109,14 @@ public void deleteIntegration(final SecurityContext securityContext, final Strin
"[identity: %s][workspace_id: %s][integration_id: %s] Unable to delete integration in Kessel's inventory",
SecurityContextUtil.extractRhIdentity(securityContext), workspaceId, integrationId, request
);
meterRegistry.counter(KESSEL_METRICS_INVENTORY_INTEGRATION_COUNTER_NAME, Tags.of(COUNTER_TAG_REQUEST_RESULT, COUNTER_TAG_FAILURES)).increment();

throw e;
} finally {
// Stop the timer.
deleteIntegrationTimer.stop(this.meterRegistry.timer(KESSEL_METRICS_INVENTORY_INTEGRATION_TIMER_NAME, Tags.of(Constants.KESSEL_METRICS_TAG_RESOURCE_TYPE_KEY, ResourceType.INTEGRATION.name())));
}

// Stop the timer.
deleteIntegrationTimer.stop(this.meterRegistry.timer(KESSEL_METRICS_INVENTORY_INTEGRATION_TIMER_NAME, Tags.of(Constants.KESSEL_METRICS_TAG_RESOURCE_TYPE_KEY, ResourceType.INTEGRATION.name())));
meterRegistry.counter(KESSEL_METRICS_INVENTORY_INTEGRATION_COUNTER_NAME, Tags.of(COUNTER_TAG_REQUEST_RESULT, COUNTER_TAG_SUCCESSES)).increment();

Log.tracef("[identity: %s][workspace_id: %s][integration_id: %s] Received payload for the integration removal in Kessel's inventory: %s", SecurityContextUtil.extractRhIdentity(securityContext), workspaceId, integrationId, response);
Log.debugf("[identity: %s][workspace_id: %s][integration_id: %s] Integration deleted in Kessel's inventory", SecurityContextUtil.extractRhIdentity(securityContext), workspaceId, integrationId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ public class KesselAuthorization {
* particular permission for a subject.
*/
private static final String KESSEL_METRICS_PERMISSION_CHECK_TIMER_NAME = "notifications.kessel.relationships.permission.check.requests";
/**
* Represents the counter name to count permission check requests.
*/
public static final String KESSEL_METRICS_PERMISSION_CHECK_COUNTER_NAME = "notifications.kessel.relationships.permission.check.count";
/**
* Represents the counter name to count lookup resources requests.
*/
public static final String KESSEL_METRICS_LOOKUP_RESOURCES_COUNTER_NAME = "notifications.kessel.relationships.lookup.check.count";

protected static final String COUNTER_TAG_FAILURES = "failures";
protected static final String COUNTER_TAG_REQUEST_RESULT = "result";
protected static final String COUNTER_TAG_SUCCESSES = "successes";

@Inject
CheckClient checkClient;
Expand Down Expand Up @@ -102,12 +114,14 @@ public void hasPermissionOnResource(final SecurityContext securityContext, final
"[identity: %s][permission: %s][resource_type: %s][resource_id: %s] Unable to query Kessel for a permission on a resource",
identity, permission, resourceType, resourceId
);

meterRegistry.counter(KESSEL_METRICS_PERMISSION_CHECK_COUNTER_NAME, Tags.of(COUNTER_TAG_REQUEST_RESULT, COUNTER_TAG_FAILURES)).increment();
throw e;
} finally {
// Stop the timer.
permissionCheckTimer.stop(this.meterRegistry.timer(KESSEL_METRICS_PERMISSION_CHECK_TIMER_NAME, Tags.of(KESSEL_METRICS_TAG_PERMISSION_KEY, permission.getKesselPermissionName(), Constants.KESSEL_METRICS_TAG_RESOURCE_TYPE_KEY, resourceType.name())));
}

// Stop the timer.
permissionCheckTimer.stop(this.meterRegistry.timer(KESSEL_METRICS_PERMISSION_CHECK_TIMER_NAME, Tags.of(KESSEL_METRICS_TAG_PERMISSION_KEY, permission.getKesselPermissionName(), Constants.KESSEL_METRICS_TAG_RESOURCE_TYPE_KEY, resourceType.name())));
meterRegistry.counter(KESSEL_METRICS_PERMISSION_CHECK_COUNTER_NAME, Tags.of(COUNTER_TAG_REQUEST_RESULT, COUNTER_TAG_SUCCESSES)).increment();

Log.tracef("[identity: %s][permission: %s][resource_type: %s][resource_id: %s] Received payload for the permission check: %s", identity, permission, resourceType, resourceId, response);

Expand Down Expand Up @@ -152,12 +166,15 @@ public Set<UUID> lookupAuthorizedIntegrations(final SecurityContext securityCont
"[identity: %s][permission: %s][resource_type: %s] Runtime error when querying Kessel for integration resources with request payload: %s",
identity, integrationPermission, ResourceType.INTEGRATION, request
);
meterRegistry.counter(KESSEL_METRICS_LOOKUP_RESOURCES_COUNTER_NAME, Tags.of(COUNTER_TAG_REQUEST_RESULT, COUNTER_TAG_FAILURES)).increment();

throw e;
} finally {
// Stop the timer.
lookupTimer.stop(this.meterRegistry.timer(KESSEL_METRICS_LOOKUP_RESOURCES_TIMER_NAME, Tags.of(KESSEL_METRICS_TAG_PERMISSION_KEY, integrationPermission.getKesselPermissionName(), Constants.KESSEL_METRICS_TAG_RESOURCE_TYPE_KEY, ResourceType.INTEGRATION.name())));
}

// Stop the timer.
lookupTimer.stop(this.meterRegistry.timer(KESSEL_METRICS_LOOKUP_RESOURCES_TIMER_NAME, Tags.of(KESSEL_METRICS_TAG_PERMISSION_KEY, integrationPermission.getKesselPermissionName(), Constants.KESSEL_METRICS_TAG_RESOURCE_TYPE_KEY, ResourceType.INTEGRATION.name())));
meterRegistry.counter(KESSEL_METRICS_LOOKUP_RESOURCES_COUNTER_NAME, Tags.of(COUNTER_TAG_REQUEST_RESULT, COUNTER_TAG_SUCCESSES)).increment();

// Process the incoming responses.
final Set<UUID> uuids = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.redhat.cloud.notifications.auth.kessel;

import com.redhat.cloud.notifications.MicrometerAssertionHelper;
import com.redhat.cloud.notifications.auth.principal.ConsolePrincipal;
import com.redhat.cloud.notifications.auth.principal.rhid.RhIdPrincipal;
import com.redhat.cloud.notifications.auth.principal.rhid.RhIdentity;
Expand All @@ -9,7 +10,9 @@
import io.quarkus.test.junit.mockito.InjectSpy;
import jakarta.inject.Inject;
import jakarta.ws.rs.core.SecurityContext;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.project_kessel.api.inventory.v1beta1.resources.CreateNotificationsIntegrationRequest;
Expand All @@ -20,6 +23,11 @@

import java.util.UUID;

import static com.redhat.cloud.notifications.auth.kessel.KesselAssets.KESSEL_METRICS_INVENTORY_INTEGRATION_COUNTER_NAME;
import static com.redhat.cloud.notifications.auth.kessel.KesselAuthorization.COUNTER_TAG_FAILURES;
import static com.redhat.cloud.notifications.auth.kessel.KesselAuthorization.COUNTER_TAG_REQUEST_RESULT;
import static com.redhat.cloud.notifications.auth.kessel.KesselAuthorization.COUNTER_TAG_SUCCESSES;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;

@QuarkusTest
Expand All @@ -33,22 +41,23 @@ public class KesselAssetsTest {
@InjectMock
NotificationsIntegrationClient notificationsIntegrationClient;

@Inject
MicrometerAssertionHelper micrometerAssertionHelper;

@BeforeEach
void beforeEach() {
// save counter values
saveCounterValues();
}

/**
* Test that the function under test calls the Kessel inventory to create
* the integration.
*/
@Test
void testCreateIntegration() {
// Mock the security context.
final SecurityContext mockedSecurityContext = Mockito.mock(SecurityContext.class);

// Create a RhIdentity principal and assign it to the mocked security
// context.
final RhIdentity identity = Mockito.mock(RhIdentity.class);
Mockito.when(identity.getName()).thenReturn("Red Hat user");

final ConsolePrincipal<?> principal = new RhIdPrincipal(identity);
Mockito.when(mockedSecurityContext.getUserPrincipal()).thenReturn(principal);
final SecurityContext mockedSecurityContext = this.initMockedSecurityContextWithRhIdentity();

// Enable the Kessel back end integration for this test.
Mockito.when(this.backendConfig.isKesselRelationsEnabled(anyString())).thenReturn(true);
Expand All @@ -58,6 +67,8 @@ void testCreateIntegration() {

// Verify that the inventory call was made.
Mockito.verify(this.notificationsIntegrationClient, Mockito.times(1)).CreateNotificationsIntegration(Mockito.any(CreateNotificationsIntegrationRequest.class));

assertCounterIncrements(1, 0);
}

/**
Expand All @@ -67,15 +78,7 @@ void testCreateIntegration() {
@Test
void testDeleteIntegration() {
// Mock the security context.
final SecurityContext mockedSecurityContext = Mockito.mock(SecurityContext.class);

// Create a RhIdentity principal and assign it to the mocked security
// context.
final RhIdentity identity = Mockito.mock(RhIdentity.class);
Mockito.when(identity.getName()).thenReturn("Red Hat user");

final ConsolePrincipal<?> principal = new RhIdPrincipal(identity);
Mockito.when(mockedSecurityContext.getUserPrincipal()).thenReturn(principal);
final SecurityContext mockedSecurityContext = this.initMockedSecurityContextWithRhIdentity();

// Enable the Kessel back end integration for this test.
Mockito.when(this.backendConfig.isKesselRelationsEnabled(anyString())).thenReturn(true);
Expand All @@ -85,6 +88,35 @@ void testDeleteIntegration() {

// Verify that the inventory call was made.
Mockito.verify(this.notificationsIntegrationClient, Mockito.times(1)).DeleteNotificationsIntegration(Mockito.any(DeleteNotificationsIntegrationRequest.class));

assertCounterIncrements(1, 0);
}


/**
* Tests failures calling Kessel inventory api
*/
@Test
void testCreateAndDeleteFailures() {
// Mock the security context.
final SecurityContext mockedSecurityContext = this.initMockedSecurityContextWithRhIdentity();

Mockito.when(this.notificationsIntegrationClient.CreateNotificationsIntegration(any(CreateNotificationsIntegrationRequest.class))).thenThrow(RuntimeException.class);
Mockito.when(this.notificationsIntegrationClient.DeleteNotificationsIntegration(any(DeleteNotificationsIntegrationRequest.class))).thenThrow(RuntimeException.class);

// Call the function under test.
Assertions.assertThrows(
RuntimeException.class,
() -> this.kesselAssets.deleteIntegration(mockedSecurityContext, UUID.randomUUID().toString(), UUID.randomUUID().toString())
);
assertCounterIncrements(0, 1);

// Call the function under test.
Assertions.assertThrows(
RuntimeException.class,
() -> this.kesselAssets.createIntegration(mockedSecurityContext, UUID.randomUUID().toString(), UUID.randomUUID().toString())
);
assertCounterIncrements(0, 2);
}

/**
Expand Down Expand Up @@ -127,4 +159,31 @@ void testBuildDeleteIntegrationRequest() {
Assertions.assertEquals(this.backendConfig.getKesselInventoryReporterInstanceId(), reporterData.getReporterInstanceId(), "the \"reporter instance id\" was incorrectly set");
Assertions.assertEquals(ReporterData.ReporterType.NOTIFICATIONS, reporterData.getReporterType(), "the \"reporter type\" was incorrectly set");
}

/**
* Mock the security context.
*/
private static @NotNull SecurityContext initMockedSecurityContextWithRhIdentity() {
// Mock the security context.
final SecurityContext mockedSecurityContext = Mockito.mock(SecurityContext.class);

// Create a RhIdentity principal and assign it to the mocked security
// context.
final RhIdentity identity = Mockito.mock(RhIdentity.class);
Mockito.when(identity.getName()).thenReturn("Red Hat user");

final ConsolePrincipal<?> principal = new RhIdPrincipal(identity);
Mockito.when(mockedSecurityContext.getUserPrincipal()).thenReturn(principal);
return mockedSecurityContext;
}

private void saveCounterValues() {
this.micrometerAssertionHelper.saveCounterValueFilteredByTagsBeforeTest(KESSEL_METRICS_INVENTORY_INTEGRATION_COUNTER_NAME, COUNTER_TAG_REQUEST_RESULT, COUNTER_TAG_SUCCESSES);
this.micrometerAssertionHelper.saveCounterValueFilteredByTagsBeforeTest(KESSEL_METRICS_INVENTORY_INTEGRATION_COUNTER_NAME, COUNTER_TAG_REQUEST_RESULT, COUNTER_TAG_FAILURES);
}

private void assertCounterIncrements(final int expectedSuccesses, final int expectedFailures) {
this.micrometerAssertionHelper.assertCounterValueFilteredByTagsIncrement(KESSEL_METRICS_INVENTORY_INTEGRATION_COUNTER_NAME, COUNTER_TAG_REQUEST_RESULT, COUNTER_TAG_SUCCESSES, expectedSuccesses);
this.micrometerAssertionHelper.assertCounterValueFilteredByTagsIncrement(KESSEL_METRICS_INVENTORY_INTEGRATION_COUNTER_NAME, COUNTER_TAG_REQUEST_RESULT, COUNTER_TAG_FAILURES, expectedFailures);
}
}
Loading
Loading