feat(rds): add mock mode to create clusters and instances without Docker - #1655
Conversation
Floci backs RDS clusters and instances with real Docker containers and an auth proxy. In CI or environments without access to the Docker socket, CreateDBCluster/CreateDBInstance fail, so the resources never reach an available state. Add FLOCI_SERVICES_RDS_MOCK (default false), mirroring the existing mock mode of EC2/EKS/ECS/OpenSearch/MSK. When enabled, cluster and instance creation skip the container and proxy and are registered as AVAILABLE immediately with a localhost endpoint; delete and runtime restoration likewise skip all Docker calls. Non-mock behavior is unchanged.
In mock mode, reboot skipped the container restart (guarded by a null containerId) but still started a real TCP auth proxy, breaking the no-container/no-proxy invariant. Gate the container restart and proxy start on !mock so a mock reboot only flips status back to AVAILABLE.
There was a problem hiding this comment.
Pull request overview
Adds an RDS “mock mode” configuration toggle so CreateDBCluster / CreateDBInstance can succeed (and become AVAILABLE) in environments without Docker, aligning RDS with existing “metadata-only, no Docker” patterns used by other Floci services.
Changes:
- Introduces
floci.services.rds.mock(FLOCI_SERVICES_RDS_MOCK) config flag with defaults wired into main + testapplication.yml. - Updates
RdsServiceto bypass container/proxy operations in mock mode and to restore resources asAVAILABLEwithlocalhostendpoints. - Adds unit tests and documentation for the new configuration behavior.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/main/java/io/github/hectorvent/floci/config/EmulatorConfig.java | Adds mock flag to RDS service config with default false. |
| src/main/java/io/github/hectorvent/floci/services/rds/RdsService.java | Skips Docker/proxy work in mock mode; adjusts endpoint/status handling and restore logic. |
| src/main/resources/application.yml | Documents and defaults floci.services.rds.mock to false. |
| src/test/resources/application.yml | Adds floci.services.rds.mock: false to test config. |
| src/test/java/io/github/hectorvent/floci/services/rds/RdsServiceTest.java | Adds unit tests asserting mock mode skips container/proxy operations and marks resources AVAILABLE. |
| docs/configuration/environment-variables.md | Documents FLOCI_SERVICES_RDS_MOCK. |
| docs/configuration/advanced/application-yml.md | Documents floci.services.rds.mock in the YAML example. |
|
| Filename | Overview |
|---|---|
| src/main/java/io/github/hectorvent/floci/services/rds/RdsService.java | Core change: all Docker/proxy call sites guarded by if (!mock); backendHost/backendPort initialization made explicit (null/0); restore paths use reserveOrAllocateProxyPort; log message updated. Logic is consistent across all paths. |
| src/test/java/io/github/hectorvent/floci/services/rds/RdsServiceTest.java | Adds 7 focused unit tests covering all new mock-mode code paths (cluster create, cluster-member instance create, standalone instance create, cluster delete, standalone instance delete, distinct ports, reboot). |
| src/main/java/io/github/hectorvent/floci/config/EmulatorConfig.java | Adds boolean mock() with @WithDefault("false") to RdsServiceConfig, matching the pattern used by other mock-capable services. |
| docs/services/rds.md | Documents the new env var, adds a Mock mode section with a Docker Compose example and a note about mode-switching semantics over persisted state. |
| docs/configuration/environment-variables.md | Adds FLOCI_SERVICES_RDS_MOCK row with correct default and description. |
| docs/configuration/advanced/application-yml.md | Adds mock: false inline comment entry under the rds: block, consistent with the main application.yml. |
| src/main/resources/application.yml | Adds mock: false under rds: with an inline comment, following existing patterns for other services. |
| src/test/resources/application.yml | Adds mock: false under rds: to mirror main config, required for test suite baseline. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[CreateDBCluster / CreateDBInstance] --> B{mock=true?}
B -- No --> C[allocateProxyPort]
B -- Yes --> C
C --> D{mock=true?}
D -- No --> E[Start Docker container\ncontainerManager.start]
D -- Yes --> F[Skip container\ncontainerId = null\nvolumeId = null]
E --> G[proxyManager.startProxy\nendpoint = proxyEndpointHost:port]
F --> H[endpoint = localhost:port]
G --> I[Persist cluster/instance\nstatus = AVAILABLE]
H --> I
I --> J[Delete / Reboot]
J --> K{mock=true?}
K -- No --> L[proxyManager.stopProxy\ncontainerManager.stop\ncontainerManager.removeVolume]
K -- Yes --> M[Skip all Docker/proxy calls]
L --> N[releaseProxyPort\nDelete from storage]
M --> N
I --> O[Restore on startup]
O --> P{mock=true?}
P -- No --> Q[Start container\nStart proxy\nstatus = AVAILABLE]
P -- Yes --> R[reserveOrAllocateProxyPort\nendpoint = localhost:port\nstatus = AVAILABLE]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[CreateDBCluster / CreateDBInstance] --> B{mock=true?}
B -- No --> C[allocateProxyPort]
B -- Yes --> C
C --> D{mock=true?}
D -- No --> E[Start Docker container\ncontainerManager.start]
D -- Yes --> F[Skip container\ncontainerId = null\nvolumeId = null]
E --> G[proxyManager.startProxy\nendpoint = proxyEndpointHost:port]
F --> H[endpoint = localhost:port]
G --> I[Persist cluster/instance\nstatus = AVAILABLE]
H --> I
I --> J[Delete / Reboot]
J --> K{mock=true?}
K -- No --> L[proxyManager.stopProxy\ncontainerManager.stop\ncontainerManager.removeVolume]
K -- Yes --> M[Skip all Docker/proxy calls]
L --> N[releaseProxyPort\nDelete from storage]
M --> N
I --> O[Restore on startup]
O --> P{mock=true?}
P -- No --> Q[Start container\nStart proxy\nstatus = AVAILABLE]
P -- Yes --> R[reserveOrAllocateProxyPort\nendpoint = localhost:port\nstatus = AVAILABLE]
Reviews (4): Last reviewed commit: "fix(rds): skip Docker volume name for mo..." | Re-trigger Greptile
Address PR review: mock mode hardcoded proxyBasePort for every cluster and instance, collapsing all endpoints onto localhost:7001 and leaving usedPorts unreserved. Allocate a unique proxy port even in mock mode (still skipping the container and auth proxy), and preserve/reserve the persisted port on restore instead of resetting it. Also gate proxyManager.stopProxy on !mock in the delete paths, matching the reboot path. Add tests for standalone-instance deletion in mock mode and for distinct mock endpoint ports.
|
Pushed 3faa618 addressing the review feedback:
See the inline reply re: the |
|
I think the failing test is flakiness, since this PR touches totally unrelated code. I could push a dummy commit to rerun the CI. Thoughts? |
|
Thanks @dnlopes, another well motivated one. Reviewed the flag plumbing and every guarded path against the current What checks out:
One small non blocking catch: cluster member instances created in mock persist a bogus instanceDockerVolumeName = cluster.getDockerVolumeName() != null
? cluster.getDockerVolumeName()
: volumeName(cluster.getVolumeId(), cluster.getDbClusterIdentifier()); // null volumeId in mockHarmless while mocked, but if the persisted store is later loaded with Nit only: the mock endpoint hardcodes None of this needs to block the merge. Nice, disciplined change. |
…nt mode switching Review feedback from floci-io#1655: - Cluster member instances created in mock mode no longer persist a volume name fabricated from the cluster's null volume id, which a later non-mock restore could try to reference. - Document RDS mock mode on the service page, including that switching FLOCI_SERVICES_RDS_MOCK over persisted state is best-effort in both directions, matching the other mock-capable services.
|
Thanks @hectorvent. Addressed in dd9d3a5:
|
hectorvent
left a comment
There was a problem hiding this comment.
Thanks @dnlopes,
This is a great addition to floci
Summary
Floci backs RDS clusters and instances with real Docker containers and an auth proxy. In CI or environments without access to the Docker socket,
CreateDBCluster/CreateDBInstancefail, so the resources never reach an available state.This adds
FLOCI_SERVICES_RDS_MOCK(defaultfalse), mirroring the existing mock mode of EC2/EKS/ECS/OpenSearch/MSK. When enabled:AVAILABLEimmediately, with alocalhostendpoint;Describe*responses stay realistic;Non-mock behavior is unchanged.
Type of change
fix:)feat:)feat!:orfix!:)AWS Compatibility
No wire-protocol change — this adds a runtime mode toggle, not a new action, following the established
FLOCI_SERVICES_<svc>_MOCKconvention ("metadata only, no Docker"). Mocked clusters/instances reportavailableso standard clients and IaC tools observe them as ready without a backing container.Verified with the AWS Crossplane / Upbound AWS provider (
aws-sdk-go-v2) provisioning an Aurora PostgreSQL cluster + serverless instance on a Docker-less k3d cluster: the managed resources reachReadyand the connection ConfigMap is populated. Also covered by unit tests.Checklist
./mvnw testpasses locally