1 # Copyright 2021 Canonical Ltd.
3 # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 # not use this file except in compliance with the License. You may obtain
5 # a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 # License for the specific language governing permissions and limitations
15 # For those usages not covered by the Apache License, Version 2.0 please
16 # contact: legal@canonical.com
18 # To get in touch with the maintainers, please contact:
19 # osm-charmers@lists.launchpad.net
22 # This file populates the Actions tab on Charmhub.
23 # See https://juju.is/docs/some-url-to-be-determined/ for a checklist and guidance.
25 """Keystone cluster library.
27 This library allows the integration with Apache Guacd charm. Is is published as part of the
28 [davigar15-apache-guacd]((https://charmhub.io/davigar15-apache-guacd) charm.
30 The charm that requires guacd should include the following content in its metadata.yaml:
40 A typical example of including this library might be:
44 from ops.framework import StoredState
45 from charms.keystone.v0 import cluster
47 class SomeApplication(CharmBase):
48 on = cluster.ClusterEvents()
50 def __init__(self, *args):
52 self.cluster = cluster.Cluster(self)
53 self.framework.observe(self.on.cluster_keys_changed, self._cluster_keys_changed)
56 def _cluster_keys_changed(self, _):
57 fernet_keys = self.cluster.fernet_keys
58 credential_keys = self.cluster.credential_keys
66 from typing
import Any
, Dict
, List
68 from ops
.charm
import CharmEvents
69 from ops
.framework
import EventBase
, EventSource
, Object
70 from ops
.model
import Relation
72 # Number of keys need might need to be adjusted in the future
73 NUMBER_FERNET_KEYS
= 2
74 NUMBER_CREDENTIAL_KEYS
= 2
76 logger
= logging
.getLogger(__name__
)
79 class ClusterKeysChangedEvent(EventBase
):
80 """Event to announce a change in the Guacd service."""
83 class ClusterEvents(CharmEvents
):
86 cluster_keys_changed
= EventSource(ClusterKeysChangedEvent
)
89 class Cluster(Object
):
92 def __init__(self
, charm
):
93 super().__init
__(charm
, "cluster")
97 def fernet_keys(self
) -> List
[str]:
99 relation
: Relation
= self
.model
.get_relation("cluster")
100 application_data
= relation
.data
[self
.model
.app
]
101 return json
.loads(application_data
.get("keys-fernet", "[]"))
104 def credential_keys(self
) -> List
[str]:
105 """Credential keys."""
106 relation
: Relation
= self
.model
.get_relation("cluster")
107 application_data
= relation
.data
[self
.model
.app
]
108 return json
.loads(application_data
.get("keys-credential", "[]"))
110 def save_keys(self
, keys
: Dict
[str, Any
]) -> None:
111 """Generate fernet and credential keys.
113 This method will generate new keys and fire the cluster_keys_changed event.
115 logger
.debug("Saving keys...")
116 relation
: Relation
= self
.model
.get_relation("cluster")
117 data
= relation
.data
[self
.model
.app
]
118 current_keys_str
= data
.get("key_repository", "{}")
119 current_keys
= json
.loads(current_keys_str
)
120 if current_keys
!= keys
:
121 data
["key_repository"] = json
.dumps(keys
)
122 self
.charm
.on
.cluster_keys_changed
.emit()
123 logger
.info("Keys saved!")
125 def get_keys(self
) -> Dict
[str, Any
]:
126 """Get keys from the relation.
129 Dict[str, Any]: Dictionary with the keys.
131 relation
: Relation
= self
.model
.get_relation("cluster")
132 data
= relation
.data
[self
.model
.app
]
133 current_keys_str
= data
.get("key_repository", "{}")
134 current_keys
= json
.loads(current_keys_str
)