X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=installers%2Fcharm%2Fosm-keystone%2Fsrc%2Fcluster.py;fp=installers%2Fcharm%2Fosm-keystone%2Fsrc%2Fcluster.py;h=f38adec015938bda7120dcd98d2b03429e8950a3;hb=d5b463cc04638b134d982c386596c82258c509fb;hp=0000000000000000000000000000000000000000;hpb=6003632d2c82a93d71a8826c6bcd182e22140bc3;p=osm%2Fdevops.git diff --git a/installers/charm/osm-keystone/src/cluster.py b/installers/charm/osm-keystone/src/cluster.py new file mode 100644 index 00000000..f38adec0 --- /dev/null +++ b/installers/charm/osm-keystone/src/cluster.py @@ -0,0 +1,135 @@ +# Copyright 2021 Canonical Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +# +# +# This file populates the Actions tab on Charmhub. +# See https://juju.is/docs/some-url-to-be-determined/ for a checklist and guidance. + +"""Keystone cluster library. + +This library allows the integration with Apache Guacd charm. Is is published as part of the +[davigar15-apache-guacd]((https://charmhub.io/davigar15-apache-guacd) charm. + +The charm that requires guacd should include the following content in its metadata.yaml: + +```yaml +# ... +peers: + cluster: + interface: cluster +# ... +``` + +A typical example of including this library might be: + +```python +# ... +from ops.framework import StoredState +from charms.keystone.v0 import cluster + +class SomeApplication(CharmBase): + on = cluster.ClusterEvents() + + def __init__(self, *args): + # ... + self.cluster = cluster.Cluster(self) + self.framework.observe(self.on.cluster_keys_changed, self._cluster_keys_changed) + # ... + + def _cluster_keys_changed(self, _): + fernet_keys = self.cluster.fernet_keys + credential_keys = self.cluster.credential_keys + # ... +``` +""" + + +import json +import logging +from typing import Any, Dict, List + +from ops.charm import CharmEvents +from ops.framework import EventBase, EventSource, Object +from ops.model import Relation + +# Number of keys need might need to be adjusted in the future +NUMBER_FERNET_KEYS = 2 +NUMBER_CREDENTIAL_KEYS = 2 + +logger = logging.getLogger(__name__) + + +class ClusterKeysChangedEvent(EventBase): + """Event to announce a change in the Guacd service.""" + + +class ClusterEvents(CharmEvents): + """Cluster Events.""" + + cluster_keys_changed = EventSource(ClusterKeysChangedEvent) + + +class Cluster(Object): + """Peer relation.""" + + def __init__(self, charm): + super().__init__(charm, "cluster") + self.charm = charm + + @property + def fernet_keys(self) -> List[str]: + """Fernet keys.""" + relation: Relation = self.model.get_relation("cluster") + application_data = relation.data[self.model.app] + return json.loads(application_data.get("keys-fernet", "[]")) + + @property + def credential_keys(self) -> List[str]: + """Credential keys.""" + relation: Relation = self.model.get_relation("cluster") + application_data = relation.data[self.model.app] + return json.loads(application_data.get("keys-credential", "[]")) + + def save_keys(self, keys: Dict[str, Any]) -> None: + """Generate fernet and credential keys. + + This method will generate new keys and fire the cluster_keys_changed event. + """ + logger.debug("Saving keys...") + relation: Relation = self.model.get_relation("cluster") + data = relation.data[self.model.app] + current_keys_str = data.get("key_repository", "{}") + current_keys = json.loads(current_keys_str) + if current_keys != keys: + data["key_repository"] = json.dumps(keys) + self.charm.on.cluster_keys_changed.emit() + logger.info("Keys saved!") + + def get_keys(self) -> Dict[str, Any]: + """Get keys from the relation. + + Returns: + Dict[str, Any]: Dictionary with the keys. + """ + relation: Relation = self.model.get_relation("cluster") + data = relation.data[self.model.app] + current_keys_str = data.get("key_repository", "{}") + current_keys = json.loads(current_keys_str) + return current_keys