Skip to content

Commit d64a0d2

Browse files
Port over changes from VM operator related to external connectivity (#225)
## Issue 1. We published a newer version of the rock on 8.0/edge. We should use this rock, as it contains and upgraded version of mysql-router-exporter 2. There were changes in shared files made in the vm charm when working on external connectivity ## Solution 1. Update the rock image 2. Port over changes
1 parent c33b7ed commit d64a0d2

15 files changed

+528
-154
lines changed

metadata.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@ resources:
5353
mysql-router-image:
5454
type: oci-image
5555
description: OCI image for mysql-router
56-
upstream-source: ghcr.io/canonical/charmed-mysql@sha256:5082c99baa7a77c82d73247674e270838dc0a8165c02f7619cf5642d1427cba7
56+
upstream-source: ghcr.io/canonical/charmed-mysql@sha256:a1c81aab3e4ac53a2cb0454c6f3e8946d0586a97dba2585f2df1c7ef365ef437
5757
assumes:
5858
- k8s-api

poetry.lock

Lines changed: 1 addition & 2 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
@@ -10,7 +10,7 @@ authors = []
1010

1111
[tool.poetry.dependencies]
1212
python = "^3.10"
13-
ops = "^2.6.0"
13+
ops = "<2.10.0"
1414
lightkube = "^0.14.0"
1515
tenacity = "^8.2.3"
1616
jinja2 = "^3.1.2"
@@ -19,7 +19,7 @@ requests = "^2.31.0"
1919

2020
[tool.poetry.group.charm-libs.dependencies]
2121
# data_platform_libs/v0/data_interfaces.py
22-
ops = ">=2.0.0"
22+
ops = "<2.10.0"
2323
# tls_certificates_interface/v1/tls_certificates.py
2424
cryptography = "*"
2525
jsonschema = "*"
@@ -53,7 +53,7 @@ pytest = "^7.4.0"
5353
pytest-xdist = "^3.3.1"
5454
pytest-cov = "^4.1.0"
5555
ops-scenario = "^5.6.2"
56-
ops = ">=2.0.0"
56+
ops = "<2.10.0"
5757
pytest-mock = "^3.11.1"
5858

5959
[tool.poetry.group.integration.dependencies]
@@ -65,7 +65,7 @@ juju = "^3.2.2"
6565
mysql-connector-python = "~8.0.33"
6666
pyyaml = "^6.0.1"
6767
tenacity = "^8.2.2"
68-
ops = "^2.6.0"
68+
ops = "<2.10.0"
6969
allure-pytest = "^2.13.2"
7070

7171

src/abstract_charm.py

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,9 @@
55

66
import abc
77
import logging
8-
import socket
98
import typing
109

1110
import ops
12-
import tenacity
1311

1412
import container
1513
import lifecycle
@@ -18,6 +16,7 @@
1816
import relations.cos
1917
import relations.database_provides
2018
import relations.database_requires
19+
import relations.tls
2120
import server_exceptions
2221
import upgrade
2322
import workload
@@ -28,6 +27,11 @@
2827
class MySQLRouterCharm(ops.CharmBase, abc.ABC):
2928
"""MySQL Router charm"""
3029

30+
_READ_WRITE_PORT = 6446
31+
_READ_ONLY_PORT = 6447
32+
_READ_WRITE_X_PORT = 6448
33+
_READ_ONLY_X_PORT = 6449
34+
3135
def __init__(self, *args) -> None:
3236
super().__init__(*args)
3337
# Instantiate before registering other event observers
@@ -60,6 +64,7 @@ def __init__(self, *args) -> None:
6064
self.on[upgrade.PEER_RELATION_ENDPOINT_NAME].relation_created,
6165
self._upgrade_relation_created,
6266
)
67+
self.tls = relations.tls.RelationEndpoint(self)
6368

6469
@property
6570
@abc.abstractmethod
@@ -97,35 +102,39 @@ def _read_only_endpoint(self) -> str:
97102
@property
98103
@abc.abstractmethod
99104
def _exposed_read_write_endpoint(self) -> str:
100-
pass
105+
"""The exposed read-write endpoint"""
101106

102107
@property
103108
@abc.abstractmethod
104109
def _exposed_read_only_endpoint(self) -> str:
105-
pass
110+
"""The exposed read-only endpoint"""
111+
112+
@abc.abstractmethod
113+
def is_externally_accessible(self, *, event) -> typing.Optional[bool]:
114+
"""Whether endpoints should be externally accessible.
115+
116+
Only defined in vm charm to return True/False. In k8s charm, returns None.
117+
"""
106118

107119
@property
108120
def _tls_certificate_saved(self) -> bool:
109121
"""Whether a TLS certificate is available to use"""
110-
# TODO VM TLS: Update property after implementing TLS on machine_charm
111-
return False
122+
return self.tls.certificate_saved
112123

113124
@property
114125
def _tls_key(self) -> typing.Optional[str]:
115126
"""Custom TLS key"""
116-
# TODO VM TLS: Update property after implementing TLS on machine_charm
117-
return None
127+
return self.tls.key
118128

119129
@property
120-
def _tls_certificate(self) -> typing.Optional[str]:
121-
"""Custom TLS certificate"""
122-
# TODO VM TLS: Update property after implementing TLS on machine_charm
123-
return None
130+
def _tls_certificate_authority(self) -> typing.Optional[str]:
131+
"""Custom TLS certificate authority"""
132+
return self.tls.certificate_authority
124133

125134
@property
126-
def _tls_certificate_authority(self) -> typing.Optional[str]:
127-
# TODO VM TLS: Update property after implementing TLS on machine charm
128-
return None
135+
def _tls_certificate(self) -> typing.Optional[str]:
136+
"""Custom TLS certificate"""
137+
return self.tls.certificate
129138

130139
def _cos_exporter_config(self, event) -> typing.Optional[relations.cos.ExporterConfig]:
131140
"""Returns the exporter config for MySQLRouter exporter if cos relation exists"""
@@ -201,36 +210,27 @@ def set_status(self, *, event, app=True, unit=True) -> None:
201210
self.unit.status = self._determine_unit_status(event=event)
202211
logger.debug(f"Set unit status to {self.unit.status}")
203212

204-
def wait_until_mysql_router_ready(self) -> None:
213+
@abc.abstractmethod
214+
def wait_until_mysql_router_ready(self, *, event) -> None:
205215
"""Wait until a connection to MySQL Router is possible.
206216
207217
Retry every 5 seconds for up to 30 seconds.
208218
"""
209-
logger.debug("Waiting until MySQL Router is ready")
210-
self.unit.status = ops.MaintenanceStatus("MySQL Router starting")
211-
try:
212-
for attempt in tenacity.Retrying(
213-
reraise=True,
214-
stop=tenacity.stop_after_delay(30),
215-
wait=tenacity.wait_fixed(5),
216-
):
217-
with attempt:
218-
for port in (6446, 6447):
219-
with socket.socket() as s:
220-
assert s.connect_ex(("localhost", port)) == 0
221-
except AssertionError:
222-
logger.exception("Unable to connect to MySQL Router")
223-
raise
224-
else:
225-
logger.debug("MySQL Router is ready")
226219

227220
@abc.abstractmethod
228-
def _reconcile_node_port(self, event) -> None:
221+
def _reconcile_node_port(self, *, event) -> None:
229222
"""Reconcile node port.
230223
231224
Only applies to Kubernetes charm
232225
"""
233226

227+
@abc.abstractmethod
228+
def _reconcile_ports(self, *, event) -> None:
229+
"""Reconcile exposed ports.
230+
231+
Only applies to Machine charm
232+
"""
233+
234234
# =======================
235235
# Handlers
236236
# =======================
@@ -271,7 +271,10 @@ def reconcile(self, event=None) -> None: # noqa: C901
271271
if self._upgrade.unit_state == "outdated":
272272
if self._upgrade.authorized:
273273
self._upgrade.upgrade_unit(
274-
workload_=workload_, tls=self._tls_certificate_saved
274+
event=event,
275+
workload_=workload_,
276+
tls=self._tls_certificate_saved,
277+
exporter_config=self._cos_exporter_config(event),
275278
)
276279
else:
277280
self.set_status(event=event)
@@ -311,13 +314,19 @@ def reconcile(self, event=None) -> None: # noqa: C901
311314
)
312315
if workload_.container_ready:
313316
workload_.reconcile(
317+
event=event,
314318
tls=self._tls_certificate_saved,
315319
unit_name=self.unit.name,
316320
exporter_config=self._cos_exporter_config(event),
317321
key=self._tls_key,
318322
certificate=self._tls_certificate,
319323
certificate_authority=self._tls_certificate_authority,
320324
)
325+
if not self._upgrade.in_progress and isinstance(
326+
workload_, workload.AuthenticatedWorkload
327+
):
328+
self._reconcile_ports(event=event)
329+
321330
# Empty waiting status means we're waiting for database requires relation before
322331
# starting workload
323332
if not workload_.status or workload_.status == ops.WaitingStatus():

src/container.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,12 @@ def __init__(
9898
mysql_router_command: str,
9999
mysql_shell_command: str,
100100
mysql_router_password_command: str,
101+
unit_name: str,
101102
) -> None:
102103
self._mysql_router_command = mysql_router_command
103104
self._mysql_shell_command = mysql_shell_command
104105
self._mysql_router_password_command = mysql_router_password_command
106+
self._unit_name = unit_name
105107

106108
@property
107109
@abc.abstractmethod

src/kubernetes_charm.py

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
import lightkube.models.meta_v1
1616
import lightkube.resources.core_v1
1717
import ops
18+
import tenacity
1819

1920
import abstract_charm
2021
import kubernetes_logrotate
2122
import kubernetes_upgrade
2223
import logrotate
23-
import relations.tls
2424
import rock
2525
import upgrade
2626

@@ -32,9 +32,6 @@
3232
class KubernetesRouterCharm(abstract_charm.MySQLRouterCharm):
3333
"""MySQL Router Kubernetes charm"""
3434

35-
_READ_WRITE_PORT = 6446
36-
_READ_ONLY_PORT = 6447
37-
3835
def __init__(self, *args) -> None:
3936
super().__init__(*args)
4037
self._namespace = self.model.name
@@ -44,29 +41,11 @@ def __init__(self, *args) -> None:
4441
self.on[rock.CONTAINER_NAME].pebble_ready, self._on_workload_container_pebble_ready
4542
)
4643
self.framework.observe(self.on.stop, self._on_stop)
47-
# TODO VM TLS: Move to super class
48-
self.tls = relations.tls.RelationEndpoint(self)
4944

5045
@property
5146
def _subordinate_relation_endpoint_names(self) -> typing.Optional[typing.Iterable[str]]:
5247
return
5348

54-
@property
55-
def _tls_certificate_saved(self) -> bool:
56-
return self.tls.certificate_saved
57-
58-
@property
59-
def _tls_key(self) -> typing.Optional[str]:
60-
return self.tls.key
61-
62-
@property
63-
def _tls_certificate(self) -> typing.Optional[str]:
64-
return self.tls.certificate
65-
66-
@property
67-
def _tls_certificate_authority(self) -> typing.Optional[str]:
68-
return self.tls.certificate_authority
69-
7049
@property
7150
def _container(self) -> rock.Rock:
7251
return rock.Rock(unit=self.unit)
@@ -82,10 +61,39 @@ def _upgrade(self) -> typing.Optional[kubernetes_upgrade.Upgrade]:
8261
except upgrade.PeerRelationNotReady:
8362
pass
8463

85-
def _reconcile_node_port(self, event) -> None:
86-
"""Reconcile node port."""
64+
def is_externally_accessible(self, *, event) -> typing.Optional[bool]:
65+
"""No-op since this charm is exposed with node-port"""
66+
67+
def _reconcile_node_port(self, *, event) -> None:
8768
self._patch_service(event)
8869

70+
def _reconcile_ports(self, *, event) -> None:
71+
"""Needed for VM, so no-op"""
72+
73+
def wait_until_mysql_router_ready(self, *, event=None) -> None:
74+
logger.debug("Waiting until MySQL Router is ready")
75+
self.unit.status = ops.MaintenanceStatus("MySQL Router starting")
76+
try:
77+
for attempt in tenacity.Retrying(
78+
reraise=True,
79+
stop=tenacity.stop_after_delay(30),
80+
wait=tenacity.wait_fixed(5),
81+
):
82+
with attempt:
83+
for port in (
84+
self._READ_WRITE_PORT,
85+
self._READ_ONLY_PORT,
86+
self._READ_WRITE_X_PORT,
87+
self._READ_ONLY_X_PORT,
88+
):
89+
with socket.socket() as s:
90+
assert s.connect_ex(("localhost", port)) == 0
91+
except AssertionError:
92+
logger.exception("Unable to connect to MySQL Router")
93+
raise
94+
else:
95+
logger.debug("MySQL Router is ready")
96+
8997
@property
9098
def model_service_domain(self) -> str:
9199
"""K8s service domain for Juju model"""

src/kubernetes_logrotate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,5 @@ def disable(self) -> None:
4141

4242
logger.debug("Removing logrotate config and executor files")
4343
super().disable()
44-
self._logrotate_executor.unlink()
44+
self._logrotate_executor.unlink(missing_ok=True)
4545
logger.debug("Removed logrotate config and executor files")

0 commit comments

Comments
 (0)