Skip to content
This repository was archived by the owner on May 15, 2023. It is now read-only.

Commit 4b0be33

Browse files
committed
More gracefully handle errors loading service config
If we can't load service config, we'll loudly log it and then replace the application with one which responds to all requests with HTTP 503 Service Unavailable. Equivalent of cloudendpoints/endpoints-management-java#39
1 parent ed7a875 commit 4b0be33

File tree

8 files changed

+28
-11
lines changed

8 files changed

+28
-11
lines changed

endpoints_management/config/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,7 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
15+
from __future__ import absolute_import
16+
17+
from .service_config import ServiceConfigException

endpoints_management/config/service_config.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939
_SERVICE_VERSION_ENV_KEY = u"ENDPOINTS_SERVICE_VERSION"
4040

4141

42+
class ServiceConfigException(Exception):
43+
pass
44+
45+
4246
def fetch_service_config(service_name=None, service_version=None):
4347
"""Fetches the service config from Google Serivce Management API.
4448
@@ -76,7 +80,7 @@ def fetch_service_config(service_name=None, service_version=None):
7680
status_code = response.status
7781
if status_code != 200:
7882
message_template = u"Fetching service config failed (status code {})"
79-
_log_and_raise(Exception, message_template.format(status_code))
83+
_log_and_raise(ServiceConfigException, message_template.format(status_code))
8084

8185
logger.debug(u'obtained service json from the management api:\n%s', response.data)
8286
service = encoding.JsonToMessage(messages.Service, response.data)

endpoints_management/control/service.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@
3737
from apitools.base.py import encoding
3838
from enum import Enum
3939

40+
from ..config import service_config
4041
from . import label_descriptor, metric_descriptor, path_regex, sm_messages
41-
from endpoints_management.config import service_config
4242

4343

4444
logger = logging.getLogger(__name__)

endpoints_management/control/wsgi.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@
3333
import urllib2
3434
import urlparse
3535
import wsgiref.util
36+
from webob.exc import HTTPServiceUnavailable
3637

3738
from ..auth import suppliers, tokens
39+
from ..config.service_config import ServiceConfigException
3840
from . import check_request, quota_request, report_request, service, sm_messages
3941

4042

@@ -118,9 +120,14 @@ def add_all(application, project_id, control_client,
118120
loader (:class:`endpoints_management.control.service.Loader`): loads the service
119121
instance that configures this instance's behaviour
120122
"""
121-
a_service = loader.load()
122-
if not a_service:
123-
raise ValueError(u"Failed to load service config")
123+
try:
124+
a_service = loader.load()
125+
if not a_service:
126+
raise ValueError(u'No service config loaded.')
127+
except (ServiceConfigException, ValueError):
128+
logger.exception(u'Failed to load service config, installing server error handler.')
129+
# This will answer all requests with HTTP 503 Service Unavailable
130+
return HTTPServiceUnavailable
124131
authenticator = _create_authenticator(a_service)
125132

126133
wrapped_app = Middleware(application, project_id, control_client)

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ pyjwkest>=1.0.0,<=1.0.9
88
requests>=2.10.0,<3.0
99
strict-rfc3339>=0.7,<0.8
1010
urllib3>=1.16,<2.0
11+
webob>=1.7.4

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"requests>=2.10.0,<3.0",
4141
'strict-rfc3339>=0.7,<0.8',
4242
'urllib3>=1.16,<2.0',
43+
'webob>=1.7.4',
4344
]
4445

4546
tests_require = [

test/test_service_config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ def test_fetch_service_config_failed(self):
8888
mock_http_client = mock.MagicMock()
8989
mock_http_client.request.return_value = mock_response
9090
ServiceConfigFetchTest._get_http_client.return_value = mock_http_client
91-
with self.assertRaisesRegexp(Exception, u"status code 403"):
91+
with self.assertRaisesRegexp(service_config.ServiceConfigException, u"status code 403"):
9292
service_config.fetch_service_config()
9393

9494
@mock.patch(u"endpoints_management.config.service_config.client.GoogleCredentials",

test/test_wsgi.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,11 @@ def test_should_send_report_request_if_check_fails(self):
134134

135135
def test_load_service_failed(self):
136136
loader = mock.MagicMock(load=lambda: None)
137-
with self.assertRaisesRegex(ValueError, u"Failed to load service config"):
138-
wsgi.add_all(_DummyWsgiApp(),
139-
self.PROJECT_ID,
140-
mock.MagicMock(spec=client.Client),
141-
loader=loader)
137+
result = wsgi.add_all(_DummyWsgiApp(),
138+
self.PROJECT_ID,
139+
mock.MagicMock(spec=client.Client),
140+
loader=loader)
141+
assert result is wsgi.HTTPServiceUnavailable
142142

143143

144144
_SYSTEM_PARAMETER_CONFIG_TEST = b"""

0 commit comments

Comments
 (0)