Skip to content

Commit 19574bd

Browse files
committed
Merge remote-tracking branch 'canorigin/main' into deployment-zero-units
2 parents a1b24dd + 9614915 commit 19574bd

23 files changed

+2241
-1792
lines changed

.github/workflows/ci.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ on:
2222
jobs:
2323
lint:
2424
name: Lint
25-
uses: canonical/data-platform-workflows/.github/workflows/[email protected].1
25+
uses: canonical/data-platform-workflows/.github/workflows/[email protected].2
2626

2727
unit-test:
2828
name: Unit test charm
@@ -42,7 +42,7 @@ jobs:
4242

4343
build:
4444
name: Build charm
45-
uses: canonical/data-platform-workflows/.github/workflows/[email protected].1
45+
uses: canonical/data-platform-workflows/.github/workflows/[email protected].2
4646
with:
4747
cache: true
4848

@@ -61,7 +61,7 @@ jobs:
6161
- lint
6262
- unit-test
6363
- build
64-
uses: canonical/data-platform-workflows/.github/workflows/[email protected].1
64+
uses: canonical/data-platform-workflows/.github/workflows/[email protected].2
6565
with:
6666
artifact-prefix: ${{ needs.build.outputs.artifact-prefix }}
6767
cloud: lxd

.github/workflows/release.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ jobs:
2424

2525
build:
2626
name: Build charm
27-
uses: canonical/data-platform-workflows/.github/workflows/[email protected].1
27+
uses: canonical/data-platform-workflows/.github/workflows/[email protected].2
2828

2929
release:
3030
name: Release charm
3131
needs:
3232
- ci-tests
3333
- build
34-
uses: canonical/data-platform-workflows/.github/workflows/[email protected].1
34+
uses: canonical/data-platform-workflows/.github/workflows/[email protected].2
3535
with:
3636
channel: 14/edge
3737
artifact-prefix: ${{ needs.build.outputs.artifact-prefix }}

.github/workflows/sync_issue_to_jira.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
jobs:
1010
sync:
1111
name: Sync GitHub issue to Jira
12-
uses: canonical/data-platform-workflows/.github/workflows/[email protected].1
12+
uses: canonical/data-platform-workflows/.github/workflows/[email protected].2
1313
with:
1414
jira-base-url: https://warthogs.atlassian.net
1515
jira-project-key: DPE

CONTRIBUTING.md

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ this operator.
88
- Generally, before developing enhancements to this charm, you should consider [opening an issue
99
](https://github.com/canonical/postgresql-operator/issues) explaining your use case.
1010
- If you would like to chat with us about your use-cases or proposed implementation, you can reach
11-
us at [public Canonical Data Platform channel](https://chat.charmhub.io/charmhub/channels/data-platform)
12-
or [Discourse](https://discourse.charmhub.io/).
11+
us using any channel from our [Contacts](https://charmhub.io/postgresql/docs/r-contacts).
1312
- Familiarising yourself with the [Charmed Operator Framework](https://juju.is/docs/sdk) library
1413
will help you a lot when working on new features or bug fixes.
1514
- All enhancements require review before being merged. Code review typically examines
@@ -40,13 +39,45 @@ tox # runs 'lint' and 'unit' environments
4039

4140
## Build charm
4241

43-
Build the charm in this git repository using:
42+
The build environment assumes that there are preinstalled on the system:
43+
* [tox](https://tox.wiki/) (version 4+ !!!)
44+
* [poetry](https://python-poetry.org/)
45+
* [charmcraft](https://snapcraft.io/charmcraft)
46+
* [charmcraftcache](https://github.com/canonical/charmcraftcache)
47+
* [pipx](https://pipx.pypa.io/stable/installation/)
48+
* [libpq-dev](https://www.postgresql.org/docs/current/libpq.html)
49+
50+
To build the charm it is also necessary at least 5GB of free disk space and
51+
it is recommended to provide 4+ CPU cores and 8GB+ RAM for a decent build speed.
52+
53+
To install all above build dependencies (assuming you are on Ubuntu 22.04 LTS):
4454

4555
```shell
46-
tox run -e build-dev
56+
sudo snap install charmcraft --classic
57+
58+
sudo snap install lxd # should be pre-installed on 22.04
59+
lxd init --auto # init LXD (if never used earlier)
60+
61+
sudo apt update && sudo apt install --yes libpq-dev pipx
62+
63+
sudo apt purge tox # if old tox version is installed from apt
64+
65+
pipx ensurepath
66+
pipx install tox
67+
pipx install poetry
68+
pipx install charmcraftcache
4769
```
4870

49-
The tox build environment assumes that there is a preinstalled [poetry](https://python-poetry.org/) on the system.
71+
Ensure local pip binaries are in your $PATH (otherwise re-login to your shell):
72+
```shell
73+
charmcraftcache --help
74+
```
75+
76+
Build the charm (inside this Git repository):
77+
78+
```shell
79+
tox run -e build-dev
80+
```
5081

5182
### Deploy
5283

poetry.lock

Lines changed: 14 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ repository = "https://github.com/canonical/postgresql-operator"
1515
python = "^3.10"
1616
ops = "^2.12.0"
1717
cryptography = "^42.0.5"
18-
boto3 = "^1.34.85"
18+
boto3 = "^1.34.86"
1919
pgconnstr = "^1.0.1"
2020
requests = "^2.31.0"
2121
tenacity = "^8.2.3"
@@ -66,10 +66,10 @@ optional = true
6666

6767
[tool.poetry.group.integration.dependencies]
6868
pytest = "^8.1.1"
69-
pytest-github-secrets = {git = "https://github.com/canonical/data-platform-workflows", tag = "v13.1.1", subdirectory = "python/pytest_plugins/github_secrets"}
69+
pytest-github-secrets = {git = "https://github.com/canonical/data-platform-workflows", tag = "v13.1.2", subdirectory = "python/pytest_plugins/github_secrets"}
7070
pytest-operator = "^0.34.0"
71-
pytest-operator-cache = {git = "https://github.com/canonical/data-platform-workflows", tag = "v13.1.1", subdirectory = "python/pytest_plugins/pytest_operator_cache"}
72-
pytest-operator-groups = {git = "https://github.com/canonical/data-platform-workflows", tag = "v13.1.1", subdirectory = "python/pytest_plugins/pytest_operator_groups"}
71+
pytest-operator-cache = {git = "https://github.com/canonical/data-platform-workflows", tag = "v13.1.2", subdirectory = "python/pytest_plugins/pytest_operator_cache"}
72+
pytest-operator-groups = {git = "https://github.com/canonical/data-platform-workflows", tag = "v13.1.2", subdirectory = "python/pytest_plugins/pytest_operator_groups"}
7373
# renovate caret doesn't work: https://github.com/renovatebot/renovate/issues/26940
7474
juju = "<=3.4.0.0"
7575
boto3 = "*"

src/charm.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,6 +1451,14 @@ def _restart(self, event: RunWithLock) -> None:
14511451
self.unit.status = BlockedStatus(error_message)
14521452
return
14531453

1454+
try:
1455+
for attempt in Retrying(wait=wait_fixed(3), stop_after_delay=stop_after_delay(300)):
1456+
with attempt:
1457+
if not self._can_connect_to_postgresql:
1458+
assert False
1459+
except Exception:
1460+
logger.exception("Unable to reconnect to postgresql")
1461+
14541462
# Start or stop the pgBackRest TLS server service when TLS certificate change.
14551463
self.backup.start_stop_pgbackrest_service()
14561464

src/constants.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
PEER = "database-peers"
1313
UPGRADE_RELATION = "upgrade"
1414
ALL_CLIENT_RELATIONS = [DATABASE, LEGACY_DB, LEGACY_DB_ADMIN]
15+
ALL_LEGACY_RELATIONS = [LEGACY_DB, LEGACY_DB_ADMIN]
1516
API_REQUEST_TIMEOUT = 5
1617
PATRONI_CLUSTER_STATUS_ENDPOINT = "cluster"
1718
BACKUP_USER = "backup"
@@ -36,7 +37,7 @@
3637
SNAP_PACKAGES = [
3738
(
3839
POSTGRESQL_SNAP_NAME,
39-
{"revision": {"aarch64": "110", "x86_64": "111"}, "channel": "14/stable"},
40+
{"revision": {"aarch64": "112", "x86_64": "113"}, "channel": "14/stable"},
4041
)
4142
]
4243

@@ -68,3 +69,7 @@
6869
UNIT_SCOPE = "unit"
6970

7071
SECRET_KEY_OVERRIDES = {"ca": "cauth"}
72+
73+
ENDPOINT_SIMULTANEOUSLY_BLOCKING_MESSAGE = (
74+
"Please choose one endpoint to use. No need to relate all of them simultaneously!"
75+
)

src/relations/db.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,12 @@
2121
from ops.model import ActiveStatus, BlockedStatus, Relation, Unit
2222
from pgconnstr import ConnectionString
2323

24-
from constants import APP_SCOPE, DATABASE_PORT
24+
from constants import (
25+
ALL_LEGACY_RELATIONS,
26+
APP_SCOPE,
27+
DATABASE_PORT,
28+
ENDPOINT_SIMULTANEOUSLY_BLOCKING_MESSAGE,
29+
)
2530
from utils import new_password
2631

2732
logger = logging.getLogger(__name__)
@@ -87,6 +92,20 @@ def _check_for_blocking_relations(self, relation_id: int) -> bool:
8792
return True
8893
return False
8994

95+
def _check_exist_current_relation(self) -> bool:
96+
for r in self.charm.client_relations:
97+
if r in ALL_LEGACY_RELATIONS:
98+
return True
99+
return False
100+
101+
def _check_multiple_endpoints(self) -> bool:
102+
"""Checks if there are relations with other endpoints."""
103+
is_exist = self._check_exist_current_relation()
104+
for relation in self.charm.client_relations:
105+
if relation.name not in ALL_LEGACY_RELATIONS and is_exist:
106+
return True
107+
return False
108+
90109
def _on_relation_changed(self, event: RelationChangedEvent) -> None:
91110
"""Handle the legacy db/db-admin relation changed event.
92111
@@ -96,6 +115,10 @@ def _on_relation_changed(self, event: RelationChangedEvent) -> None:
96115
if not self.charm.unit.is_leader():
97116
return
98117

118+
if self._check_multiple_endpoints():
119+
self.charm.unit.status = BlockedStatus(ENDPOINT_SIMULTANEOUSLY_BLOCKING_MESSAGE)
120+
return
121+
99122
if (
100123
"cluster_initialised" not in self.charm._peers.data[self.charm.app]
101124
or not self.charm._patroni.member_started
@@ -277,6 +300,16 @@ def _update_unit_status(self, relation: Relation) -> None:
277300
]:
278301
if not self._check_for_blocking_relations(relation.id):
279302
self.charm.unit.status = ActiveStatus()
303+
self._update_unit_status_on_blocking_endpoint_simultaneously()
304+
305+
def _update_unit_status_on_blocking_endpoint_simultaneously(self):
306+
"""Clean up Blocked status if this is due related of multiple endpoints."""
307+
if (
308+
self.charm.is_blocked
309+
and self.charm.unit.status.message == ENDPOINT_SIMULTANEOUSLY_BLOCKING_MESSAGE
310+
):
311+
if not self._check_multiple_endpoints():
312+
self.charm.unit.status = ActiveStatus()
280313

281314
def update_endpoints(self, relation: Relation = None) -> None:
282315
"""Set the read/write and read-only endpoints."""

src/relations/postgresql_provider.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,16 @@
1717
PostgreSQLGetPostgreSQLVersionError,
1818
PostgreSQLListUsersError,
1919
)
20-
from ops.charm import CharmBase, RelationBrokenEvent
20+
from ops.charm import CharmBase, RelationBrokenEvent, RelationChangedEvent
2121
from ops.framework import Object
2222
from ops.model import ActiveStatus, BlockedStatus, Relation
2323

24-
from constants import ALL_CLIENT_RELATIONS, APP_SCOPE, DATABASE_PORT
24+
from constants import (
25+
ALL_CLIENT_RELATIONS,
26+
APP_SCOPE,
27+
DATABASE_PORT,
28+
ENDPOINT_SIMULTANEOUSLY_BLOCKING_MESSAGE,
29+
)
2530
from utils import new_password
2631

2732
logger = logging.getLogger(__name__)
@@ -48,7 +53,10 @@ def __init__(self, charm: CharmBase, relation_name: str = "database") -> None:
4853
self.framework.observe(
4954
charm.on[self.relation_name].relation_broken, self._on_relation_broken
5055
)
51-
56+
self.framework.observe(
57+
charm.on[self.relation_name].relation_changed,
58+
self._on_relation_changed_event,
59+
)
5260
self.charm = charm
5361

5462
# Charm events defined in the database provides charm library.
@@ -190,6 +198,13 @@ def update_endpoints(self, event: DatabaseRequestedEvent = None) -> None:
190198
read_only_endpoints,
191199
)
192200

201+
def _check_multiple_endpoints(self) -> bool:
202+
"""Checks if there are relations with other endpoints."""
203+
relation_names = {relation.name for relation in self.charm.client_relations}
204+
if "database" in relation_names and len(relation_names) > 1:
205+
return True
206+
return False
207+
193208
def _update_unit_status(self, relation: Relation) -> None:
194209
"""# Clean up Blocked status if it's due to extensions request."""
195210
if (
@@ -199,6 +214,27 @@ def _update_unit_status(self, relation: Relation) -> None:
199214
if not self.check_for_invalid_extra_user_roles(relation.id):
200215
self.charm.unit.status = ActiveStatus()
201216

217+
self._update_unit_status_on_blocking_endpoint_simultaneously()
218+
219+
def _on_relation_changed_event(self, event: RelationChangedEvent) -> None:
220+
"""Event emitted when the relation has changed."""
221+
# Leader only
222+
if not self.charm.unit.is_leader():
223+
return
224+
225+
if self._check_multiple_endpoints():
226+
self.charm.unit.status = BlockedStatus(ENDPOINT_SIMULTANEOUSLY_BLOCKING_MESSAGE)
227+
return
228+
229+
def _update_unit_status_on_blocking_endpoint_simultaneously(self):
230+
"""Clean up Blocked status if this is due related of multiple endpoints."""
231+
if (
232+
self.charm.is_blocked
233+
and self.charm.unit.status.message == ENDPOINT_SIMULTANEOUSLY_BLOCKING_MESSAGE
234+
):
235+
if not self._check_multiple_endpoints():
236+
self.charm.unit.status = ActiveStatus()
237+
202238
def check_for_invalid_extra_user_roles(self, relation_id: int) -> bool:
203239
"""Checks if there are relations with invalid extra user roles.
204240

0 commit comments

Comments
 (0)