https://github.com/canonical/ops-lib-pgsql
PostgreSQL database relation interface for Juju Operator Framework charms.
https://github.com/canonical/ops-lib-pgsql
hacktoberfest juju juju-interface operator
Last synced: 3 months ago
JSON representation
PostgreSQL database relation interface for Juju Operator Framework charms.
- Host: GitHub
- URL: https://github.com/canonical/ops-lib-pgsql
- Owner: canonical
- License: lgpl-3.0
- Created: 2020-08-18T05:27:16.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2022-10-04T04:54:52.000Z (over 3 years ago)
- Last Synced: 2024-10-30T07:06:59.658Z (about 1 year ago)
- Topics: hacktoberfest, juju, juju-interface, operator
- Language: Python
- Homepage:
- Size: 136 KB
- Stars: 4
- Watchers: 4
- Forks: 4
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Juju Operator Framework Charm Interface for PostgreSQL Relations
================================================================
[](https://badge.fury.io/py/ops-lib-pgsql)
[](https://pypi.python.org/pypi/ops-lib-pgsql/)
[](https://github.com/canonical/ops-lib-pgsql/blob/master/LICENSE)
[](https://github.com/canonical/ops-lib-pgsql/actions?query=workflow%3ATests)
To use this interface in your
[Juju Operator Framework](https://github.com/canonical/operator) charm,
instruct [charmcraft](https://github.com/canonical/charmcraft) to embed
it into your built Operator Framework charm by adding ops-lib-pgsql to
your `requirements.txt` file::
```
ops
ops-lib-pgsql
```
Your charm needs to declare its use of the interface in its `metadata.yaml` file:
```yaml
requires:
db:
interface: pgsql
limit: 1 # Most charms only handle a single PostgreSQL Application.
```
Your charm needs to bootstrap it and handle events:
```python
import ops.lib
pgsql = ops.lib.use("pgsql", 1, "postgresql-charmers@lists.launchpad.net")
class MyCharm(ops.charm.CharmBase):
_state = ops.framework.StoredState()
def __init__(self, *args):
super().__init__(*args)
self._state.set_default(db_conn_str=None, db_uri=None, db_ro_uris=[])
self.db = pgsql.PostgreSQLClient(self, 'db') # 'db' relation in metadata.yaml
self.framework.observe(self.db.on.database_relation_joined, self._on_database_relation_joined)
self.framework.observe(self.db.on.master_changed, self._on_master_changed)
self.framework.observe(self.db.on.standby_changed, self._on_standby_changed)
def _on_database_relation_joined(self, event: pgsql.DatabaseRelationJoinedEvent):
if self.model.unit.is_leader():
# Provide requirements to the PostgreSQL server.
event.database = 'mydbname' # Request database named mydbname
event.extensions = ['citext'] # Request the citext extension installed
elif event.database != 'mydbname':
# Leader has not yet set requirements. Defer, incase this unit
# becomes leader and needs to perform that operation.
event.defer()
return
def _on_master_changed(self, event: pgsql.MasterChangedEvent):
if event.database != 'mydbname':
# Leader has not yet set requirements. Wait until next event,
# or risk connecting to an incorrect database.
return
# The connection to the primary database has been created,
# changed or removed. More specific events are available, but
# most charms will find it easier to just handle the Changed
# events. event.master is None if the master database is not
# available, or a pgsql.ConnectionString instance.
self._state.db_conn_str = None if event.master is None else event.master.conn_str
self._state.db_uri = None if event.master is None else event.master.uri
# You probably want to emit an event here or call a setup routine to
# do something useful with the libpq connection string or URI now they
# are available.
def _on_standby_changed(self, event: pgsql.StandbyChangedEvent):
if event.database != 'mydbname':
# Leader has not yet set requirements. Wait until next event,
# or risk connecting to an incorrect database.
return
# Charms needing access to the hot standby databases can get
# their connection details here. Applications can scale out
# horizontally if they can make use of the read only hot
# standby replica databases, rather than only use the single
# master. event.stanbys will be an empty list if no hot standby
# databases are available.
self._state.db_ro_uris = [c.uri for c in event.standbys]
```