From 533c4c464cab127c4cb63ae902ee0f403b0b619f Mon Sep 17 00:00:00 2001 From: Levin Kerschberger Date: Tue, 27 Aug 2024 14:15:57 +0200 Subject: [PATCH] Feat: VHVAPM-530/531 --- .gitignore | 3 + backend/build.gradle | 10 +++ .../controller/ConfigurationController.java | 40 +++++++++++ .../model/InspectitConfiguration.java | 17 +++++ .../InstrumentationConfiguration.java | 20 ++++++ .../model/instrumentation/Scope.java | 24 +++++++ .../service/ConfigurationService.java | 19 +++++ .../controller/ConnectionController.java | 4 ++ backend/src/main/resources/application.yaml | 12 ++++ .../ConfigurationControllerTest.java | 71 +++++++++++++++++++ 10 files changed, 220 insertions(+) create mode 100644 backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/controller/ConfigurationController.java create mode 100644 backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/model/InspectitConfiguration.java create mode 100644 backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/model/instrumentation/InstrumentationConfiguration.java create mode 100644 backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/model/instrumentation/Scope.java create mode 100644 backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/service/ConfigurationService.java create mode 100644 backend/src/test/java/rocks/inspectit/gepard/agentmanager/configuration/controller/ConfigurationControllerTest.java diff --git a/.gitignore b/.gitignore index 4620c279..2931085f 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,6 @@ fabric.properties /ui/build_packageClient/ **/.DS_Store + +**/node_modules +**/.nuxt diff --git a/backend/build.gradle b/backend/build.gradle index 5703d34b..fd9fb446 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -30,8 +30,18 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-validation' annotationProcessor 'org.projectlombok:lombok' + + // Actuator - for management endpoints + implementation 'org.springframework.boot:spring-boot-starter-actuator' + // Swagger - for API documentation + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0' + + // Test testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + + // Management + } tasks.named('test') { diff --git a/backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/controller/ConfigurationController.java b/backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/controller/ConfigurationController.java new file mode 100644 index 00000000..0cc7b700 --- /dev/null +++ b/backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/controller/ConfigurationController.java @@ -0,0 +1,40 @@ +/* (C) 2024 */ +package rocks.inspectit.gepard.agentmanager.configuration.controller; + +import io.swagger.v3.oas.annotations.Operation; +import jakarta.validation.Valid; +import java.util.Objects; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import rocks.inspectit.gepard.agentmanager.configuration.model.InspectitConfiguration; +import rocks.inspectit.gepard.agentmanager.configuration.service.ConfigurationService; + +@RestController +@RequestMapping("/api/v1/agent-configuration") +@RequiredArgsConstructor +public class ConfigurationController { + + private final ConfigurationService configurationService; + + @GetMapping + @Operation(summary = "Get the agent configuration.") + public ResponseEntity getAgentConfiguration() { + InspectitConfiguration configuration = configurationService.getConfiguration(); + + // No config available + if (Objects.isNull(configuration)) { + return ResponseEntity.noContent().build(); + } + + return ResponseEntity.ok().body(configurationService.getConfiguration()); + } + + @PutMapping + @Operation(summary = "Update the agent configuration.") + public ResponseEntity updateAgentConfiguration( + @Valid @RequestBody InspectitConfiguration configuration) { + configurationService.updateConfiguration(configuration); + return ResponseEntity.ok().build(); + } +} diff --git a/backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/model/InspectitConfiguration.java b/backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/model/InspectitConfiguration.java new file mode 100644 index 00000000..521e34d2 --- /dev/null +++ b/backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/model/InspectitConfiguration.java @@ -0,0 +1,17 @@ +/* (C) 2024 */ +package rocks.inspectit.gepard.agentmanager.configuration.model; + +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import rocks.inspectit.gepard.agentmanager.configuration.model.instrumentation.InstrumentationConfiguration; + +/** Model of an inspectit gepard configuration. */ +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class InspectitConfiguration { + + @Valid private InstrumentationConfiguration instrumentation = new InstrumentationConfiguration(); +} diff --git a/backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/model/instrumentation/InstrumentationConfiguration.java b/backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/model/instrumentation/InstrumentationConfiguration.java new file mode 100644 index 00000000..a2a07e4e --- /dev/null +++ b/backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/model/instrumentation/InstrumentationConfiguration.java @@ -0,0 +1,20 @@ +/* (C) 2024 */ +package rocks.inspectit.gepard.agentmanager.configuration.model.instrumentation; + +import jakarta.validation.Valid; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * The Instrumentation Configuration contains all configuration related to instrumentation. e.g + * scopes, rules, actions. + */ +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class InstrumentationConfiguration { + + @Valid private List scopes = List.of(); +} diff --git a/backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/model/instrumentation/Scope.java b/backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/model/instrumentation/Scope.java new file mode 100644 index 00000000..2bbce88c --- /dev/null +++ b/backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/model/instrumentation/Scope.java @@ -0,0 +1,24 @@ +/* (C) 2024 */ +package rocks.inspectit.gepard.agentmanager.configuration.model.instrumentation; + +import jakarta.validation.constraints.NotNull; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * Represents a scope in the instrumentation configuration. A scope defines a set of methods which + * should be instrumented. + */ +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class Scope { + + @NotNull(message = "Fqn is missing.") private String fqn; + + private List methods = List.of(); + + private boolean enabled = false; +} diff --git a/backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/service/ConfigurationService.java b/backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/service/ConfigurationService.java new file mode 100644 index 00000000..3ff00ab9 --- /dev/null +++ b/backend/src/main/java/rocks/inspectit/gepard/agentmanager/configuration/service/ConfigurationService.java @@ -0,0 +1,19 @@ +/* (C) 2024 */ +package rocks.inspectit.gepard.agentmanager.configuration.service; + +import org.springframework.stereotype.Service; +import rocks.inspectit.gepard.agentmanager.configuration.model.InspectitConfiguration; + +@Service +public class ConfigurationService { + + private InspectitConfiguration inspectitConfiguration; + + public InspectitConfiguration getConfiguration() { + return inspectitConfiguration; + } + + public void updateConfiguration(InspectitConfiguration configuration) { + inspectitConfiguration = configuration; + } +} diff --git a/backend/src/main/java/rocks/inspectit/gepard/agentmanager/connection/controller/ConnectionController.java b/backend/src/main/java/rocks/inspectit/gepard/agentmanager/connection/controller/ConnectionController.java index 4c6bed35..569085c7 100644 --- a/backend/src/main/java/rocks/inspectit/gepard/agentmanager/connection/controller/ConnectionController.java +++ b/backend/src/main/java/rocks/inspectit/gepard/agentmanager/connection/controller/ConnectionController.java @@ -1,6 +1,7 @@ /* (C) 2024 */ package rocks.inspectit.gepard.agentmanager.connection.controller; +import io.swagger.v3.oas.annotations.Operation; import jakarta.validation.Valid; import java.util.List; import java.util.UUID; @@ -25,6 +26,7 @@ public class ConnectionController { private final ConnectionService connectionService; @PostMapping + @Operation(summary = "Connect an agent to the agent manager.") public ResponseEntity connect(@Valid @RequestBody CreateConnectionRequest connectRequest) { Connection connection = connectionService.handleConnectRequest(connectRequest); return ResponseEntity.created( @@ -36,11 +38,13 @@ public ResponseEntity connect(@Valid @RequestBody CreateConnectionRequest } @GetMapping + @Operation(summary = "Get all connections.") public ResponseEntity> getConnections() { return ResponseEntity.ok(connectionService.getConnections()); } @GetMapping("/{id}") + @Operation(summary = "Get a connection by id.") public ResponseEntity getConnection(@PathVariable UUID id) { return ResponseEntity.ok(connectionService.getConnection(id)); } diff --git a/backend/src/main/resources/application.yaml b/backend/src/main/resources/application.yaml index 9a918fe3..d960767d 100644 --- a/backend/src/main/resources/application.yaml +++ b/backend/src/main/resources/application.yaml @@ -18,6 +18,18 @@ server: bundle: "server" enabled-protocols: "TLSv1.3" +management: + server: + port: 9090 + endpoints: + web: + exposure: + include: "openapi, swagger-ui" + +springdoc: + show-actuator: true + use-management-port: true + inspectit: gepard: security: diff --git a/backend/src/test/java/rocks/inspectit/gepard/agentmanager/configuration/controller/ConfigurationControllerTest.java b/backend/src/test/java/rocks/inspectit/gepard/agentmanager/configuration/controller/ConfigurationControllerTest.java new file mode 100644 index 00000000..dabc3b64 --- /dev/null +++ b/backend/src/test/java/rocks/inspectit/gepard/agentmanager/configuration/controller/ConfigurationControllerTest.java @@ -0,0 +1,71 @@ +/* (C) 2024 */ +package rocks.inspectit.gepard.agentmanager.configuration.controller; + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import rocks.inspectit.gepard.agentmanager.configuration.model.InspectitConfiguration; +import rocks.inspectit.gepard.agentmanager.configuration.model.instrumentation.InstrumentationConfiguration; +import rocks.inspectit.gepard.agentmanager.configuration.model.instrumentation.Scope; +import rocks.inspectit.gepard.agentmanager.configuration.service.ConfigurationService; + +@WebMvcTest(controllers = ConfigurationController.class) +class ConfigurationControllerTest { + + @Autowired private MockMvc mockMvc; + + @Autowired private ObjectMapper objectMapper; + + @MockBean private ConfigurationService configurationService; + + @Test + void getConfiguration_whenNoConfigAvailable_shouldReturnNoContent() throws Exception { + + when(configurationService.getConfiguration()).thenReturn(null); + + mockMvc.perform(get("/api/v1/agent-configuration")).andExpect(status().isNoContent()); + } + + @Test + void getConfiguration_whenConfigAvailable_shouldReturnOk() throws Exception { + when(configurationService.getConfiguration()).thenReturn(new InspectitConfiguration()); + + mockMvc + .perform(get("/api/v1/agent-configuration")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(content().json(objectMapper.writeValueAsString(new InspectitConfiguration()))); + } + + @Test + void updateConfiguration_shouldReturnOkAndConfiguration() throws Exception { + + InspectitConfiguration configuration = createConfiguration(); + + when(configurationService.getConfiguration()).thenReturn(configuration); + + mockMvc + .perform( + get("/api/v1/agent-configuration") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(configuration))) + .andExpect(status().isOk()); + } + + private InspectitConfiguration createConfiguration() { + Scope scope = new Scope("org.test.package", List.of("testMethod"), true); + InstrumentationConfiguration instrumentationConfiguration = + new InstrumentationConfiguration(List.of(scope)); + return new InspectitConfiguration(instrumentationConfiguration); + } +}