Commit Graph
10 Commits
Author SHA1 Message Date
Andrei Kvapil 90b3719f6a fix(mongodb): expose replica-set members per pod for external access (#2514) (#2522)
## What this PR does

Fixes #2514.

When `external: true` is set on a non-sharded `MongoDB`, Cozystack
rendered a single
`LoadBalancer` Service whose selector matched **all** replica-set
members
(`app.kubernetes.io/replset: rs0`). Round-robin balancing sent ~⅔ of
writes to
secondaries and they were rejected with `MongoServerError: not primary`.

Drivers couldn't recover on their own either: connecting through the LB
returned
the in-cluster DNS names of all members from `isMaster`, none of which
resolve
from outside the cluster, so automatic primary discovery failed.

This PR replaces the manual `external-svc.yaml` (for replica-set mode)
with the
Percona MongoDB operator's native `replsets[].expose` feature:

```yaml
replsets:
  - name: rs0
    expose:
      enabled: true
      type: LoadBalancer
      externalTrafficPolicy: Local
```

The operator then:
- creates one `LoadBalancer` Service **per pod** (`<release>-rs0-0`,
`-1`, `-2`)
  with `statefulset.kubernetes.io/pod-name` selectors,
- watches `Service.status.loadBalancer.ingress` for each pod and
rewrites the
  member `host` in `rs.conf` to the external IPs.

External clients use a standard replica-set URI
(`mongodb://...:27017,...:27017,...:27017/?replicaSet=rs0`) and the
driver
discovers the primary correctly from outside the cluster.

For **sharded** mode the existing single `LoadBalancer` is preserved —
it
front-ends stateless `mongos`, which can route writes to the right shard
primary itself. `external-svc.yaml` is now scoped to that case only.

### Tested

- `helm unittest .` in `packages/apps/mongodb/`: 91/91 pass.
- Applied on a dev stand:
  - `replsets[0].expose` is set as expected in the rendered PSMDB CR.
- The Percona operator (`v1.21.1`) accepts the spec and creates 3
per-pod
    `LoadBalancer` Services with `statefulset.kubernetes.io/pod-name`
selectors. The previous single round-robin Service is no longer
rendered.
- With an LB IP pool present, the operator promotes the allocated LB IPs
into
    the PSMDB `status.host` field and into `rs.conf`.

End-to-end mongosh write loop wasn't run on the dev stand because the
underlying network does not advertise/route allocated LoadBalancer IPs
(no
working L2/BGP path), so the rewritten `rs.conf` members are unreachable
in
that environment. The structural change is otherwise fully verified and
the
issue's reproduction scenario expects a real LB-capable network.

### Release note

```release-note
fix(mongodb): expose each replica-set member through its own LoadBalancer when `external: true`, so external clients can discover the primary via the standard replica-set connection string and writes no longer fail with "not primary" errors.
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* External LoadBalancer services now only render when both external and
sharding are enabled.
* Replica set external exposure is now conditional based on the external
setting.
* Service configuration now uses LoadBalancer type with Local traffic
policy for external access.
* Service selectors refined for proper mongos targeting in sharded
deployments.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-04 20:40:58 +02:00
Arsolitt ff69555dbb test(mongodb): rename finalizer assertions to reflect both finalizers
Test descriptions said 'percona.com/delete-psmdb-pvc finalizer'
while the assertions verified both delete-psmdb-pvc and
delete-psmdb-pods-in-order. Use 'Percona finalizers' to match
what the tests actually check.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-28 19:02:40 +03:00
Arsolitt 8e777da24c fix(mongodb): scope users secret to release name
The operator deletes spec.secrets.users (defaulted to the global
percona-server-mongodb-users) as part of the delete-psmdb-pvc
finalizer flow. With the default value, deleting one MongoDB
release in a namespace would remove the secret shared with any
other MongoDB release there.

Override spec.secrets.users with a release-scoped name so each
release owns its own secret and uninstalls do not collide.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-28 19:01:25 +03:00
Arsolitt 1a2cb25376 test(mongodb): assert delete-psmdb-pods-in-order finalizer
Upstream Percona Operator v1.21.1 ships both delete-psmdb-pvc and
delete-psmdb-pods-in-order in deploy/cr.yaml by default. The
pods-in-order finalizer ensures primary-last graceful shutdown,
preventing data loss on cluster deletion under load.

Currently fails — establishes red phase before adding the finalizer.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-28 17:01:21 +03:00
Arsolitt 733226ded0 test(mongodb): cover sharded mode and drop strict equal
Replace the equal assertion (which would block adding more finalizers)
with a sharded-mode test case ensuring the finalizer is rendered
regardless of replicaset/sharded configuration.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-28 17:01:21 +03:00
Arsolitt 8eb764dd40 test(mongodb): tighten finalizer assertion
Rename test description to accurately reflect what's verified
(template renders the finalizer, not runtime cleanup behavior).
Add equal assertion locking the exact finalizer list to catch
regressions where a stray finalizer is appended.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-28 17:01:20 +03:00
Arsolitt 5a9c1a4416 test(mongodb): assert PSMDB CR has delete-psmdb-pvc finalizer
Add helm-unittest assertion verifying that the rendered
PerconaServerMongoDB CR carries percona.com/delete-psmdb-pvc finalizer.
Currently fails — establishes red phase before adding the fix.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-28 16:34:17 +03:00
Myasnikov Daniil 8358c04ce9 fix(mongodb): expose replica-set members per pod for external access (#2514)
A single LoadBalancer selecting all replset members round-robined writes
across primary and secondaries, so ~⅔ of writes failed with "not primary".
Drivers couldn't auto-recover either: `isMaster` returned in-cluster DNS
names that don't resolve from outside.

Switch to the Percona operator's native `replsets[].expose` so it creates
one LoadBalancer per pod and rewrites `rs.conf` with the external IPs;
the driver then discovers the primary correctly via the standard replica
set connection string. The manual `external-svc.yaml` is now scoped to
sharded mode (mongos front-end) only.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-04-28 17:06:07 +05:00
Andrei KvapilandClaude b0fa330d88 refactor(mongodb): unify users and databases configuration
Align MongoDB configuration with postgres and mysql patterns:
- Add separate `databases` section with `roles.admin` and `roles.readonly`
- Simplify `users` to only contain optional password field
- All users now authenticate via `admin` database (MongoDB best practice)
- Admin role maps to readWrite + dbAdmin permissions
- Readonly role maps to read permission

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2026-01-27 23:24:42 +01:00
Aleksei SviridkinandClaude 271a52c892 feat(apps): add MongoDB managed application
Add MongoDB managed service based on Percona Operator for MongoDB with:

- Replica set mode (default) and sharded cluster mode
- Configurable replicas, storage, and resource presets
- Custom users with role-based access control
- S3-compatible backup with PITR support
- Bootstrap/restore from backup
- External access support
- WorkloadMonitor integration for dashboard
- Comprehensive helm-unittest test coverage (91 tests)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
2026-01-19 13:39:57 +01:00