Skip to content

All units receive config-changed when application config changes - #73

Open
github-actions[bot] wants to merge 1 commit into
mainfrom
probe/issue-72
Open

All units receive config-changed when application config changes#73
github-actions[bot] wants to merge 1 commit into
mainfrom
probe/issue-72

Conversation

@github-actions

@github-actions github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

Issue

#72 asks: when a charm has a config option and multiple units, does a config change fire config-changed on every unit, or is it the leader's responsibility to propagate the change to other units?

Claim under test

Claim: When application config changes, Juju fires the config-changed event on every unit of the application — not just the leader. It is not the leader's job to propagate config to peers.

My understanding (independent of the docs)

Juju treats application config as shared state visible to all units. When config is changed via juju config, Juju fires config-changed independently on each unit. This is a fundamental Juju behaviour, not something the charm framework or leader election mediates. I therefore expect that after a config change, every unit's charm code runs its config-changed handler, and any per-unit observable set by that handler (such as the unit workload status message) will be updated on every unit.

What I changed

I modified the kepler charm (the only charm touched, so only kepler's CI runs):

  • src/charm.py: added a config-changed observer and a shared _update_status() helper. Both the pebble-ready and config-changed handlers now set the unit status to ActiveStatus(f"log-level={config}"). This makes "did this unit get config-changed?" observable per-unit via juju status. Both handlers derive the message from the same config value, so neither clobbers the other.
  • tests/unit/test_charm.py: updated the existing test_pebble_layer to expect the new status message, and added two new unit tests:
    • test_config_changed_updates_status — verifies the config-changed handler sets the status.
    • test_config_changed_survives_pebble_ready — sequence test firing config-changed then pebble-ready, asserting the status message survives the full sequence (defends against event-interaction bugs).
  • tests/integration/test_charm.py: test_deploy now deploys with num_units=2. Added test_all_units_get_config_changed, which changes log-level to debug, waits until every unit's workload status message reads log-level=debug, then asserts both units report the new value.

How the test engages the claim

The integration test deploys two units, then changes the log-level config. The charm's config-changed handler sets the unit status message to log-level=<value>. The test uses a custom juju.wait ready condition (_all_units_report) that does not return until every unit's workload status message is log-level=debug — not merely until agents are idle. This eliminates any race where juju.wait returns before config-changed is processed.

  • If all units get config-changed (the claim), both units update their status message, the wait condition is satisfied, and the assertions pass → CI passes, claim validated.
  • If only the leader gets config-changed, the non-leader's status message never changes, the wait condition is never satisfied, juju.wait times out, and the test fails → CI fails, claim refuted.

Test design review

  1. Triggering event: config-changed, fired by juju config.
  2. Observable: unit workload status message (log-level=debug).
  3. Handlers that modify the observable: _on_config_changed and _on_demo_server_pebble_ready — both call _update_status(), which derives the message from the same config value.
  4. Event sequence after the trigger: after juju config, only config-changed fires on each unit; pebble-ready does not re-fire (the container is already running). No later handler clobbers the observable.
  5. Robustness: even if pebble-ready did fire after config-changed, it sets the same message (same config value). The companion unit test test_config_changed_survives_pebble_ready confirms this in run_tox.

run_tox result

tox -e format,lint,unit passes for kepler: 3 unit tests pass, lint and format clean, pyright reports 0 errors. The integration test imports and type-checks cleanly; CI will run it against a real Juju controller.

@github-actions github-actions Bot changed the title All units get config-changed on a config update All units receive config-changed when application config changes Sep 7, 2026
@dwilding

dwilding commented Sep 7, 2026

Copy link
Copy Markdown
Owner

PR validates "Who gets it?" for config-changed.

https://canonical.com/juju/docs/juju-cli/3.6/reference/hook/#config-changed

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