Skip to content

feat(rds): add mock mode to create clusters and instances without Docker - #1655

Merged
hectorvent merged 4 commits into
floci-io:mainfrom
dnlopes:feat/rds-mock-mode
Jul 5, 2026
Merged

feat(rds): add mock mode to create clusters and instances without Docker#1655
hectorvent merged 4 commits into
floci-io:mainfrom
dnlopes:feat/rds-mock-mode

Conversation

@dnlopes

@dnlopes dnlopes commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

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/CreateDBInstance fail, so the resources never reach an available state.

This adds 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 auth proxy and are registered as AVAILABLE immediately, with a localhost endpoint;
  • subnet/AZ/VPC placement metadata is still resolved (it needs no Docker), so Describe* responses stay realistic;
  • delete, reboot, and runtime restoration likewise skip all Docker/proxy calls.

Non-mock behavior is unchanged.

Type of change

  • Bug fix (fix:)
  • New feature (feat:)
  • Breaking change (feat!: or fix!:)
  • Docs / chore

AWS Compatibility

No wire-protocol change — this adds a runtime mode toggle, not a new action, following the established FLOCI_SERVICES_<svc>_MOCK convention ("metadata only, no Docker"). Mocked clusters/instances report available so 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 reach Ready and the connection ConfigMap is populated. Also covered by unit tests.

Checklist

  • ./mvnw test passes locally
  • New or updated integration test added
  • Commit messages follow Conventional Commits

dnlopes added 2 commits June 30, 2026 12:49
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.
Copilot AI review requested due to automatic review settings June 30, 2026 13:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 + test application.yml.
  • Updates RdsService to bypass container/proxy operations in mock mode and to restore resources as AVAILABLE with localhost endpoints.
  • 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.

Comment thread src/main/java/io/github/hectorvent/floci/services/rds/RdsService.java Outdated
@greptile-apps

greptile-apps Bot commented Jun 30, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds FLOCI_SERVICES_RDS_MOCK (default false) to RdsService, mirroring the existing mock-mode pattern used by EC2/EKS/ECS/OpenSearch/MSK. When enabled, CreateDBCluster and CreateDBInstance skip container and auth-proxy startup and register resources as AVAILABLE immediately with a localhost endpoint, while subnet/AZ/VPC placement resolution is still performed.

  • RdsService.java: All four affected code paths — create cluster, create instance, delete (cluster + instance), reboot, and restore-on-startup — are guarded with if (!mock) blocks; proxy ports are always allocated (even in mock) to keep usedPorts consistent and endpoints unique.
  • EmulatorConfig.java / application.yml (main + test): New mock field wired with @WithDefault(\"false\") following the established config convention; all required YAML and doc files updated.
  • RdsServiceTest.java: Seven new unit tests cover cluster creation, cluster-member and standalone instance creation, cluster and standalone instance deletion, distinct-port assignment, and reboot in mock mode.

Confidence Score: 5/5

Safe to merge — the change is a purely additive runtime toggle that defaults to false and leaves all existing Docker-backed behaviour untouched.

The mock flag is consistently applied across every affected code path (create, delete, reboot, and restore-on-startup for both clusters and instances). Proxy-port allocation happens unconditionally in both modes so usedPorts stays coherent. Previous review concerns about port handling and stopProxy guards have been addressed. Seven new unit tests cover all new branching paths, and the config changes follow the established FLOCI pattern exactly.

No files require special attention.

Important Files Changed

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]
Loading
%%{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]
Loading

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.
@dnlopes

dnlopes commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

Pushed 3faa618 addressing the review feedback:

  • Unique mock endpoint ports (Copilot ×4, Greptile P1): create paths now always allocateProxyPort() even in mock — only the container and auth proxy are skipped — so each cluster/instance gets a distinct, reserved port instead of all collapsing onto localhost:7001. Restore paths now preserve/reserve the persisted port (reserveOrAllocateProxyPort) rather than resetting to proxyBasePort.
  • stopProxy consistency (Greptile summary note): gated on !mock in both delete paths, matching the reboot path.
  • Test coverage (Greptile P2): added mockModeDeleteStandaloneInstanceSkipsDockerCleanup and mockModeAssignsDistinctEndpointPorts.

See the inline reply re: the getContainerId() guard suggestion — addressed the port concern a different way to keep the no-Docker guarantee intact. All RDS tests pass (./mvnw test -Dtest=RdsServiceTest).

@dnlopes

dnlopes commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

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?

@hectorvent hectorvent added feature rds Amazon Relational Database Service (RDS) labels Jul 1, 2026
@hectorvent

Copy link
Copy Markdown
Collaborator

Thanks @dnlopes, another well motivated one. Reviewed the flag plumbing and every guarded path against the current RdsService internals.

What checks out:

  • No hidden Docker or OS dependency in mock: allocateProxyPort() is a pure in memory counter, so the "always reserve a unique port" comment is accurate and keeps usedPorts consistent across mode switches. The distinct endpoint test pins it.
  • Non mock paths are untouched, every change sits inside an if (!mock) guard or the new restore branches.
  • Config plumbing is complete (EmulatorConfig, main and test application.yml, both docs pages) and follows the established FLOCI_SERVICES_<svc>_MOCK convention.
  • Past 99 mock DBs the port range still throws InsufficientDBInstanceCapacity, a real declared RDS fault.

One small non blocking catch: cluster member instances created in mock persist a bogus dockerVolumeName. The member branch falls through to the volume name fallback when the cluster has no docker volume name, and in mock the volume id is also null:

instanceDockerVolumeName = cluster.getDockerVolumeName() != null
        ? cluster.getDockerVolumeName()
        : volumeName(cluster.getVolumeId(), cluster.getDbClusterIdentifier()); // null volumeId in mock

Harmless while mocked, but if the persisted store is later loaded with mock=false, restore would reference a volume that never existed. A mock ? null : ... guard closes it. Related and fine to just document: switching modes over persisted state is best effort in both directions (real to mock orphans containers on delete, mock to real restores fresh ones), same as the other mock services.

Nit only: the mock endpoint hardcodes localhost where non mock uses the Docker host resolver. Nothing listens either way, so purely cosmetic.

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.
@dnlopes

dnlopes commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @hectorvent.

Addressed in dd9d3a5:

  1. Bogus dockerVolumeName on mock cluster members: the member branch in createDbInstance now skips the volume-name computation entirely in mock mode (an if (!mock) guard, matching the style of the surrounding ones), so mock members persist null instead of a name fabricated from the cluster's null volume id. The existing mock cluster-member test now asserts getDockerVolumeName() is null.
  2. Mode switching over persisted state: documented on docs/services/rds.md in a new "Mock mode (CI / tests)" section (that page didn't mention mock mode yet), including a note that flipping FLOCI_SERVICES_RDS_MOCK between restarts is best-effort in both directions — real→mock leaves containers/volumes behind on delete, mock→real restores fresh empty containers — same as the other mock-capable services.

@hectorvent hectorvent self-assigned this Jul 5, 2026

@hectorvent hectorvent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @dnlopes,
This is a great addition to floci

@hectorvent
hectorvent merged commit f490bbe into floci-io:main Jul 5, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature rds Amazon Relational Database Service (RDS) waiting-contributor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants