1
1
# Copyright 2024 Canonical Ltd.
2
- # Licensed under the Apache2.0, see LICENCE file in charm source for details.
2
+ # Licensed under the Apache2.0. See LICENSE file in charm source for details.
3
3
"""Library for the nginx-route relation.
4
4
5
5
This library contains the require and provide functions for handling
13
13
14
14
Other optional arguments include:
15
15
- additional_hostnames
16
+ - backend_protocol
16
17
- limit_rps
17
18
- limit_whitelist
18
19
- max_body_size
33
34
```python
34
35
from charms.nginx_ingress_integrator.v0.nginx_route import NginxRouteRequirer
35
36
36
- # In your charm's `__init__` method.
37
+ # In your charm's `__init__` method (assuming your app is listening on port 8080) .
37
38
require_nginx_route(
38
39
charm=self,
39
- service_hostname=self.config["external_hostname"] ,
40
+ service_hostname=self.app.name ,
40
41
service_name=self.app.name,
41
- service_port=80
42
+ service_port=8080
42
43
)
43
44
44
45
```
51
52
You _must_ require nginx route as part of the `__init__` method
52
53
rather than, for instance, a config-changed event handler, for the relation
53
54
changed event to be properly handled.
55
+
56
+ In the example above we're setting `service_hostname` (which translates to the
57
+ external hostname for the application when related to nginx-ingress-integrator)
58
+ to `self.app.name` here. This ensures by default the charm will be available on
59
+ the name of the deployed juju application, but can be overridden in a
60
+ production deployment by setting `service-hostname` on the
61
+ nginx-ingress-integrator charm. For example:
62
+ ```bash
63
+ juju deploy nginx-ingress-integrator
64
+ juju deploy my-charm
65
+ juju relate nginx-ingress-integrator my-charm:nginx-route
66
+ # The service is now reachable on the ingress IP(s) of your k8s cluster at
67
+ # 'http://my-charm'.
68
+ juju config nginx-ingress-integrator service-hostname='my-charm.example.com'
69
+ # The service is now reachable on the ingress IP(s) of your k8s cluster at
70
+ # 'http://my-charm.example.com'.
71
+ ```
54
72
"""
55
73
import logging
56
74
import typing
61
79
import ops .model
62
80
63
81
# The unique Charmhub library identifier, never change it
64
- LIBID = "c13d5d639bcd09f8c4f5b195264ed53d "
82
+ LIBID = "3c212b6ed3cf43dfbf9f2e322e634beb "
65
83
66
84
# Increment this major API version when introducing breaking changes
67
85
LIBAPI = 0
68
86
69
87
# Increment this PATCH version before using `charmcraft publish-lib` or reset
70
88
# to 0 if you are raising the major API version
71
- LIBPATCH = 1
89
+ LIBPATCH = 7
72
90
73
91
__all__ = ["require_nginx_route" , "provide_nginx_route" ]
74
92
@@ -101,7 +119,7 @@ class _NginxRouteCharmEvents(ops.charm.CharmEvents):
101
119
nginx_route_broken = ops .framework .EventSource (_NginxRouteBrokenEvent )
102
120
103
121
104
- class _NginxRouteRequirer (ops .framework .Object ):
122
+ class NginxRouteRequirer (ops .framework .Object ):
105
123
"""This class defines the functionality for the 'requires' side of the 'nginx-route' relation.
106
124
107
125
Hook events observed:
@@ -130,7 +148,7 @@ def __init__(
130
148
self ._config_reconciliation ,
131
149
)
132
150
# Set default values.
133
- self ._config : typing .Dict [str , typing .Union [str , int , bool ]] = {
151
+ self .config : typing .Dict [str , typing .Union [str , int , bool ]] = {
134
152
"service-namespace" : self ._charm .model .name ,
135
153
** config ,
136
154
}
@@ -145,20 +163,25 @@ def _config_reconciliation(self, _event: typing.Any = None) -> None:
145
163
delete_keys = {
146
164
relation_field
147
165
for relation_field in relation_app_data
148
- if relation_field not in self ._config
166
+ if relation_field not in self .config
149
167
}
150
168
for delete_key in delete_keys :
151
169
del relation_app_data [delete_key ]
152
- relation_app_data .update ({k : str (v ) for k , v in self ._config .items ()})
170
+ relation_app_data .update ({k : str (v ) for k , v in self .config .items ()})
153
171
154
172
155
- def require_nginx_route ( # pylint: disable=too-many-locals,too-many-branches
173
+ # C901 is ignored since the method has too many ifs but wouldn't be
174
+ # necessarily good to reduce to smaller methods.
175
+ # E501: line too long
176
+ def require_nginx_route ( # pylint: disable=too-many-locals,too-many-branches,too-many-arguments # noqa: C901,E501
156
177
* ,
157
178
charm : ops .charm .CharmBase ,
158
179
service_hostname : str ,
159
180
service_name : str ,
160
181
service_port : int ,
161
182
additional_hostnames : typing .Optional [str ] = None ,
183
+ backend_protocol : typing .Optional [str ] = None ,
184
+ enable_access_log : typing .Optional [bool ] = None ,
162
185
limit_rps : typing .Optional [int ] = None ,
163
186
limit_whitelist : typing .Optional [str ] = None ,
164
187
max_body_size : typing .Optional [int ] = None ,
@@ -172,7 +195,7 @@ def require_nginx_route( # pylint: disable=too-many-locals,too-many-branches
172
195
session_cookie_max_age : typing .Optional [int ] = None ,
173
196
tls_secret_name : typing .Optional [str ] = None ,
174
197
nginx_route_relation_name : str = "nginx-route" ,
175
- ) -> None :
198
+ ) -> NginxRouteRequirer :
176
199
"""Set up nginx-route relation handlers on the requirer side.
177
200
178
201
This function must be invoked in the charm class constructor.
@@ -187,6 +210,10 @@ def require_nginx_route( # pylint: disable=too-many-locals,too-many-branches
187
210
option via relation.
188
211
additional_hostnames: configure Nginx ingress integrator
189
212
additional-hostnames option via relation, optional.
213
+ backend_protocol: configure Nginx ingress integrator
214
+ backend-protocol option via relation, optional.
215
+ enable_access_log: configure Nginx ingress
216
+ nginx.ingress.kubernetes.io/enable-access-log option.
190
217
limit_rps: configure Nginx ingress integrator limit-rps
191
218
option via relation, optional.
192
219
limit_whitelist: configure Nginx ingress integrator
@@ -215,6 +242,9 @@ def require_nginx_route( # pylint: disable=too-many-locals,too-many-branches
215
242
nginx_route_relation_name: Specifies the relation name of
216
243
the relation handled by this requirer class. The relation
217
244
must have the nginx-route interface.
245
+
246
+ Returns:
247
+ the NginxRouteRequirer.
218
248
"""
219
249
config : typing .Dict [str , typing .Union [str , int , bool ]] = {}
220
250
if service_hostname is not None :
@@ -225,6 +255,10 @@ def require_nginx_route( # pylint: disable=too-many-locals,too-many-branches
225
255
config ["service-port" ] = service_port
226
256
if additional_hostnames is not None :
227
257
config ["additional-hostnames" ] = additional_hostnames
258
+ if backend_protocol is not None :
259
+ config ["backend-protocol" ] = backend_protocol
260
+ if enable_access_log is not None :
261
+ config ["enable-access-log" ] = "true" if enable_access_log else "false"
228
262
if limit_rps is not None :
229
263
config ["limit-rps" ] = limit_rps
230
264
if limit_whitelist is not None :
@@ -250,7 +284,7 @@ def require_nginx_route( # pylint: disable=too-many-locals,too-many-branches
250
284
if tls_secret_name is not None :
251
285
config ["tls-secret-name" ] = tls_secret_name
252
286
253
- _NginxRouteRequirer (
287
+ return NginxRouteRequirer (
254
288
charm = charm , config = config , nginx_route_relation_name = nginx_route_relation_name
255
289
)
256
290
@@ -297,6 +331,9 @@ def _on_relation_changed(self, event: ops.charm.RelationChangedEvent) -> None:
297
331
298
332
Args:
299
333
event: Event triggering the relation-changed hook for the relation.
334
+
335
+ Raises:
336
+ RuntimeError: if _on_relation changed is triggered by a broken relation.
300
337
"""
301
338
# `self.unit` isn't available here, so use `self.model.unit`.
302
339
if not self ._charm .model .unit .is_leader ():
@@ -370,8 +407,13 @@ def provide_nginx_route(
370
407
on_nginx_route_broken: Callback function for the nginx-route-broken event.
371
408
nginx_route_relation_name: Specifies the relation name of the relation handled by this
372
409
provider class. The relation must have the nginx-route interface.
410
+
411
+ Raises:
412
+ RuntimeError: If provide_nginx_route was invoked twice with
413
+ the same nginx-route relation name
373
414
"""
374
- if __provider_references .get (charm , {}).get (nginx_route_relation_name ) is not None :
415
+ ref_dict : typing .Dict [str , typing .Any ] = __provider_references .get (charm , {})
416
+ if ref_dict .get (nginx_route_relation_name ) is not None :
375
417
raise RuntimeError (
376
418
"provide_nginx_route was invoked twice with the same nginx-route relation name"
377
419
)
0 commit comments