Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dbcluster peer relation #56

Merged
merged 2 commits into from
Nov 29, 2023
Merged

Add dbcluster peer relation #56

merged 2 commits into from
Nov 29, 2023

Conversation

manadart
Copy link
Member

@manadart manadart commented Nov 27, 2023

This adds a new peer relation to the controller charm: dbcluster.

The binding for this relation will ultimately replace the Juju controller configuration article, juju-ha-space. Accordingly, the charm ensures that the current bound space yields a unique ingress address that gets set in relation data. If the address is not unique, the charm enters the blocked state.

Further work will follow that will write a charm-sourced configuration file to disk that will be an analogue for agent configuration.

Copy link

@PietroPasotti PietroPasotti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see some serious problems with the status management and one clear bug with the _db_bind_address state persistence, the rest is nits, pointers, or small suggestions.

src/charm.py Outdated Show resolved Hide resolved
src/charm.py Outdated Show resolved Hide resolved
src/charm.py Outdated
@@ -39,7 +44,7 @@ def _on_start(self, _):
self.unit.status = ActiveStatus()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you shouldn't do this unconditionally in __init__.
Suppose you receive website_relation_joined and you go in Blocked, next event you see (whichever event!) you'll go back to active and the user will never know that there's something wrong with the charm.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I understand. Is there a good example of this appropriate to a (currently) simple charm like this one?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can look at our most recent charm: https://github.com/canonical/mimir-coordinator-k8s-operator/blob/main/src/charm.py#L103

in a nutshell: observe the collect_unit_status event, and add several 'is this healthy?' endpoints that each adds a piece of status to the event. Either blocked or active.
Ops will take the worst status and set it to the unit, on each event.

return

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the remote unit can always access a remote's IP via `event.relation.data[event.relation.unit]["ingress-address"], although I'm not sure if it's the same 'ingress address' we're talking about here.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try jhack show-relation --show-juju-keys db controller to see for yourself what's in there

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ingres-address as set automatically during scope entry is actually just pulled from the zero index of the sorted addresses determined by retrieving network info (the same backing as the call to the network-get tool.

We actually want to give the assurance that the list is constituted by a single unique entry, hence the logic here. Going into the blocked state if we don't have a unique address is a message to the user that they need to set the endpoint binding to an appropriate space.

@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"])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

personally I'd use a MagicMock instead of creating these custom types but that's a preference.

binding = MagicMock()
binding.network.ingress_addresses = [...]
binding.network.ingress_address = ...

Copy link

@PietroPasotti PietroPasotti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks much better!

def _on_start(self, _):
self.unit.status = ActiveStatus()
def _on_collect_status(self, event: CollectStatusEvent):
if len(self._stored.last_bind_addresses) > 1:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unless you're doing it on purpose for readability, you can equivalently:

Suggested change
if len(self._stored.last_bind_addresses) > 1:
if self._stored.last_bind_addresses:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

len > 1 is having more than 1, not having more than 0. We're explicitly testing for the case that you don't have a singular unique value.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be > 0 though, right?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah my bad, misread that. You're totally right.

Copy link
Member

@anvial anvial left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read your and Pietro comments, looks like you made and agreement.

Did not find any opportunity to test it.

My +1 to unblock your further actions.

def _on_start(self, _):
self.unit.status = ActiveStatus()
def _on_collect_status(self, event: CollectStatusEvent):
if len(self._stored.last_bind_addresses) > 1:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

len > 1 is having more than 1, not having more than 0. We're explicitly testing for the case that you don't have a singular unique value.

@jameinel
Copy link
Member

@manadart your commits to this branch aren't signed.
You can just sign the last commit with:

git commit --amend --no-edit -S

Or go back and sign the chain of them with:

git rebase --exec 'git commit --amend --no-edit -n -S' -i development

@manadart manadart force-pushed the add-db-cluster branch 2 times, most recently from 8d2c5e3 to 9cf3fcd Compare November 29, 2023 15:36
relation data if we have a unique ingress address, or become blocked if
there is not a unique address.
Instead we handle the collect_unit_status event, using our known state
to supply candidate status values.
@manadart manadart merged commit cbe61b7 into juju:main Nov 29, 2023
@manadart manadart deleted the add-db-cluster branch November 29, 2023 15:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants