Skip to content

Commit

Permalink
Merge pull request #574 from codecentric/add-events-to-track-service-…
Browse files Browse the repository at this point in the history
…using-modulith

Add events to track service using modulith
  • Loading branch information
denniseffing authored Jan 3, 2024
2 parents c4da7bf + ef314d2 commit d1384da
Show file tree
Hide file tree
Showing 35 changed files with 565 additions and 159 deletions.
24 changes: 13 additions & 11 deletions BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,16 @@ The goal is to provide infrastructure configurations which...

Each habitcentric service runs with the same ports across all deployment options.

| Service | Port |
|-------------------|-------|
| gateway | 9000 |
| habit | 9001 |
| habit-postgres | 10001 |
| track | 9002 |
| track-postgres | 10002 |
| report | 9003 |
| ui | 9004 |
| keycloak | 8080 |
| keycloak-postgres | 10003 |
| Service | Port |
|-------------------|---------------|
| gateway | 9000 |
| habit | 9001 |
| habit-postgres | 10001 |
| track | 9002 |
| track-postgres | 10002 |
| report | 9003 |
| ui | 9004 |
| keycloak | 8080 |
| keycloak-postgres | 10003 |
| kafka | 11001 - 11003 |
| kafka-ui | 11001 - 11003 |
32 changes: 32 additions & 0 deletions infrastructure/docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ services:
- track-db
environment:
DB_HOST: track-db
KAFKA_BOOTSTRAP_SERVERS: kafka:11001
networks:
- habitcentric-net
track-db:
Expand All @@ -111,6 +112,37 @@ services:
TRACKING_SERVICE_HOST: http://localhost:9000/
networks:
- habitcentric-net
kafka:
image: 'bitnami/kafka:latest'
ports:
- "11003:11003"
environment:
- KAFKA_CFG_NODE_ID=0
- KAFKA_CFG_PROCESS_ROLES=controller,broker
- KAFKA_CFG_LISTENERS=PLAINTEXT://:11001,CONTROLLER://:11002,EXTERNAL://:11003
- KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:SASL_PLAINTEXT,EXTERNAL:SASL_PLAINTEXT
- KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:11001,EXTERNAL://localhost:11003
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@kafka:11002
- KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
- KAFKA_CLIENT_USERS=track,kafka-ui
- KAFKA_CLIENT_PASSWORDS=track,kafka-ui
networks:
- habitcentric-net
kafka-ui:
container_name: kafka-ui
image: provectuslabs/kafka-ui:latest
ports:
- "11004:11004"
environment:
SERVER_PORT: 11004
DYNAMIC_CONFIG_ENABLED: 'true'
KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:11001
KAFKA_CLUSTERS_0_PROPERTIES_SECURITY_PROTOCOL: SASL_PLAINTEXT
KAFKA_CLUSTERS_0_PROPERTIES_SASL_MECHANISM: PLAIN
KAFKA_CLUSTERS_0_PROPERTIES_SASL_JAAS_CONFIG: 'org.apache.kafka.common.security.plain.PlainLoginModule required username="kafka-ui" password="kafka-ui";'
networks:
- habitcentric-net

volumes:
auth-keycloak-db-data:
networks:
Expand Down
17 changes: 17 additions & 0 deletions infrastructure/istio/config/23-mtls-authz-policies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,23 @@ spec:
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: hc-kafka-authz
namespace: hc-kafka
spec:
action: ALLOW
selector:
matchLabels:
app.kubernetes.io/name: kafka
app.kubernetes.io/instance: hc-kafka
rules:
- from:
- source:
principals:
- cluster.local/ns/hc-track/sa/track
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: keycloak-authz
namespace: hc-keycloak
Expand Down
30 changes: 23 additions & 7 deletions infrastructure/kubernetes/helmfile.d/00-namespaces.yaml
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
bases:
- environments.yaml

repositories:
- name: incubator
url: https://charts.helm.sh/incubator

environments:
default:
istio:
linkerd:
kuma:
traefik-mesh:

releases:
- name: namespaces
chart: incubator/raw
Expand Down Expand Up @@ -94,6 +90,26 @@ releases:
"kuma.io/mesh": "default"
{{- end }}
spec:
- apiVersion: v1
kind: Namespace
metadata:
name: hc-kafka
{{- if eq .Environment.Name "istio" }}
labels:
"istio-injection": "enabled"
{{- end }}
{{- if eq .Environment.Name "linkerd" }}
annotations:
"linkerd.io/inject": "enabled"
"config.linkerd.io/trace-collector": "linkerd-collector.linkerd:55678"
"config.alpha.linkerd.io/trace-collector-service-account": "linkerd-collector"
{{- end }}
{{- if eq .Environment.Name "kuma" }}
annotations:
"kuma.io/sidecar-injection": "enabled"
"kuma.io/mesh": "default"
{{- end }}
spec:
- apiVersion: v1
kind: Namespace
metadata:
Expand Down
10 changes: 3 additions & 7 deletions infrastructure/kubernetes/helmfile.d/10-keycloak.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
bases:
- environments.yaml

repositories:
- name: codecentric
url: https://codecentric.github.io/helm-charts
Expand All @@ -6,13 +9,6 @@ repositories:
- name: bitnami-archive-full-index
url: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami

environments:
default:
istio:
linkerd:
kuma:
traefik-mesh:

releases:
- name: keycloak-postgresql
namespace: hc-keycloak
Expand Down
16 changes: 16 additions & 0 deletions infrastructure/kubernetes/helmfile.d/15-kafka.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
bases:
- environments.yaml

repositories:
- name: bitnami-archive-full-index
url: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami

releases:
- name: kafka
namespace: hc-kafka
labels:
service: kafka
chart: bitnami-archive-full-index/kafka
version: 25.3.1
values:
- ./values/kafka-values.yaml.gotmpl
8 changes: 2 additions & 6 deletions infrastructure/kubernetes/helmfile.d/20-habitcentric.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
environments:
default:
istio:
linkerd:
kuma:
traefik-mesh:
bases:
- environments.yaml

repositories:
- name: bitnami-archive-full-index
Expand Down
6 changes: 6 additions & 0 deletions infrastructure/kubernetes/helmfile.d/environments.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
environments:
default:
istio:
linkerd:
kuma:
traefik-mesh:
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
controller:
replicaCount: 1
kraft:
# generated with: uuidgen | tr -d '-' | base64 | cut -b 1-22
clusterId: "ZDQ2MzI3MWEwNmIwNGMyMT"
sasl:
interbroker:
password: "kafka"
controller:
password: "kafka"
client:
users:
- "track"
passwords:
- "track"

externalAccess:
enabled: true
service:
broker:
type: LoadBalancer
ports:
external: 9094
controller:
type: LoadBalancer
containerPorts:
external: 9094
autoDiscovery:
enabled: true

serviceAccount:
create: true

rbac:
create: true
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ image:
pullPolicy: Always

## habitcentric track service configuration

{{- if (eq .Environment.Name "traefik-mesh") }}
extraEnv:
- name: KAFKA_BOOTSTRAP_SERVERS
value: kafka.hc-kafka.svc.cluster.local:9092
{{- if (eq .Environment.Name "traefik-mesh") }}
- name: MANAGEMENT_ZIPKIN_TRACING_ENDPOINT
value: http://jaeger-collector.traefik-mesh.svc.cluster.local:9411
{{- end }}
Expand Down
16 changes: 16 additions & 0 deletions services/track/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ spotless {

repositories {
mavenCentral()
maven {
url "https://repo.spring.io/milestone"
}
}

test {
Expand Down Expand Up @@ -79,12 +82,25 @@ ext {
ext['junit-jupiter.version'] = versions.junitJupiter
ext['jna.version'] = versions.jna // Required for Docker on ARM

dependencyManagement {
imports {
mavenBom 'org.springframework.modulith:spring-modulith-bom:1.1.0-M1'
}
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.security:spring-security-oauth2-jose'

// Spring Modulith
implementation "org.springframework.modulith:spring-modulith-starter-core"
implementation "org.springframework.modulith:spring-modulith-starter-jpa"
implementation "org.springframework.modulith:spring-modulith-events-kafka"
intTestImplementation "org.springframework.modulith:spring-modulith-starter-test"

implementation 'io.micrometer:micrometer-tracing-bridge-otel'
implementation 'io.opentelemetry:opentelemetry-exporter-zipkin'
runtimeOnly "org.postgresql:postgresql:$versions.postgresql"
Expand Down
30 changes: 29 additions & 1 deletion services/track/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,35 @@ services:
image: bitnami/postgresql:15
restart: always
ports:
- 10002:10002
- "10002:10002"
environment:
POSTGRESQL_PASSWORD: postgres
POSTGRESQL_PORT_NUMBER: 10002

kafka:
image: 'bitnami/kafka:latest'
ports:
- "11003:11003"
environment:
- KAFKA_CFG_NODE_ID=0
- KAFKA_CFG_PROCESS_ROLES=controller,broker
- KAFKA_CFG_LISTENERS=PLAINTEXT://:11001,CONTROLLER://:11002,EXTERNAL://:11003
- KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:SASL_PLAINTEXT,EXTERNAL:SASL_PLAINTEXT
- KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:11001,EXTERNAL://localhost:11003
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@kafka:11002
- KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
- KAFKA_CLIENT_USERS=track,kafka-ui
- KAFKA_CLIENT_PASSWORDS=track,kafka-ui

kafka-ui:
container_name: kafka-ui
image: provectuslabs/kafka-ui:latest
ports:
- "11004:11004"
environment:
SERVER_PORT: 11004
DYNAMIC_CONFIG_ENABLED: 'true'
KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:11001
KAFKA_CLUSTERS_0_PROPERTIES_SECURITY_PROTOCOL: SASL_PLAINTEXT
KAFKA_CLUSTERS_0_PROPERTIES_SASL_MECHANISM: PLAIN
KAFKA_CLUSTERS_0_PROPERTIES_SASL_JAAS_CONFIG: 'org.apache.kafka.common.security.plain.PlainLoginModule required username="kafka-ui" password="kafka-ui";'
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package de.codecentric.habitcentric.track.habit;

import static org.assertj.core.api.Assertions.assertThat;

import de.codecentric.habitcentric.track.auth.UserIdArgumentResolver;
import java.time.LocalDate;
import java.util.Set;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.modulith.test.ApplicationModuleTest;
import org.springframework.modulith.test.Scenario;
import org.springframework.test.context.ActiveProfiles;

@ActiveProfiles("intTest")
@ApplicationModuleTest
@MockBean(UserIdArgumentResolver.class)
public class HabitModuleIntegrationTest {

@Autowired private HabitTrackingController habitTrackingController;
@Autowired private HabitTrackingRepository habitTrackingRepository;

@AfterEach
void tearDown() {
habitTrackingRepository.deleteAll();
}

@Test
void shouldPublishDateTrackedEventWhenHabitTrackingIsSaved(Scenario scenario) {
habitTrackingRepository.save(
HabitTracking.from("userId", 1L, Set.of(LocalDate.parse("2023-09-29"))));

scenario
.stimulate(
() ->
habitTrackingController.putHabitTrackingRecords(
"userId",
1L,
Set.of(LocalDate.parse("2023-09-29"), LocalDate.parse("2023-09-30"))))
.andWaitForEventOfType(HabitTracking.DateTracked.class)
.toArriveAndVerify(
event -> {
assertThat(event.habitId()).isEqualTo(1L);
assertThat(event.userId()).isEqualTo("userId");
assertThat(event.trackDate()).isEqualTo(LocalDate.parse("2023-09-30"));
});
}

@Test
void shouldPublishDateUntrackedEventWhenExistingHabitTrackingIsRemoved(Scenario scenario) {
habitTrackingRepository.save(
HabitTracking.from(
"userId", 1L, Set.of(LocalDate.parse("2023-09-29"), LocalDate.parse("2023-09-30"))));

scenario
.stimulate(
() ->
habitTrackingController.putHabitTrackingRecords(
"userId", 1L, Set.of(LocalDate.parse("2023-09-29"))))
.andWaitForEventOfType(HabitTracking.DateUntracked.class)
.toArriveAndVerify(
event -> {
assertThat(event.habitId()).isEqualTo(1L);
assertThat(event.userId()).isEqualTo("userId");
assertThat(event.trackDate()).isEqualTo(LocalDate.parse("2023-09-30"));
});
}
}
Loading

0 comments on commit d1384da

Please sign in to comment.