Merge ~mthaddon/charm-k8s-ingress/+git/charm-k8s-ingress:configmap into charm-k8s-ingress:master

Proposed by Tom Haddon
Status: Merged
Approved by: Jon Seager
Approved revision: 52fe1d914f6c52023e8f2d5e501e919a5428ea9c
Merged at revision: 0f23f2610e89e9fab3786e832919bc5433410b50
Proposed branch: ~mthaddon/charm-k8s-ingress/+git/charm-k8s-ingress:configmap
Merge into: charm-k8s-ingress:master
Diff against target: 166 lines (+64/-5)
4 files modified
config.yaml (+9/-0)
lib/charms/ingress/v0/ingress.py (+5/-1)
src/charm.py (+27/-2)
tests/unit/test_charm.py (+23/-2)
Reviewer Review Type Date Requested Status
🤖 prod-jenkaas-is (community) continuous-integration Approve
ingress-charmers Pending
Review via email: mp+400899@code.launchpad.net

Commit message

Add the retry-errors option

Description of the change

Add the retry-errors option.

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
🤖 prod-jenkaas-is (prod-jenkaas-is) wrote :

A CI job is currently in progress. A follow up comment will be added when it completes.

Revision history for this message
🤖 prod-jenkaas-is (prod-jenkaas-is) wrote :

PASSED: Continuous integration, rev:52fe1d914f6c52023e8f2d5e501e919a5428ea9c
https://jenkins.canonical.com/is/job/lp-charm-k8s-ingress-ci/33/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/is/job/lp-charm-test/70/
    None: https://jenkins.canonical.com/is/job/lp-update-mp/81314/

Click here to trigger a rebuild:
https://jenkins.canonical.com/is/job/lp-charm-k8s-ingress-ci/33//rebuild

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

Change successfully merged at revision 0f23f2610e89e9fab3786e832919bc5433410b50

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 c7b2377..9a9b7cf 100644
3--- a/config.yaml
4+++ b/config.yaml
5@@ -9,6 +9,15 @@ options:
6 default: 0
7 description: Max allowed body-size (for file uploads) in megabytes, set to 0 to disable limits.
8 type: int
9+ retry-errors:
10+ default: ""
11+ description: >
12+ Specifies in which cases a request should be retried against the next server.
13+ Comma-separated list, e.g. "error,timeout,http_502,http_503,http_504".
14+ See http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream
15+ for more details. Unrecognised values will be ignored. The nginx default
16+ will be used if this config option is set to an empty value.
17+ type: string
18 service-hostname:
19 default: ""
20 description: The hostname of the service to create an ingress for.
21diff --git a/lib/charms/ingress/v0/ingress.py b/lib/charms/ingress/v0/ingress.py
22index 2412e06..acef2c0 100644
23--- a/lib/charms/ingress/v0/ingress.py
24+++ b/lib/charms/ingress/v0/ingress.py
25@@ -12,10 +12,13 @@ Import `IngressRequires` in your charm, with two required options:
26 - service-name (required)
27 - service-port (required)
28 - max_body-size
29+ - retry-errors
30 - service-namespace
31 - session-cookie-max-age
32 - tls-secret-name
33
34+See `config.yaml` for descriptions of each, along with the required type.
35+
36 As an example:
37 ```
38 from charms.ingress.v0.ingress import IngressRequires
39@@ -44,7 +47,7 @@ LIBAPI = 0
40
41 # Increment this PATCH version before using `charmcraft push-lib` or reset
42 # to 0 if you are raising the major API version
43-LIBPATCH = 7
44+LIBPATCH = 8
45
46 logger = logging.getLogger(__name__)
47
48@@ -56,6 +59,7 @@ REQUIRED_INGRESS_RELATION_FIELDS = {
49
50 OPTIONAL_INGRESS_RELATION_FIELDS = {
51 "max-body-size",
52+ "retry-errors",
53 "service-namespace",
54 "session-cookie-max-age",
55 "tls-secret-name",
56diff --git a/src/charm.py b/src/charm.py
57index 17ee96d..e14f76a 100755
58--- a/src/charm.py
59+++ b/src/charm.py
60@@ -97,6 +97,29 @@ class IngressCharm(CharmBase):
61 return self._get_config_or_relation_data("service-namespace", self.model.name)
62
63 @property
64+ def _retry_errors(self):
65+ """Return the retry-errors setting from config or relation."""
66+ retry = self._get_config_or_relation_data("retry-errors", "")
67+ if not retry:
68+ return ""
69+ # See http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream.
70+ accepted_values = [
71+ "error",
72+ "timeout",
73+ "invalid_header",
74+ "http_500",
75+ "http_502",
76+ "http_503",
77+ "http_504",
78+ "http_403",
79+ "http_404",
80+ "http_429",
81+ "non_idempotent",
82+ "off",
83+ ]
84+ return " ".join([x.strip() for x in retry.split(",") if x.strip() in accepted_values])
85+
86+ @property
87 def _service_hostname(self):
88 """Return the hostname for the service we're connecting to."""
89 return self._get_config_or_relation_data("service-hostname", "")
90@@ -185,6 +208,8 @@ class IngressCharm(CharmBase):
91 }
92 if self._max_body_size:
93 annotations["nginx.ingress.kubernetes.io/proxy-body-size"] = self._max_body_size
94+ if self._retry_errors:
95+ annotations["nginx.ingress.kubernetes.io/proxy-next-upstream"] = self._retry_errors
96 if self._session_cookie_max_age:
97 annotations["nginx.ingress.kubernetes.io/affinity"] = "cookie"
98 annotations["nginx.ingress.kubernetes.io/affinity-mode"] = "balanced"
99@@ -262,7 +287,7 @@ class IngressCharm(CharmBase):
100 logger.info(
101 "Ingress updated in namespace %s with name %s",
102 self._namespace,
103- self._service_name,
104+ self._ingress_name,
105 )
106 else:
107 api.create_namespaced_ingress(
108@@ -272,7 +297,7 @@ class IngressCharm(CharmBase):
109 logger.info(
110 "Ingress created in namespace %s with name %s",
111 self._namespace,
112- self._service_name,
113+ self._ingress_name,
114 )
115
116 def _on_config_changed(self, _):
117diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py
118index 4075546..ac2f0c5 100644
119--- a/tests/unit/test_charm.py
120+++ b/tests/unit/test_charm.py
121@@ -132,6 +132,19 @@ class TestCharm(unittest.TestCase):
122 self.harness.update_relation_data(relation_id, 'gunicorn', relations_data)
123 self.assertEqual(self.harness.charm._namespace, "relationnamespace")
124
125+ def test_retry_errors(self):
126+ """Test the retry-errors property."""
127+ # Test empty value.
128+ self.assertEqual(self.harness.charm._retry_errors, "")
129+ # Test we deal with spaces or not spaces properly.
130+ self.harness.update_config({"retry-errors": "error, timeout, http_502, http_503"})
131+ self.assertEqual(self.harness.charm._retry_errors, "error timeout http_502 http_503")
132+ self.harness.update_config({"retry-errors": "error,timeout,http_502,http_503"})
133+ self.assertEqual(self.harness.charm._retry_errors, "error timeout http_502 http_503")
134+ # Test unknown value.
135+ self.harness.update_config({"retry-errors": "error,timeout,http_502,http_418"})
136+ self.assertEqual(self.harness.charm._retry_errors, "error timeout http_502")
137+
138 def test_service_port(self):
139 """Test the service-port property."""
140 # First set via config.
141@@ -323,8 +336,15 @@ class TestCharm(unittest.TestCase):
142 )
143 self.harness.update_config({"tls-secret-name": "gunicorn_tls"})
144 self.assertEqual(self.harness.charm._get_k8s_ingress(), expected)
145- # Test max_body_size and session-cookie-max-age config options.
146- self.harness.update_config({"tls-secret-name": "", "max-body-size": 20, "session-cookie-max-age": 3600})
147+ # Test max_body_size, retry_http_errors and session-cookie-max-age config options.
148+ self.harness.update_config(
149+ {
150+ "max-body-size": 20,
151+ "retry-errors": "error,timeout,http_502,http_503",
152+ "session-cookie-max-age": 3600,
153+ "tls-secret-name": "",
154+ }
155+ )
156 expected = kubernetes.client.NetworkingV1beta1Ingress(
157 api_version="networking.k8s.io/v1beta1",
158 kind="Ingress",
159@@ -334,6 +354,7 @@ class TestCharm(unittest.TestCase):
160 "nginx.ingress.kubernetes.io/affinity": "cookie",
161 "nginx.ingress.kubernetes.io/affinity-mode": "balanced",
162 "nginx.ingress.kubernetes.io/proxy-body-size": "20m",
163+ "nginx.ingress.kubernetes.io/proxy-next-upstream": "error timeout http_502 http_503",
164 "nginx.ingress.kubernetes.io/rewrite-target": "/",
165 "nginx.ingress.kubernetes.io/session-cookie-change-on-failure": "true",
166 "nginx.ingress.kubernetes.io/session-cookie-max-age": "3600",

Subscribers

People subscribed via source and target branches

to all changes: