Merge ~twom/charm-k8s-ingress:allow-disabling-rewrite into charm-k8s-ingress:master

Proposed by Tom Wardill
Status: Merged
Approved by: Jon Seager
Approved revision: 2d86f0294516e38f3d09d8e6620963f141dc63a5
Merged at revision: 1562894c58139f79caa7b83b606496e77058bc94
Proposed branch: ~twom/charm-k8s-ingress:allow-disabling-rewrite
Merge into: charm-k8s-ingress:master
Diff against target: 157 lines (+82/-3)
4 files modified
config.yaml (+8/-0)
lib/charms/nginx_ingress_integrator/v0/ingress.py (+4/-0)
src/charm.py (+21/-3)
tests/unit/test_charm.py (+49/-0)
Reviewer Review Type Date Requested Status
ingress-charmers Pending
Review via email: mp+403274@code.launchpad.net

Commit message

Allow disabling and setting the rewrite target

Description of the change

Add a setting for disabling the rewrite annotation, and another to allow the target to be overridden.

Default to 'on' and '/'.

Some complications around handling the boolean value which there might be a better way of doing, but I'm not sure about the data types we can guarantee.

To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

This merge proposal is being monitored by mergebot. Change the status to Approved to merge.

Revision history for this message
Tom Wardill (twom) wrote :

I'm unsure why black has decided it wants to suddenly change a bunch of the line wrapping in this, I can unpick it if it's preferred.

Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Change successfully merged at revision 1562894c58139f79caa7b83b606496e77058bc94

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/config.yaml b/config.yaml
2index 087d353..f94797d 100644
3--- a/config.yaml
4+++ b/config.yaml
5@@ -57,6 +57,14 @@ options:
6 for more details. Unrecognised values will be ignored. The nginx default
7 will be used if this config option is set to an empty value.
8 type: string
9+ rewrite-enabled:
10+ default: ""
11+ description: Whether requests should be written to the `rewrite-target`
12+ type: boolean
13+ rewrite-target:
14+ default: "/"
15+ description: The path to rewrite requests to.
16+ type: string
17 service-hostname:
18 default: ""
19 description: The hostname of the service to create an ingress for.
20diff --git a/lib/charms/nginx_ingress_integrator/v0/ingress.py b/lib/charms/nginx_ingress_integrator/v0/ingress.py
21index 780458e..6eb60ba 100644
22--- a/lib/charms/nginx_ingress_integrator/v0/ingress.py
23+++ b/lib/charms/nginx_ingress_integrator/v0/ingress.py
24@@ -16,6 +16,8 @@ Import `IngressRequires` in your charm, with two required options:
25 - max-body-size
26 - path-routes
27 - retry-errors
28+ - rewrite-enabled
29+ - rewrite-target
30 - service-namespace
31 - session-cookie-max-age
32 - tls-secret-name
33@@ -77,6 +79,8 @@ OPTIONAL_INGRESS_RELATION_FIELDS = {
34 "limit-whitelist",
35 "max-body-size",
36 "retry-errors",
37+ "rewrite-target",
38+ "rewrite-enabled",
39 "service-namespace",
40 "session-cookie-max-age",
41 "tls-secret-name",
42diff --git a/src/charm.py b/src/charm.py
43index 4d0d235..5882e04 100755
44--- a/src/charm.py
45+++ b/src/charm.py
46@@ -19,6 +19,8 @@ from ops.model import ActiveStatus, BlockedStatus
47
48 logger = logging.getLogger(__name__)
49
50+BOOLEAN_CONFIG_FIELDS = ["rewrite-enabled"]
51+
52
53 def _core_v1_api():
54 """Use the v1 k8s API."""
55@@ -69,6 +71,9 @@ class NginxIngressCharm(CharmBase):
56 def _get_config_or_relation_data(self, field, fallback):
57 """Helper method to get data from config or the ingress relation."""
58 config_data = self.config[field]
59+ # A value of False is valid in these fields, so check it's not a null-value instead
60+ if field in BOOLEAN_CONFIG_FIELDS and (config_data is not None and config_data != ""):
61+ return config_data
62 if config_data:
63 return config_data
64 relation = self.model.get_relation("ingress")
65@@ -118,6 +123,19 @@ class NginxIngressCharm(CharmBase):
66 return ""
67
68 @property
69+ def _rewrite_enabled(self):
70+ """Return whether rewriting should be enabled from config or relation"""
71+ value = self._get_config_or_relation_data("rewrite-enabled", True)
72+ # config data is typed, relation data is a string
73+ # Convert to string, then compare to a known value.
74+ return str(value).lower() == "true"
75+
76+ @property
77+ def _rewrite_target(self):
78+ """Return the rewrite target from config or relation."""
79+ return self._get_config_or_relation_data("rewrite-target", "/")
80+
81+ @property
82 def _namespace(self):
83 """Return the namespace to operate on."""
84 return self._get_config_or_relation_data("service-namespace", self.model.name)
85@@ -228,9 +246,9 @@ class NginxIngressCharm(CharmBase):
86 )
87 ]
88 )
89- annotations = {
90- "nginx.ingress.kubernetes.io/rewrite-target": "/",
91- }
92+ annotations = {}
93+ if self._rewrite_enabled:
94+ annotations["nginx.ingress.kubernetes.io/rewrite-target"] = self._rewrite_target
95 if self._limit_rps:
96 annotations["nginx.ingress.kubernetes.io/limit-rps"] = self._limit_rps
97 if self._limit_whitelist:
98diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py
99index ecc9ea1..193bc7b 100644
100--- a/tests/unit/test_charm.py
101+++ b/tests/unit/test_charm.py
102@@ -279,6 +279,55 @@ class TestCharm(unittest.TestCase):
103 # Now it's the value from the relation.
104 self.assertEqual(self.harness.charm._tls_secret_name, "gunicorn-tls-new")
105
106+ def test_rewrite_enabled_property(self):
107+ """Test for enabling request rewrites."""
108+ # First set via config.
109+ self.harness.update_config({"rewrite-enabled": True})
110+ self.assertEqual(self.harness.charm._rewrite_enabled, True)
111+ relation_id = self.harness.add_relation("ingress", "gunicorn")
112+ self.harness.add_relation_unit(relation_id, "gunicorn/0")
113+ relations_data = {
114+ "rewrite-enabled": "False",
115+ "service-name": "gunicorn",
116+ "service-hostname": "foo.internal",
117+ }
118+ self.harness.update_relation_data(relation_id, "gunicorn", relations_data)
119+ # Still /test-target because it's set via config.
120+ self.assertEqual(self.harness.charm._rewrite_enabled, True)
121+ self.harness.update_config({"rewrite-enabled": ""})
122+ self.assertEqual(self.harness.charm._rewrite_enabled, False)
123+
124+ def test_rewrite_annotations(self):
125+ self.harness.disable_hooks()
126+ self.harness.update_config(
127+ {
128+ "service-hostname": "foo.internal",
129+ "service-name": "gunicorn",
130+ "service-port": 80,
131+ }
132+ )
133+ result_dict = self.harness.charm._get_k8s_ingress().to_dict()
134+ expected = {
135+ "nginx.ingress.kubernetes.io/rewrite-target": "/",
136+ "nginx.ingress.kubernetes.io/ssl-redirect": "false",
137+ }
138+ self.assertEqual(result_dict["metadata"]["annotations"], expected)
139+
140+ self.harness.update_config({"rewrite-enabled": False})
141+ result_dict = self.harness.charm._get_k8s_ingress().to_dict()
142+ expected = {"nginx.ingress.kubernetes.io/ssl-redirect": "false"}
143+ self.assertEqual(result_dict["metadata"]["annotations"], expected)
144+
145+ self.harness.update_config({"rewrite-target": "/test-target"})
146+ self.harness.update_config({"rewrite-enabled": True})
147+
148+ expected = {
149+ "nginx.ingress.kubernetes.io/rewrite-target": "/test-target",
150+ "nginx.ingress.kubernetes.io/ssl-redirect": "false",
151+ }
152+ result_dict = self.harness.charm._get_k8s_ingress().to_dict()
153+ self.assertEqual(result_dict["metadata"]["annotations"], expected)
154+
155 @patch('charm.NginxIngressCharm._on_config_changed')
156 def test_on_ingress_relation_changed(self, _on_config_changed):
157 """Test ingress relation changed handler."""

Subscribers

People subscribed via source and target branches

to all changes: