Skip to content
Open
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
File renamed without changes.
96 changes: 96 additions & 0 deletions docker/full.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
version: "3.8"

# Full FluxGate Development Environment
# Includes: MongoDB, Redis (standalone), ELK Stack
#
# Usage:
# docker-compose -f docker/full.yml up -d
# docker-compose -f docker/full.yml down
#
# Services:
# - MongoDB: localhost:27017 (user: fluxgate, password: fluxgate123)
# - Redis: localhost:6379
# - Elasticsearch: localhost:9200
# - Kibana: localhost:5601
# - Logstash: localhost:5044 (TCP input), localhost:9600 (monitoring)

services:
# ============================================
# MongoDB - Rule Storage
# ============================================
mongo:
image: mongo:7.0
container_name: fluxgate-mongo
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: fluxgate
MONGO_INITDB_ROOT_PASSWORD: fluxgate123
MONGO_INITDB_DATABASE: fluxgate
volumes:
- mongo-data:/data/db

# ============================================
# Redis Standalone - Rate Limiting
# ============================================
redis:
image: redis:7.2-alpine
container_name: fluxgate-redis
ports:
- "6379:6379"

# ============================================
# ELK Stack - Logging & Monitoring
# ============================================
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.12.2
container_name: elk-elasticsearch
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- ES_JAVA_OPTS=-Xms1g -Xmx1g
ports:
- "9200:9200"
volumes:
- es-data:/usr/share/elasticsearch/data

kibana:
image: docker.elastic.co/kibana/kibana:8.12.2
container_name: elk-kibana
depends_on:
- elasticsearch
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
ports:
- "5601:5601"

logstash:
image: docker.elastic.co/logstash/logstash:8.12.2
container_name: elk-logstash
depends_on:
- elasticsearch
ports:
- "5044:5044" # TCP input
- "9600:9600" # Logstash monitoring API
environment:
- XPACK_MONITORING_ENABLED=false
- PIPELINE_WORKERS=1
command: >
logstash -e '
input {
tcp {
port => 5044
codec => json_lines
}
}
output {
elasticsearch {
hosts => ["http://elasticsearch:9200"]
index => "fluxgate-logs-%{+YYYY.MM.dd}"
}
}
'

volumes:
mongo-data:
es-data:
17 changes: 17 additions & 0 deletions docker/mongo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version: "3.8"

services:
mongo:
image: mongo:7.0
container_name: fluxgate-mongo
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: fluxgate
MONGO_INITDB_ROOT_PASSWORD: fluxgate123
MONGO_INITDB_DATABASE: fluxgate
volumes:
- mongo-data:/data/db

volumes:
mongo-data:
11 changes: 11 additions & 0 deletions docker/redis-cluster.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version: "3.8"

services:
redis-cluster:
image: grokzen/redis-cluster:7.0.10
container_name: redis-cluster-test
environment:
IP: 0.0.0.0
INITIAL_PORT: 7100
ports:
- "7100-7105:7100-7105"
8 changes: 8 additions & 0 deletions docker/redis-standalone.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version: "3.8"

services:
redis:
image: redis:7.2-alpine
container_name: fluxgate-redis
ports:
- "6379:6379"
135 changes: 135 additions & 0 deletions fluxgate-control-support/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>io.github.openfluxgate</groupId>
<artifactId>fluxgate</artifactId>
<version>0.1.4</version>
</parent>

<artifactId>fluxgate-control-support</artifactId>
<packaging>jar</packaging>

<name>FluxGate Control Support</name>
<description>Support library for FluxGate Control Plane (Admin/Studio) - provides rule change notification capabilities</description>

<dependencies>
<!-- Lettuce Redis Client -->
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.3.2.RELEASE</version>
</dependency>

<!-- Jackson for JSON serialization -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.2</version>
</dependency>

<!-- SLF4J Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>

<!-- Spring Boot Auto-Configuration (optional) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>3.3.5</version>
<optional>true</optional>
</dependency>

<!-- Spring Boot Configuration Processor (optional, for IDE hints) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>3.3.5</version>
<optional>true</optional>
</dependency>

<!-- Spring AOP (optional, for @NotifyRuleChange annotation support) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>6.1.14</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.22</version>
<optional>true</optional>
</dependency>

<!-- Test -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.6</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>

<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<configuration>
<excludes>
<!-- Exclude auto-configuration that requires Redis -->
<exclude>**/autoconfigure/**</exclude>
<!-- Exclude Redis notifier that requires actual Redis connection -->
<exclude>**/RedisRuleChangeNotifier.class</exclude>
<!-- Exclude AOP aspect that requires Spring context -->
<exclude>**/aop/RuleChangeAspect.class</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.fluxgate.control.aop;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Annotation to automatically notify FluxGate instances to perform a full rule reload.
*
* <p>When applied to a method, the {@link RuleChangeAspect} will automatically call {@link
* org.fluxgate.control.notify.RuleChangeNotifier#notifyFullReload()} after the method completes
* successfully.
*
* <p>Use this annotation for operations that affect multiple rules or when the specific rule set ID
* is not available.
*
* <p>Example usage:
*
* <pre>{@code
* @Service
* public class RuleManagementService {
*
* @NotifyFullReload
* public void deleteAllRules() {
* mongoRepository.deleteAll();
* // Full reload notification is sent automatically
* }
*
* @NotifyFullReload
* public void importRules(List<RuleDto> rules) {
* mongoRepository.deleteAll();
* mongoRepository.saveAll(rules);
* }
*
* @NotifyFullReload
* public void resetToDefaults() {
* mongoRepository.deleteAll();
* mongoRepository.saveAll(defaultRules);
* }
* }
* }</pre>
*
* @see NotifyRuleChange
* @see RuleChangeAspect
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NotifyFullReload {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package org.fluxgate.control.aop;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Annotation to automatically notify FluxGate instances when a rule is changed.
*
* <p>When applied to a method, the {@link RuleChangeAspect} will automatically call {@link
* org.fluxgate.control.notify.RuleChangeNotifier#notifyChange(String)} after the method completes
* successfully.
*
* <p>The {@code ruleSetId} attribute supports Spring Expression Language (SpEL) to extract the rule
* set ID from method parameters.
*
* <p>Example usage:
*
* <pre>{@code
* @Service
* public class RuleManagementService {
*
* @NotifyRuleChange(ruleSetId = "#ruleSetId")
* public void updateRule(String ruleSetId, RuleDto dto) {
* mongoRepository.save(dto);
* // Notification is sent automatically after this method returns
* }
*
* @NotifyRuleChange(ruleSetId = "#dto.ruleSetId")
* public void saveRule(RuleDto dto) {
* mongoRepository.save(dto);
* }
*
* @NotifyRuleChange(ruleSetId = "#result.id")
* public Rule createRule(RuleDto dto) {
* return mongoRepository.save(dto);
* // Uses the returned object's id
* }
* }
* }</pre>
*
* <p>SpEL expressions can reference:
*
* <ul>
* <li>{@code #paramName} - Method parameter by name
* <li>{@code #result} - The return value of the method
* <li>{@code #root.method} - The method being invoked
* <li>{@code #root.target} - The target object
* </ul>
*
* @see NotifyFullReload
* @see RuleChangeAspect
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NotifyRuleChange {

/**
* SpEL expression to extract the rule set ID.
*
* <p>Examples:
*
* <ul>
* <li>{@code "#ruleSetId"} - Parameter named ruleSetId
* <li>{@code "#dto.ruleSetId"} - Property of a parameter
* <li>{@code "#result.id"} - Property of the return value
* </ul>
*
* @return SpEL expression for rule set ID
*/
String ruleSetId();
}
Loading