2 # Copyright 2022 Canonical Ltd.
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 # not use this file except in compliance with the License. You may obtain
6 # a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations
16 # For those usages not covered by the Apache License, Version 2.0 please
17 # contact: legal@canonical.com
19 # To get in touch with the maintainers, please contact:
20 # osm-charmers@lists.launchpad.net
23 # Learn more at: https://juju.is/docs/sdk
27 This [library](https://juju.is/docs/sdk/libraries) implements both sides of the
28 `nbi` [interface](https://juju.is/docs/sdk/relations).
30 The *provider* side of this interface is implemented by the
31 [osm-nbi Charmed Operator](https://charmhub.io/osm-nbi).
33 Any Charmed Operator that *requires* NBI for providing its
34 service should implement the *requirer* side of this interface.
36 In a nutshell using this library to implement a Charmed Operator *requiring*
40 $ charmcraft fetch-lib charms.osm_nbi.v0.nbi
55 from charms.osm_nbi.v0.nbi import NbiRequires
56 from ops.charm import CharmBase
59 class MyCharm(CharmBase):
61 def __init__(self, *args):
62 super().__init__(*args)
63 self.nbi = NbiRequires(self)
64 self.framework.observe(
65 self.on["nbi"].relation_changed,
66 self._on_nbi_relation_changed,
68 self.framework.observe(
69 self.on["nbi"].relation_broken,
70 self._on_nbi_relation_broken,
72 self.framework.observe(
73 self.on["nbi"].relation_broken,
77 def _on_nbi_relation_broken(self, event):
78 # Get NBI host and port
79 host: str = self.nbi.host
80 port: int = self.nbi.port
84 def _on_nbi_broken(self, event):
87 self.unit.status = BlockedStatus("need nbi relation")
91 [here](https://osm.etsi.org/bugzilla/enter_bug.cgi), selecting the `devops` module!
93 from typing
import Optional
95 from ops
.charm
import CharmBase
, CharmEvents
96 from ops
.framework
import EventBase
, EventSource
, Object
97 from ops
.model
import Relation
100 # The unique Charmhub library identifier, never change it
101 LIBID
= "8c888f7c869949409e12c16d78ec068b"
103 # Increment this major API version when introducing breaking changes
106 # Increment this PATCH version before using `charmcraft publish-lib` or reset
107 # to 0 if you are raising the major API version
110 NBI_HOST_APP_KEY
= "host"
111 NBI_PORT_APP_KEY
= "port"
114 class NbiRequires(Object
): # pragma: no cover
115 """Requires-side of the Nbi relation."""
117 def __init__(self
, charm
: CharmBase
, endpoint_name
: str = "nbi") -> None:
118 super().__init
__(charm
, endpoint_name
)
120 self
._endpoint
_name
= endpoint_name
122 # Observe relation events
123 event_observe_mapping
= {
124 charm
.on
[self
._endpoint
_name
].relation_changed
: self
._on
_relation
_changed
,
126 for event
, observer
in event_observe_mapping
.items():
127 self
.framework
.observe(event
, observer
)
130 def host(self
) -> str:
131 """Get nbi hostname."""
132 relation
: Relation
= self
.model
.get_relation(self
._endpoint
_name
)
134 relation
.data
[relation
.app
].get(NBI_HOST_APP_KEY
)
135 if relation
and relation
.app
140 def port(self
) -> int:
141 """Get nbi port number."""
142 relation
: Relation
= self
.model
.get_relation(self
._endpoint
_name
)
144 int(relation
.data
[relation
.app
].get(NBI_PORT_APP_KEY
))
145 if relation
and relation
.app
150 class NbiProvides(Object
):
151 """Provides-side of the Nbi relation."""
153 def __init__(self
, charm
: CharmBase
, endpoint_name
: str = "nbi") -> None:
154 super().__init
__(charm
, endpoint_name
)
155 self
._endpoint
_name
= endpoint_name
157 def set_host_info(self
, host
: str, port
: int, relation
: Optional
[Relation
] = None) -> None:
158 """Set Nbi host and port.
160 This function writes in the application data of the relation, therefore,
161 only the unit leader can call it.
164 host (str): Nbi hostname or IP address.
165 port (int): Nbi port.
166 relation (Optional[Relation]): Relation to update.
167 If not specified, all relations will be updated.
170 Exception: if a non-leader unit calls this function.
172 if not self
.model
.unit
.is_leader():
173 raise Exception("only the leader set host information.")
176 self
._update
_relation
_data
(host
, port
, relation
)
179 for relation
in self
.model
.relations
[self
._endpoint
_name
]:
180 self
._update
_relation
_data
(host
, port
, relation
)
182 def _update_relation_data(self
, host
: str, port
: int, relation
: Relation
) -> None:
183 """Update data in relation if needed."""
184 relation
.data
[self
.model
.app
][NBI_HOST_APP_KEY
] = host
185 relation
.data
[self
.model
.app
][NBI_PORT_APP_KEY
] = str(port
)