Skip to content

fix(database): skip database request without a database name - #233

Draft
marceloneppel wants to merge 6 commits into
16/edgefrom
fix/database-request-missing-name
Draft

fix(database): skip database request without a database name#233
marceloneppel wants to merge 6 commits into
16/edgefrom
fix/database-request-missing-name

Conversation

@marceloneppel

@marceloneppel marceloneppel commented Aug 28, 2026

Copy link
Copy Markdown
Member

Issue

A database_requested event that was deferred while the cluster was not ready gets replayed by ops on every subsequent dispatch. If the relation has gone away in the meantime — e.g. a cross-model consumer removed during a Patroni outage — ops supplies the dead relation, the remote databag reads back without a database key, and collect_databases coerced the missing value to an empty string. The handler then indexed it in create_relation_user_and_database, raising an uncaught IndexError: string index out of range.

ops only drops a deferred notice once its handler returns, so the exception aborted every later hook on the unit — actions included — wedging the leader until the failed hook is resolved.

Solution

Return early from collect_databases when the request carries no database name, logging a warning instead of coercing the missing value to an empty string. The handler already treats a None return as "nothing to do", so the stale notice drains on its next replay without deferring.

A live requirer can never request an empty name: Juju drops a databag key whose value is an empty string, and the provider library only emits database_requested when that key is added — the guard therefore only affects the replayed-stale-notice path.

Checklist

  • I have added or updated any relevant documentation.
  • I have cleaned any remaining cloud resources from my accounts.

…up scans

check_for_invalid_extra_user_roles() and check_for_invalid_database_name()
scanned every relation's data bucket including this charm's own application
databag. ops forbids a non-leader unit to read its own application databag,
so a follower that carries one of the qualifying Blocked statuses (set while
it still held leadership) crashes with RelationDataAccessError when a client
relation breaks and at least one other client relation remains live - and
keeps crashing on every hook retry.

Requested fields only ever live in remote databags, so the scans now skip
the own app/unit buckets. A regression test emits relation-broken through
the framework on a blocked follower so the strict access rules apply.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
Carries the database status-cleanup fix for the non-leader own-app
databag read.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
…anup paths

Parametrize the blocked-follower regression so both cleanup paths are
exercised under ops' strict relation data access rules: the direct scan
(invalid extra user roles, invalid database name) and
unblock_custom_user_errors (forbidden username, missing secret grant).

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
The invalid database name message enters the same cleanup path as the
other three qualifying Blocked statuses; assert it explicitly so a
future reordering of the cleanup branches cannot drop its coverage.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
A request deferred while the cluster was not ready can replay after its
relation has gone away, e.g. a cross-model consumer removed during a
Patroni outage. ops re-emits the deferred notice with the dead relation,
the request name reads back as absent, and the empty string made it
through to create_relation_user_and_database, whose database[-1] raised
IndexError. The exception aborts every later hook on the unit, actions
included, wedging the leader until the failed hook is resolved.

Return early instead: the handler treats a missing result as nothing to
do, so the stale notice drains on its next replay. A live requirer can
never request an empty name (Juju drops empty databag values), so the
guard only affects the replayed-stale-notice path.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
Keeps the release line moving for the database-request guard, stacked on
the 16.3.7 bump from the status-cleanup scan fix.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
Base automatically changed from fix/database-manager-own-app-databag-read to 16/edge August 31, 2026 11:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant