Skip to content

Commit

Permalink
Port bug fixes and changes noticed while testing COS integration in k…
Browse files Browse the repository at this point in the history
…8s charm (#116)

## Issue
There were a number of issues encountered while testing the COS
integration in the k8s charm. The fixes for these issues are still
missing from this repo

## Solution
Port fixes
  • Loading branch information
shayancanonical authored Apr 1, 2024
1 parent fd35e6c commit 5d89fb6
Show file tree
Hide file tree
Showing 10 changed files with 192 additions and 90 deletions.
22 changes: 21 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ ops = "^2.6.0"
tenacity = "^8.2.3"
poetry-core = "^1.7.0"
jinja2 = "^3.1.2"
requests = "^2.31.0"

[tool.poetry.group.charm-libs.dependencies]
# data_platform_libs/v0/data_interfaces.py
Expand Down
32 changes: 18 additions & 14 deletions src/abstract_charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def __init__(self, *args) -> None:
self._authenticated_workload_type = workload.AuthenticatedWorkload
self._database_requires = relations.database_requires.RelationEndpoint(self)
self._database_provides = relations.database_provides.RelationEndpoint(self)
self._cos_relation = relations.cos.COSRelation(self, self._container)
self.framework.observe(self.on.update_status, self.reconcile)
self.framework.observe(
self.on[upgrade.PEER_RELATION_ENDPOINT_NAME].relation_changed, self.reconcile
Expand Down Expand Up @@ -83,11 +84,6 @@ def _upgrade(self) -> typing.Optional[upgrade.Upgrade]:
def _logrotate(self) -> logrotate.LogRotate:
"""logrotate"""

@property
@abc.abstractmethod
def _cos(self) -> relations.cos.COSRelation:
"""COS"""

@property
@abc.abstractmethod
def _read_write_endpoint(self) -> str:
Expand All @@ -105,23 +101,30 @@ def _tls_certificate_saved(self) -> bool:
return False

@property
def _tls_key(self) -> str:
def _tls_key(self) -> typing.Optional[str]:
"""Custom TLS key"""
# TODO VM TLS: Update property after implementing TLS on machine_charm
return None

@property
def _tls_certificate(self) -> str:
def _tls_certificate(self) -> typing.Optional[str]:
"""Custom TLS certificate"""
# TODO VM TLS: Update property after implementing TLS on machine_charm
return None

@property
def _tls_certificate_authority(self) -> typing.Optional[str]:
# TODO VM TLS: Update property after implementing TLS on machine charm
return None

def _cos_exporter_config(self, event) -> typing.Optional[relations.cos.ExporterConfig]:
"""Returns the exporter config for MySQLRouter exporter if cos relation exists"""
cos_relation_exists = self._cos.relation_exists and not self._cos.is_relation_breaking(
event
cos_relation_exists = (
self._cos_relation.relation_exists
and not self._cos_relation.is_relation_breaking(event)
)
return self._cos.exporter_user_config if cos_relation_exists else None
if cos_relation_exists:
return self._cos_relation.exporter_user_config

def get_workload(self, *, event):
"""MySQL Router workload"""
Expand All @@ -130,11 +133,11 @@ def get_workload(self, *, event):
container_=self._container,
logrotate_=self._logrotate,
connection_info=connection_info,
cos=self._cos,
cos=self._cos_relation,
charm_=self,
)
return self._workload_type(
container_=self._container, logrotate_=self._logrotate, cos=self._cos
container_=self._container, logrotate_=self._logrotate, cos=self._cos_relation
)

@staticmethod
Expand Down Expand Up @@ -259,8 +262,8 @@ def reconcile(self, event=None) -> None: # noqa: C901
f"{isinstance(workload_, workload.AuthenticatedWorkload)=}, "
f"{workload_.container_ready=}, "
f"{self._database_requires.is_relation_breaking(event)=}, "
f"{self._upgrade.in_progress=}"
f"{self._cos.is_relation_breaking(event)=}"
f"{self._upgrade.in_progress=}, "
f"{self._cos_relation.is_relation_breaking(event)=}"
)

try:
Expand Down Expand Up @@ -289,6 +292,7 @@ def reconcile(self, event=None) -> None: # noqa: C901
exporter_config=self._cos_exporter_config(event),
key=self._tls_key,
certificate=self._tls_certificate,
certificate_authority=self._tls_certificate_authority,
)
# Empty waiting status means we're waiting for database requires relation before
# starting workload
Expand Down
30 changes: 29 additions & 1 deletion src/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,17 +134,33 @@ def update_mysql_router_service(self, *, enabled: bool, tls: bool = None) -> Non

@abc.abstractmethod
def update_mysql_router_exporter_service(
self, *, enabled: bool, config: "relations.cos.ExporterConfig" = None
self,
*,
enabled: bool,
config: "relations.cos.ExporterConfig" = None,
tls: bool = None,
key_filename: str = None,
certificate_filename: str = None,
certificate_authority_filename: str = None,
) -> None:
"""Update and restart the MySQL Router exporter service.
Args:
enabled: Whether MySQL Router exporter service is enabled
config: The configuration for MySQL Router exporter
tls: Whether custom TLS is enabled on the unit
key_filename: The TLS key filename
certificate_filename: The TLS certificate filename
certificate_authority_filename: The TLS certificate authority filename
"""
if enabled and not config:
raise ValueError("Missing MySQL Router exporter config")

if tls and not (certificate_authority_filename and certificate_filename and key_filename):
raise ValueError(
"`key`, `certificate` and `certificate_authority` required when tls=True"
)

@abc.abstractmethod
def upgrade(self, unit: ops.Unit) -> None:
"""Upgrade container version
Expand Down Expand Up @@ -203,6 +219,18 @@ def set_mysql_router_rest_api_password(
"""Set REST API credentials using the mysqlrouter_password command."""
self.create_router_rest_api_credentials_file()

if not password:
users_credentials = self._run_command(
[
self._mysql_router_password_command,
"list",
str(self.rest_api_credentials_file),
],
timeout=30,
)
if user not in users_credentials:
return

action = "set" if password else "delete"
self._run_command(
[
Expand Down
7 changes: 0 additions & 7 deletions src/machine_charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import abstract_charm
import machine_logrotate
import machine_upgrade
import relations.cos
import relations.database_providers_wrapper
import snap
import socket_workload
Expand All @@ -33,8 +32,6 @@ def __init__(self, *args) -> None:
self._database_provides = relations.database_providers_wrapper.RelationEndpoint(
self, self._database_provides
)
self._cos_relation = relations.cos.COSRelation(self, self._container)

self._authenticated_workload_type = socket_workload.AuthenticatedSocketWorkload
self.framework.observe(self.on.install, self._on_install)
self.framework.observe(self.on.remove, self._on_remove)
Expand Down Expand Up @@ -63,10 +60,6 @@ def _upgrade(self) -> typing.Optional[machine_upgrade.Upgrade]:
def _logrotate(self) -> machine_logrotate.LogRotate:
return machine_logrotate.LogRotate(container_=self._container)

@property
def _cos(self) -> relations.cos.COSRelation:
return self._cos_relation

@property
def _read_write_endpoint(self) -> str:
return f'file://{self._container.path("/run/mysqlrouter/mysql.sock")}'
Expand Down
37 changes: 9 additions & 28 deletions src/relations/cos.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ class COSRelation:
"""Relation with the cos bundle."""

_EXPORTER_PORT = "49152"
_HTTP_SERVER_PORT = "8443"
HTTP_SERVER_PORT = "8443"
_NAME = "cos-agent"
_PEER_RELATION_NAME = "cos"

_MONITORING_USERNAME = "monitoring"
MONITORING_USERNAME = "monitoring"
_MONITORING_PASSWORD_KEY = "monitoring-password"

def __init__(self, charm_: "abstract_charm.MySQLRouterCharm", container_: container.Container):
Expand All @@ -52,7 +52,7 @@ def __init__(self, charm_: "abstract_charm.MySQLRouterCharm", container_: contai
],
log_slots=[f"{_SNAP_NAME}:logs"],
)
self.charm = charm_
self._charm = charm_
self._container = container_

charm_.framework.observe(
Expand All @@ -74,17 +74,17 @@ def __init__(self, charm_: "abstract_charm.MySQLRouterCharm", container_: contai
def exporter_user_config(self) -> ExporterConfig:
"""Returns user config needed for the router exporter service."""
return ExporterConfig(
url=f"https://127.0.0.1:{self._HTTP_SERVER_PORT}",
username=self._MONITORING_USERNAME,
password=self._get_monitoring_password(),
url=f"https://127.0.0.1:{self.HTTP_SERVER_PORT}",
username=self.MONITORING_USERNAME,
password=self.get_monitoring_password(),
)

@property
def relation_exists(self) -> bool:
"""Whether relation with cos exists."""
return len(self.charm.model.relations.get(self._NAME, [])) == 1
return len(self._charm.model.relations.get(self._NAME, [])) == 1

def _get_monitoring_password(self) -> str:
def get_monitoring_password(self) -> str:
"""Gets the monitoring password from unit peer data, or generate and cache it."""
monitoring_password = self._secrets.get_secret(
relations.secrets.UNIT_SCOPE, self._MONITORING_PASSWORD_KEY
Expand All @@ -109,24 +109,5 @@ def is_relation_breaking(self, event) -> bool:

return (
isinstance(event, ops.RelationBrokenEvent)
and event.relation.id == self.charm.model.relations[self._NAME][0].id
and event.relation.id == self._charm.model.relations[self._NAME][0].id
)

def setup_monitoring_user(self) -> None:
"""Set up a router REST API use for mysqlrouter exporter."""
logger.debug("Setting up router REST API user for mysqlrouter exporter")
self._container.set_mysql_router_rest_api_password(
user=self._MONITORING_USERNAME,
password=self._get_monitoring_password(),
)
logger.debug("Set up router REST API user for mysqlrouter exporter")

def cleanup_monitoring_user(self) -> None:
"""Clean up router REST API user for mysqlrouter exporter."""
logger.debug("Cleaning router REST API user for mysqlrouter exporter")
self._container.set_mysql_router_rest_api_password(
user=self._MONITORING_USERNAME,
password=None,
)
self._reset_monitoring_password()
logger.debug("Cleaned router REST API user for mysqlrouter exporter")
Loading

0 comments on commit 5d89fb6

Please sign in to comment.