Skip to content

Commit

Permalink
Merge pull request #10 from mcanoy/webhooks
Browse files Browse the repository at this point in the history
Webhooks + reload on configmap change
  • Loading branch information
mcanoy authored Aug 25, 2021
2 parents 5767f79 + 0ddabb2 commit 2650757
Show file tree
Hide file tree
Showing 25 changed files with 373 additions and 188 deletions.
20 changes: 16 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,22 @@ http(s)://your-hostname[:port]/q/swagger-ui

The runtime config resource exposes an endpoints that allow clients to retrieve the base runtime configuration or the base configuration merged with a specific engagement type configuration.

`GET /engagements`
`GET /api/v1/configs/runtime`

The following parameters are supported:

Query Params:
* `type` - engagement type value listed in the base configuration file.
* `type` - engagement type value listed in the base configuration file. If not found, it reverts to the base

### Rbac Perimissions

This resource returns a map of engagement types with a list of roles (groups) that have writer permission

`GET /api/v1/configs/runtime/rbac`

### Webhooks Needed by engagements

Provides a list of webhooks that need to be added to each engagement on creation.

----

Expand All @@ -75,9 +85,11 @@ The following environment variables are available:

### Runtime Configuration

| Name | Example Value | Required |
| Name | Default Value | Required |
|------|---------------|----------|
| RUNTIME_BASE_CONFIG_FILE | /runtime/lodestar-runtime-configuration.yaml | False |
| RUNTIME_BASE_CONFIG_FILE | /runtime/base/lodestar-runtime-config-base.yaml | False |
| WEBHOOK_BASE_CONFIG_FILE | /webhooks/webhooks.yaml | False |
| LODESTAR_ENGAGEMENTS_API_URL | http://lodestar-engagements:8080 | False

## Development

Expand Down
18 changes: 11 additions & 7 deletions deployment/templates/deploymentconfig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,26 @@ spec:
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
{{- range $rConfig := .Values.runtimeConfigs }}
- name: {{ $rConfig.name }}-cm-volume
mountPath: {{ $rConfig.path }}/{{ $rConfig.file }}
subPath: {{ $rConfig.file }}
{{- range .Values.runtimeConfigs }}
- name: lodestar-runtime-{{ . | lower }}-cm-volume
mountPath: {{ $.Values.baseConfigMapPath }}/{{ . }}
{{- end }}
- name: hook-cm-volume
mountPath: /webhooks
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
{{- range $rConfig := .Values.runtimeConfigs }}
- name: {{ $rConfig.name }}-cm-volume
{{- range .Values.runtimeConfigs }}
- name: lodestar-runtime-{{ . | lower }}-cm-volume
configMap:
name: {{ $rConfig.name }}-cm
name: lodestar-runtime-{{ . | lower }}-cm
{{- end }}
- name: hook-cm-volume
configMap:
name: hook-cm
test: false
triggers:
- type: ConfigChange
Expand Down
4 changes: 2 additions & 2 deletions deployment/templates/runtime-config-cm.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{{- if .Values.development }}
apiVersion: v1
data:
lodestar-runtime-config.yaml: |
lodestar-runtime-config-base.yaml: |
---
basic_information:
engagement_types:
Expand All @@ -25,5 +25,5 @@ data:
value: optionTwo
kind: ConfigMap
metadata:
name: lodestar-runtime-cm
name: lodestar-runtime-base-cm
{{- end }}
13 changes: 4 additions & 9 deletions deployment/values-dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,8 @@ git:
uri: https://github.com/rht-labs/lodestar-config.git
ref: master

baseConfigMapPath: /runtime
runtimeConfigs:
- name: lodestar-runtime
file: lodestar-runtime-config.yaml
path: /runtime
- name: lodestar-runtime-one
file: lodestar-runtime-config-one.yaml
path: /runtime
- name: lodestar-runtime-two
file: lodestar-runtime-config-two.yaml
path: /runtime
- base
- one
- two
19 changes: 15 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,15 @@
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus-plugin.version>2.0.3.Final</quarkus-plugin.version>
<quarkus.platform.artifact-id>quarkus-universe-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
<quarkus.platform.version>2.0.3.Final</quarkus.platform.version>
<quarkus.platform.version>2.1.3.Final</quarkus.platform.version>
<surefire-plugin.version>3.0.0-M5</surefire-plugin.version>
<lombok.version>1.18.20</lombok.version>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
<sonar.project.key>rht-labs_lodestar-config</sonar.project.key>
<sonar.organization>rht-labs</sonar.organization>
<sonar.jacoco.reportPath>target/jacoco.exec</sonar.jacoco.reportPath>
<sonar.jacoco.reportPath>target/jacoco-quarkus.exec</sonar.jacoco.reportPath>
</properties>
<dependencyManagement>
<dependencies>
Expand Down Expand Up @@ -62,6 +61,18 @@
<artifactId>quarkus-smallrye-metrics</artifactId>
</dependency>
<!-- Other -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-fault-tolerance</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-scheduler</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jacoco</artifactId>
Expand Down Expand Up @@ -92,7 +103,7 @@
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus-plugin.version}</version>
<version>${quarkus.platform.version}</version>
<extensions>true</extensions>
<executions>
<execution>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.redhat.labs.lodestar.config.rest.client;

import com.redhat.labs.lodestar.model.GitlabHook;
import org.apache.http.NoHttpResponseException;
import org.eclipse.microprofile.faulttolerance.Retry;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import java.util.List;

@Retry(maxRetries = 5, delay = 1200, retryOn = NoHttpResponseException.class, abortOn = WebApplicationException.class)
@RegisterRestClient(configKey = "engagements.api")
@Produces("application/json")
public interface EngagementApiRestClient {

@PUT
@Path("/api/v1/engagements/gitlab-webhooks")
Response updateWebhooks(List<GitlabHook> webhooks);

}
58 changes: 23 additions & 35 deletions src/main/java/com/redhat/labs/lodestar/model/ConfigMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileTime;
import java.util.Optional;

import lombok.ToString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -16,6 +16,7 @@
import lombok.experimental.SuperBuilder;

@SuperBuilder
@ToString(callSuper = true)
public class ConfigMap {

private static final Logger LOGGER = LoggerFactory.getLogger(ConfigMap.class);
Expand All @@ -25,57 +26,44 @@ public class ConfigMap {
@Getter
@Builder.Default
private Optional<String> content = Optional.empty();
private long lastModifiedTime;

/**
* Returns true if the content has been loaded from the configured file.
* Otherwise, false.
*
* @return
* The last modified date is flaky in-container. Instead, read file
* each time and update when changed. Limited reads via scheduler
* @return true if the content changed
*/
public boolean readMountedFile() {
public boolean readAndUpdateMountedFile() {
String currentContent = content.orElse("");

if (null == path) {
path = Paths.get(filePath);
if (!checkPath()) {
LOGGER.warn("Unable to read file {}", filePath);
return false;
}

if (Files.isReadable(path) && isModified()) {
try {
String newContent = Files.readString(path, StandardCharsets.UTF_8);
content = Optional.of(newContent);
LOGGER.trace("content match ({}) = {} ", filePath, currentContent.equals(newContent));

try {
content = Optional.of(new String(Files.readAllBytes(path), StandardCharsets.UTF_8));
if(!currentContent.equals(newContent)) {
LOGGER.debug("Content changed for file path {}", filePath);
return true;
} catch (IOException e) {
LOGGER.error("Error updating mounted file %{} {} {} ", lastModifiedTime, path, filePath);
content = Optional.empty();
}

} catch (IOException e) {
LOGGER.error("Error updating mounted file %{} {} ", path, filePath);
content = Optional.empty();
}

return false;

}

/**
* Returns true if the file has been modified since the last load. Otherwise,
* false.
*
* @return
*/
private boolean isModified() {

FileTime fileTime;
try {
fileTime = Files.getLastModifiedTime(path);
if (fileTime.toMillis() > lastModifiedTime) {
lastModifiedTime = fileTime.toMillis();
return true;
}
} catch (IOException e) {
LOGGER.error("Error calculating isModified %{} {}", lastModifiedTime, path);
return false;
public boolean checkPath() {
if (null == path) {
path = Paths.get(filePath);
}

return false;
return Files.isReadable(path);
}

}
23 changes: 23 additions & 0 deletions src/main/java/com/redhat/labs/lodestar/model/GitlabHook.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.redhat.labs.lodestar.model;

import lombok.*;
import lombok.experimental.SuperBuilder;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class GitlabHook {
private String name;
private String baseUrl;
private boolean pushEvent;
private String pushEventsBranchFilter;
private String token;

/**
* Should the webhook be enabled after an engagement is archived
*/
private boolean enabledAfterArchive;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.redhat.labs.lodestar.model;

import com.redhat.labs.lodestar.utils.MarshalUtils;
import lombok.Builder;
import lombok.Getter;
import lombok.experimental.SuperBuilder;

import java.util.ArrayList;
import java.util.List;

@SuperBuilder
@Getter
public class GitlabHookConfiguration extends ConfigMap {

@Builder.Default
private List<GitlabHook> hooks = new ArrayList<>();

public void loadFromConfigMap() {
hooks = MarshalUtils.convertToHookList(getContent());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,23 @@

import com.redhat.labs.lodestar.utils.MarshalUtils;

import lombok.Builder;
import lombok.experimental.SuperBuilder;

@SuperBuilder
public class RuntimeConfiguration extends ConfigMap {

private Map<String, Object> configuration;
@Builder.Default
private Map<String, Object> configuration = new HashMap<>();

public Map<String, Object> getConfiguration() {

if (null != configuration && !configuration.keySet().isEmpty()) {
return configuration;
public void loadFromConfigMapIfChanged() {
if(readAndUpdateMountedFile()) { //changed
configuration = MarshalUtils.convertToMap(getContent().orElse(null)).orElse(new HashMap<>());
}
}

// load content from file
readMountedFile();

// load map from content
configuration = MarshalUtils.convertToMap(getContent().orElse(null)).orElse(new HashMap<>());
public Map<String, Object> getConfiguration() {
return configuration;

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.redhat.labs.lodestar.resource;

import com.redhat.labs.lodestar.model.GitlabHook;
import com.redhat.labs.lodestar.service.GitlabHookService;

import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;

@Path("/api/v1/configs/webhooks")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class GitlabHookConfigResource {

@Inject
GitlabHookService gitlabHookService;

@GET
public Response get() {
List<GitlabHook> webhooks = gitlabHookService.getWebhooks();
return Response.ok(webhooks).header("x-total-webhooks", webhooks.size()).build();
}
}
Loading

0 comments on commit 2650757

Please sign in to comment.