Skip to content

Commit

Permalink
Adds dbcluster peer relation with logic to set db-bind-address in
Browse files Browse the repository at this point in the history
relation data if we have a unique ingress address, or become blocked if
there is not a unique address.
  • Loading branch information
manadart committed Nov 27, 2023
1 parent 5db6a8d commit adf37a0
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 22 deletions.
3 changes: 3 additions & 0 deletions metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ provides:
interface: http
metrics-endpoint:
interface: prometheus_scrape
peers:
dbcluster:
interface: dbcluster
27 changes: 24 additions & 3 deletions src/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,17 @@ class JujuControllerCharm(CharmBase):

def __init__(self, *args):
super().__init__(*args)

self.framework.observe(self.on.config_changed, self._on_config_changed)
self.framework.observe(self.on.start, self._on_start)
self.framework.observe(
self.on.dashboard_relation_joined, self._on_dashboard_relation_joined)
self.framework.observe(
self.on.website_relation_joined, self._on_website_relation_joined)
self.framework.observe(
self.on.dbcluster_relation_changed, self._on_dbcluster_relation_changed)

self._db_bind_address = ''

self.control_socket = controlsocket.Client(
socket_path="/var/lib/juju/control.socket")
Expand All @@ -39,7 +44,7 @@ def _on_start(self, _):
self.unit.status = ActiveStatus()

def _on_config_changed(self, _):
controller_url = self.config["controller-url"]
controller_url = self.config['controller-url']
logger.info("got a new controller-url: %r", controller_url)

def _on_dashboard_relation_joined(self, event):
Expand All @@ -55,10 +60,10 @@ def _on_dashboard_relation_joined(self, event):

def _on_website_relation_joined(self, event):
"""Connect a website relation."""
logger.info("got a new website relation: %r", event)
logger.info('got a new website relation: %r', event)
port = self.api_port()
if port is None:
logger.error("machine does not appear to be a controller")
logger.error('machine does not appear to be a controller')
self.unit.status = BlockedStatus('machine does not appear to be a controller')
return

Expand Down Expand Up @@ -105,6 +110,22 @@ def _on_metrics_endpoint_relation_broken(self, event: RelationDepartedEvent):
username = metrics_username(event.relation)
self.control_socket.remove_metrics_user(username)

def _on_dbcluster_relation_changed(self, event):
ips = self.model.get_binding(event.relation).network.ingress_addresses

if len(ips) > 1:
logger.error('multiple possible DB bind addresses; set a dbcluster network binding')
self.unit.status = BlockedStatus(
'multiple possible DB bind addresses; set a dbcluster network binding')
return

ip = str(ips[0])
if self._db_bind_address == ip:
return

self._db_bind_address = ip
event.relation.data[self.unit].update({'db-bind-address': ip})

def _agent_conf(self, key: str):
"""Read a value (by key) from the agent.conf file on disk."""
unit_name = self.unit.name.replace('/', '-')
Expand Down
66 changes: 47 additions & 19 deletions tests/test_charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import os
import unittest
from charm import JujuControllerCharm
from ops.model import BlockedStatus
from ops.testing import Harness
from unittest.mock import mock_open, patch

Expand All @@ -14,10 +15,14 @@


class TestCharm(unittest.TestCase):
def test_relation_joined(self):
harness = Harness(JujuControllerCharm)
self.addCleanup(harness.cleanup)
harness.begin()
def setUp(self):
self.harness = Harness(JujuControllerCharm)
self.addCleanup(self.harness.cleanup)
self.harness.begin()

def test_dashboard_relation_joined(self):
harness = self.harness

harness.set_leader(True)
harness.update_config({"controller-url": "wss://controller/api"})
harness.update_config({"identity-provider-url": ""})
Expand All @@ -36,12 +41,10 @@ def test_relation_joined(self):
})
@patch("ops.model.Model.get_binding")
@patch("builtins.open", new_callable=mock_open, read_data=agent_conf)
def test_website_relation_joined(self, _, ingress_address):
ingress_address.return_value = MockBinding("192.168.1.17")
def test_website_relation_joined(self, _, binding):
harness = self.harness
binding.return_value = mockBinding(["192.168.1.17"])

harness = Harness(JujuControllerCharm)
self.addCleanup(harness.cleanup)
harness.begin()
harness.set_leader()
relation_id = harness.add_relation('website', 'haproxy')
harness.add_relation_unit(relation_id, 'haproxy/0')
Expand All @@ -58,10 +61,7 @@ def test_website_relation_joined(self, _, ingress_address):
@patch("controlsocket.Client.remove_metrics_user")
def test_metrics_endpoint_relation(self, mock_remove_user, mock_add_user,
mock_metrics_provider, _):
harness = Harness(JujuControllerCharm)
self.addCleanup(harness.cleanup)
harness.begin()

harness = self.harness
harness.add_network(address="192.168.1.17", endpoint="metrics-endpoint")

relation_id = harness.add_relation('metrics-endpoint', 'prometheus-k8s')
Expand All @@ -88,12 +88,40 @@ def test_metrics_endpoint_relation(self, mock_remove_user, mock_add_user,
harness.remove_relation(relation_id)
mock_remove_user.assert_called_once_with(f'juju-metrics-r{relation_id}')

@patch("ops.model.Model.get_binding")
def test_dbcluster_relation_changed_single_addr(self, binding):
harness = self.harness
binding.return_value = mockBinding(["192.168.1.17"])

relation_id = harness.add_relation('dbcluster', 'controller')
harness.add_relation_unit(relation_id, 'juju-controller/1')

harness.charm._on_dbcluster_relation_changed(
harness.charm.model.get_relation('dbcluster').data[harness.charm.unit])

data = harness.get_relation_data(relation_id, 'juju-controller/0')
self.assertEqual(data["db-bind-address"], "192.168.1.17")

@patch("ops.model.Model.get_binding")
def test_dbcluster_relation_changed_multi_addr_error(self, binding):
harness = self.harness
binding.return_value = mockBinding(["192.168.1.17", "192.168.1.18"])

relation_id = harness.add_relation('dbcluster', 'controller')
harness.add_relation_unit(relation_id, 'juju-controller/1')

harness.charm._on_dbcluster_relation_changed(
harness.charm.model.get_relation('dbcluster').data[harness.charm.unit])

self.assertIsInstance(harness.charm.unit.status, BlockedStatus)


class MockBinding:
def __init__(self, address):
self.network = MockNetwork(address)
class mockNetwork:
def __init__(self, addresses):
self.ingress_addresses = addresses
self.ingress_address = addresses[0]


class MockNetwork:
def __init__(self, address):
self.ingress_address = address
class mockBinding:
def __init__(self, addresses):
self.network = mockNetwork(addresses)

0 comments on commit adf37a0

Please sign in to comment.