Skip to content

charm.py

Andreia Velasco edited this page Sep 27, 2024 · 1 revision

The charm.py file is the entry point for the charm. It contains functions for its basic operation, including its major hooks and file management.

Event Flow

The following charts detail the expected flow of events for the pgbouncer-k8s charm. For more information on charm lifecycles, see A Charm's Life.

Charm startup

Relation events can be fired at any time during startup, but they're generally expected by the charm to run after start and pebble_ready hooks. The "golden path" in the flowchart below is shown by the bold lines.

flowchart TD
  start([Start Charm]) ==> start_hook
  start --> peer_relation_created
  start_hook[Run start hook. Defers until the workload container is available, and the leader unit  has generated config, which is then written to the container filesystem and shared to other units via peer databag.]
  start_hook ==> pebble_ready[Run pgbouncer-pebble-ready hook. Defers until config has been written to container filesystem.  Writes pebble config and TLS certs to pgbouncer container, which in turn starts pgbouncer services.]
  pebble_ready -. deferral .-> start_hook
  pebble_ready ==> begin([Begin charm operation])
  pebble_ready --> backend_database_relation_created
  pebble_ready --> client_relation_created
  backend_database_relation_created[Backend relation can be created, but won't be initialised unil pgbouncer services are running]
  backend_database_relation_created -. deferral .-> pebble_ready
    peer_relation_created[Peer relation created by default on startup. Defers config upload until config exists, and defers auth file upload until backend relation exists]
  peer_relation_created -. deferral .-> start_hook
  peer_relation_created -. deferral .-> backend_database_relation_created
  client_relation_created[Client relations can be created, but won't be initialised until pgbouncer services are running and backend database is initialised]
  client_relation_created -. deferral .-> backend_database_relation_created
  client_relation_created -. deferral .-> pebble_ready
Loading

Config updates

flowchart TD
  exists([Charm is running]) --> config_changed[Charm config is changed, firing Config-changed hook]
  exists --> relation_changed[Backend or client relation updates, triggering changes in pgbouncer config] --> update_cfg
  config_changed --> update_cfg[Leader updates config locally and in peer databag, causing a   peer-relation-changed event]
  update_cfg --> peer_changed[Follower units update config from peer databag]
  update_cfg --> reload_pgb[Reload pgbouncer]
  peer_changed --> reload_pgb
  reload_pgb --> continue([Charm continues running])
Loading

Leader Updates

flowchart TD
  exists([Charm is running])--> leader_deleted[Leader unit is deleted]
  leader_deleted --> relation_remove_leader[All relations add unit-departing  flag to unit databag, and   update connection information]
  relation_remove_leader -.-> leader_elected[leader_elected hook fires after an indeterminate amount of time]
  leader_elected --> update_leader[Update leader address in peer databag, and  update connection information in relation databags]
  update_leader --> continue([Continue normal   charm operation])
Loading

Hook Handler Flowcharts

These flowcharts detail the control flow of individual hook handlers in this program. Unless otherwise stated, a hook deferral is always followed by a return.

Start Hook

flowchart TD
  hook_fired([start Hook]) --> is_container{ Is container available? }
  is_container -- no --> defer> defer ]
  is_container -- yes --> is_cfg{ Is pgbouncer config available in container or peer databag? }
  is_cfg -- no --> is_leader{ Is the current unit Leader? }
  is_cfg -- yes --> make_dirs[Create directory structure for charm]
  is_leader -- no --> defer_wait> defer: wait for leader unit to generate config and upload to peer databag ]
  is_leader -- yes --> gen_cfg[ generate new config ]
  gen_cfg --> make_dirs
  make_dirs --> render_cfg[ render config, update relations if available ]
  render_cfg --> rtn(( return ))
Loading

PgBouncer Pebble Ready Hook

flowchart TD
  hook_fired([pgbouncer-pebble-ready Hook]) --> is_cfg{Is pgbouncer config available?}
  is_cfg -- no --> defer>defer]
  is_cfg -- yes --> gen_cfg[Generate pebble config and start pgbouncer services]
  gen_cfg --> verify[Verify pgbouncer services are running, and set charm status accordingly]
  verify --> rtn([return])
Loading

Config Changed Hook

flowchart TD
  hook_fired([config-changed Hook]) --> is_leader{Is current unit leader?}
  is_leader -- no --> rtn([return])
  is_leader -- yes --> is_cfg{Is pgbouncer  config available?}
  is_cfg -- no --> defer>defer]
  is_cfg -- yes --> match_cfg[Modify pgbouncer  config to match charm config]
  match_cfg --> render_cfg[Render config &  reload pgbouncer]
  render_cfg --> rtn2([return])
Loading

Update Status Hook

flowchart TD
  hook_fired([update-status Hook]) --> is_backend_ready{Is backend  database ready?}
  is_backend_ready -- no --> set_blocked[Set Blocked  status]
  is_backend_ready -- yes --> is_running{Is pgbouncer  running?}
  is_running -- yes --> set_active[Set Active  Status]
  is_running -- no --> set_waiting[Set Waiting  Status]
  set_blocked --> update_leader[Update leader in  Peer Relation  Databag.]
Loading