Rename to designate-bind-k8s

Moved nonce from stored state to secret
This commit is contained in:
Guillaume Boutry 2023-10-03 11:01:59 +02:00
parent 1b42ad3265
commit cbd313d56d
8 changed files with 80 additions and 68 deletions

View File

@ -1,4 +1,4 @@
# bind9-k8s # designate-bind-k8s
## Developing ## Developing
@ -13,12 +13,12 @@ Create and activate a virtualenv with the development requirements:
Get familiarise with [Charmed Operator Framework](https://juju.is/docs/sdk) Get familiarise with [Charmed Operator Framework](https://juju.is/docs/sdk)
and [Sunbeam documentation](sunbeam-docs). and [Sunbeam documentation](sunbeam-docs).
bind9-k8s charm uses the ops\_sunbeam library and extends designate-bind-k8s charm uses the ops\_sunbeam library and extends
OSBaseOperatorAPICharm from the library. OSBaseOperatorAPICharm from the library.
## Intended use case ## Intended use case
bind9-k8s charm deploys and configures OpenStack Identity service designate-bind-k8s charm deploys and configures OpenStack Identity service
on a kubernetes based environment. on a kubernetes based environment.
## Roadmap ## Roadmap
@ -41,11 +41,11 @@ run:
To deploy the local test instance: To deploy the local test instance:
juju deploy ./bind9-k8s_ubuntu-20.04-amd64.charm --trust --resource bind9-image=ghcr.io/openstack-snaps/bind9:2023.1 juju deploy ./designate-bind-k8s_ubuntu-20.04-amd64.charm --trust --resource designate-bind-image=ghcr.io/openstack-snaps/designate-bind:2023.1
<!-- LINKS --> <!-- LINKS -->
[bind9-k8s-libs-docs]: https://charmhub.io/sunbeam-bind9-operator/libraries/identity_service [designate-bind-k8s-libs-docs]: https://charmhub.io/sunbeam-designate-bind-operator/libraries/identity_service
[sunbeam-docs]: https://opendev.org/openstack/charm-ops-sunbeam/src/branch/main/README.rst [sunbeam-docs]: https://opendev.org/openstack/charm-ops-sunbeam/src/branch/main/README.rst

View File

@ -8,10 +8,10 @@ Avoid using this README file for information that is maintained or published els
Use links instead. Use links instead.
--> -->
# charm-bind9 # designate-bind-k8s
Charmhub package name: operator-template Charmhub package name: operator-template
More information: https://charmhub.io/charm-bind9 More information: https://charmhub.io/designate-bind-k8s
Describe your charm in one or two sentences. Describe your charm in one or two sentences.

View File

@ -13,7 +13,7 @@ Two events are also available to respond to:
- goneaway - goneaway
A basic example showing the usage of this relation follows: A basic example showing the usage of this relation follows:
``` ```
from charms.bind9_k8s.v0.bind_rndc import ( from charms.designate_bind_k8s.v0.bind_rndc import (
BindRndcRequires BindRndcRequires
) )
class BindRndcClientCharm(CharmBase): class BindRndcClientCharm(CharmBase):
@ -31,6 +31,13 @@ class BindRndcClientCharm(CharmBase):
self.bind_rndc.on.goneaway, self.bind_rndc.on.goneaway,
self._on_bind_rndc_goneaway self._on_bind_rndc_goneaway
) )
def _on_bind_rndc_connected(self, event):
'''React to the Bind Rndc Connected event.
This event happens when BindRndc relation is added to the
model.
'''
# Request the rndc key from the Bind Rndc relation.
self.bind_rndc.request_rndc_key("generated nonce")
def _on_bind_rndc_ready(self, event): def _on_bind_rndc_ready(self, event):
'''React to the Bind Rndc Ready event. '''React to the Bind Rndc Ready event.
This event happens when BindRndc relation is added to the This event happens when BindRndc relation is added to the
@ -49,7 +56,6 @@ class BindRndcClientCharm(CharmBase):
import json import json
import logging import logging
import secrets
from typing import ( from typing import (
Any, Any,
Dict, Dict,
@ -63,14 +69,41 @@ import ops
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# The unique Charmhub library identifier, never change it # The unique Charmhub library identifier, never change it
LIBID = "0fb2f64f2a1344feb80044cee22ef3a8" LIBID = "1cb766c981874e7383d17cf54148b3d4"
# Increment this major API version when introducing breaking changes # Increment this major API version when introducing breaking changes
LIBAPI = 0 LIBAPI = 0
# Increment this PATCH version before using `charmcraft publish-lib` or reset # Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version # to 0 if you are raising the major API version
LIBPATCH = 3 LIBPATCH = 1
class BindRndcConnectedEvent(ops.EventBase):
"""Bind rndc connected event."""
def __init__(
self,
handle: ops.Handle,
relation_id: int,
relation_name: str,
):
super().__init__(handle)
self.relation_id = relation_id
self.relation_name = relation_name
def snapshot(self) -> dict:
"""Return snapshot data that should be persisted."""
return {
"relation_id": self.relation_id,
"relation_name": self.relation_name,
}
def restore(self, snapshot: Dict[str, Any]):
"""Restore the value state from a given snapshot."""
super().restore(snapshot)
self.relation_id = snapshot["relation_id"]
self.relation_name = snapshot["relation_name"]
class BindRndcReadyEvent(ops.EventBase): class BindRndcReadyEvent(ops.EventBase):
@ -81,22 +114,16 @@ class BindRndcReadyEvent(ops.EventBase):
handle: ops.Handle, handle: ops.Handle,
relation_id: int, relation_id: int,
relation_name: str, relation_name: str,
algorithm: str,
secret: str,
): ):
super().__init__(handle) super().__init__(handle)
self.relation_id = relation_id self.relation_id = relation_id
self.relation_name = relation_name self.relation_name = relation_name
self.algorithm = algorithm
self.secret = secret
def snapshot(self) -> dict: def snapshot(self) -> dict:
"""Return snapshot data that should be persisted.""" """Return snapshot data that should be persisted."""
return { return {
"relation_id": self.relation_id, "relation_id": self.relation_id,
"relation_name": self.relation_name, "relation_name": self.relation_name,
"algorithm": self.algorithm,
"secret": self.secret,
} }
def restore(self, snapshot: Dict[str, Any]): def restore(self, snapshot: Dict[str, Any]):
@ -104,8 +131,6 @@ class BindRndcReadyEvent(ops.EventBase):
super().restore(snapshot) super().restore(snapshot)
self.relation_id = snapshot["relation_id"] self.relation_id = snapshot["relation_id"]
self.relation_name = snapshot["relation_name"] self.relation_name = snapshot["relation_name"]
self.algorithm = snapshot["algorithm"]
self.secret = snapshot["secret"]
class BindRndcGoneAwayEvent(ops.EventBase): class BindRndcGoneAwayEvent(ops.EventBase):
@ -117,7 +142,8 @@ class BindRndcGoneAwayEvent(ops.EventBase):
class BindRndcRequirerEvents(ops.ObjectEvents): class BindRndcRequirerEvents(ops.ObjectEvents):
"""List of events that the BindRndc requires charm can leverage.""" """List of events that the BindRndc requires charm can leverage."""
bind_rndc_ready = ops.EventSource(BindRndcReadyEvent) connected = ops.EventSource(BindRndcConnectedEvent)
ready = ops.EventSource(BindRndcReadyEvent)
goneaway = ops.EventSource(BindRndcGoneAwayEvent) goneaway = ops.EventSource(BindRndcGoneAwayEvent)
@ -125,13 +151,11 @@ class BindRndcRequires(ops.Object):
"""Class to be instantiated by the requiring side of the relation.""" """Class to be instantiated by the requiring side of the relation."""
on = BindRndcRequirerEvents() on = BindRndcRequirerEvents()
_stored = ops.StoredState()
def __init__(self, charm: ops.CharmBase, relation_name: str): def __init__(self, charm: ops.CharmBase, relation_name: str):
super().__init__(charm, relation_name) super().__init__(charm, relation_name)
self.charm = charm self.charm = charm
self.relation_name = relation_name self.relation_name = relation_name
self._stored.set_default(nonce="")
self.framework.observe( self.framework.observe(
self.charm.on[relation_name].relation_joined, self.charm.on[relation_name].relation_joined,
self._on_relation_joined, self._on_relation_joined,
@ -147,24 +171,20 @@ class BindRndcRequires(ops.Object):
def _on_relation_joined(self, event: ops.RelationJoinedEvent): def _on_relation_joined(self, event: ops.RelationJoinedEvent):
"""Handle relation joined event.""" """Handle relation joined event."""
self._request_rndc_key(event.relation) self.on.connected.emit(
event.relation.id,
event.relation.name,
)
def _on_relation_changed(self, event: ops.RelationJoinedEvent): def _on_relation_changed(self, event: ops.RelationJoinedEvent):
"""Handle relation changed event.""" """Handle relation changed event."""
host = self.host(event.relation) host = self.host(event.relation)
rndc_key = self.get_rndc_key(event.relation) rndc_key = self.get_rndc_key(event.relation)
if rndc_key is None:
self._request_rndc_key(event.relation)
return
if host is not None: if all((host, rndc_key)):
algorithm = rndc_key["algorithm"] self.on.ready.emit(
secret = rndc_key["secret"]
self.on.bind_rndc_ready.emit(
event.relation.id, event.relation.id,
event.relation.name, event.relation.name,
algorithm,
secret,
) )
def _on_relation_broken(self, event: ops.RelationBrokenEvent): def _on_relation_broken(self, event: ops.RelationBrokenEvent):
@ -177,33 +197,25 @@ class BindRndcRequires(ops.Object):
return None return None
return relation.data[relation.app].get("host") return relation.data[relation.app].get("host")
def nonce(self) -> str: def nonce(self, relation: ops.Relation) -> Optional[str]:
"""Return nonce from stored state.""" """Return nonce from relation."""
return self._stored.nonce return relation.data[self.charm.unit].get("nonce")
def get_rndc_key(self, relation: ops.Relation) -> Optional[dict]: def get_rndc_key(self, relation: ops.Relation) -> Optional[dict]:
"""Get rndc keys.""" """Get rndc keys."""
if relation.app is None: if relation.app is None:
return None return None
if self._stored.nonce == "": if self.nonce(relation) is None:
logger.debug("No nonce set for unit yet") logger.debug("No nonce set for unit yet")
return None return None
return json.loads( return json.loads(
relation.data[relation.app].get("rndc_keys", "{}") relation.data[relation.app].get("rndc_keys", "{}")
).get(self._stored.nonce) ).get(self.nonce(relation))
def _request_rndc_key(self, relation: ops.Relation): def request_rndc_key(self, relation: ops.Relation, nonce: str):
"""Request rndc key over the relation.""" """Request rndc key over the relation."""
if self._stored.nonce == "": relation.data[self.charm.unit]["nonce"] = nonce
self._stored.nonce = secrets.token_hex(16)
relation.data[self.charm.unit]["nonce"] = self._stored.nonce
def reconcile_rndc_key(self, relation: ops.Relation):
"""Reconcile rndc key over the relation."""
if self._stored.nonce != relation.data[self.charm.unit].get("nonce"):
self._stored.nonce = secrets.token_hex(16)
relation.data[self.charm.unit]["nonce"] = self._stored.nonce
class NewBindClientAttachedEvent(ops.EventBase): class NewBindClientAttachedEvent(ops.EventBase):

View File

@ -1,5 +1,5 @@
name: bind9-k8s name: designate-bind-k8s
summary: OpenStack bind9 service summary: OpenStack designate-bind service
maintainer: OpenStack Charmers <openstack-charmers@lists.ubuntu.com> maintainer: OpenStack Charmers <openstack-charmers@lists.ubuntu.com>
description: | description: |
Domain Name Service (DNS) is an Internet service that maps IP addresses and fully qualified domain names (FQDN) to one another. Domain Name Service (DNS) is an Internet service that maps IP addresses and fully qualified domain names (FQDN) to one another.
@ -14,15 +14,15 @@ assumes:
- juju >= 3.1 - juju >= 3.1
tags: tags:
- openstack - openstack
source: https://opendev.org/openstack/charm-bind9-k8s source: https://opendev.org/openstack/charm-designate-bind-k8s
issues: https://bugs.launchpad.net/charm-bind9-k8s issues: https://bugs.launchpad.net/charm-designate-bind-k8s
containers: containers:
bind9: designate-bind:
resource: bind9-image resource: designate-bind-image
resources: resources:
bind9-image: designate-bind-image:
type: oci-image type: oci-image
description: OCI image for bind9 description: OCI image for bind9
upstream-source: ubuntu/bind9:9.18-22.04_beta upstream-source: ubuntu/bind9:9.18-22.04_beta

View File

@ -12,9 +12,9 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
"""Bind9 Operator Charm. """designate-bind Operator Charm.
This charm provide Bind9 services This charm provide designate-bind services
""" """
import base64 import base64
@ -27,7 +27,7 @@ from typing import (
List, List,
) )
import charms.bind9_k8s.v0.bind_rndc as bind_rndc import charms.designate_bind_k8s.v0.bind_rndc as bind_rndc
import charms.observability_libs.v1.kubernetes_service_patch as kubernetes_service_patch import charms.observability_libs.v1.kubernetes_service_patch as kubernetes_service_patch
import lightkube.models.core_v1 as core_v1 import lightkube.models.core_v1 as core_v1
import ops.charm import ops.charm
@ -50,17 +50,17 @@ RNDC_REVISION_KEY = "rndc_revision"
class BindPebbleHandler(sunbeam_chandlers.ServicePebbleHandler): class BindPebbleHandler(sunbeam_chandlers.ServicePebbleHandler):
"""Pebble handler for bind9 service.""" """Pebble handler for designate-bind service."""
def get_layer(self) -> dict: def get_layer(self) -> dict:
"""Pebble layer for bind 9 service.""" """Pebble layer for bind 9 service."""
return { return {
"summary": "bind9 layer", "summary": "designate-bind layer",
"description": "pebble config layer for bind9", "description": "pebble config layer for designate-bind",
"services": { "services": {
"bind9": { "designate-bind": {
"override": "replace", "override": "replace",
"summary": "bind9", "summary": "designate-bind",
"command": "/usr/sbin/named -g -u bind", "command": "/usr/sbin/named -g -u bind",
"startup": "enabled", "startup": "enabled",
} }
@ -181,7 +181,7 @@ class BindOperatorCharm(sunbeam_charm.OSBaseOperatorCharmK8S):
"""Charm the service.""" """Charm the service."""
_state = StoredState() _state = StoredState()
service_name = "bind9" service_name = "designate-bind"
# mandatory_relations = {} # mandatory_relations = {}

View File

@ -1,8 +1,8 @@
bundle: kubernetes bundle: kubernetes
applications: applications:
bind9: designate-bind:
charm: ../../bind9-k8s.charm charm: ../../designate-bind-k8s.charm
scale: 1 scale: 1
trust: false trust: false
resources: resources:
bind9-image: ubuntu/bind9:9.18-22.04_beta designate-bind-image: ubuntu/designate-bind:9.18-22.04_beta

View File

@ -17,6 +17,6 @@ tests_options:
smoke: True smoke: True
target_deploy_status: target_deploy_status:
bind9: designate-bind:
workload-status: active workload-status: active
workload-status-message-regex: '^$' workload-status-message-regex: '^$'

View File

@ -11,7 +11,7 @@ minversion = 3.18.0
src_path = {toxinidir}/src/ src_path = {toxinidir}/src/
tst_path = {toxinidir}/tests/ tst_path = {toxinidir}/tests/
lib_path = {toxinidir}/lib/ lib_path = {toxinidir}/lib/
project_lib_path = {toxinidir}/lib/charms/bind9_k8s project_lib_path = {toxinidir}/lib/charms/designate_bind_k8s
pyproject_toml = {toxinidir}/pyproject.toml pyproject_toml = {toxinidir}/pyproject.toml
all_path = {[vars]src_path} {[vars]tst_path} {[vars]project_lib_path} all_path = {[vars]src_path} {[vars]tst_path} {[vars]project_lib_path}