Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1583)

Unified Diff: appengine/components/components/config/endpoint.py

Issue 1221643020: config services: services.cfg and validation (Closed) Base URL: git@github.com:luci/luci-py.git@master
Patch Set: nits Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: appengine/components/components/config/endpoint.py
diff --git a/appengine/components/components/config/endpoint.py b/appengine/components/components/config/endpoint.py
index e7c9e4ebd31b0cb7f941c0b8c8716993b10c5df8..06ac5f3489a15c40aae027fd21ee1d8b64a80c2d 100644
--- a/appengine/components/components/config/endpoint.py
+++ b/appengine/components/components/config/endpoint.py
@@ -5,7 +5,8 @@
"""Cloud Endpoints API for configs.
* Reads/writes config service location.
-* Validates configs. TODO(nodir): implement.
+* Validates configs.
+* Provides service metadata.
"""
import logging
@@ -18,6 +19,11 @@ from protorpc import remote
from . import common
from . import validation
+METADATA_FORMAT_VERSION = "1.0"
+
+def get_default_rule_set():
+ return validation.DEFAULT_RULE_SET
+
class ConfigSettingsMessage(messages.Message):
"""Configuration service location."""
@@ -46,6 +52,50 @@ class ValidateResponseMessage(messages.Message):
messages = messages.MessageField(ValidationMessage, 1, repeated=True)
+def is_trusted_requester():
Vadim Sh. 2015/07/08 03:05:58 I propose to reduce magicallity and store trusted_
nodir 2015/07/08 15:24:47 Done.
+ """Returns True if the requester can see the service metadata.
+
+ Used in metadata endpoint.
+
+ Returns:
+ True if the current identity is an admin or the config service.
+ """
+ if auth.is_admin():
+ return True
+
+ identity = auth.get_current_identity()
+ if identity.is_user:
+ settings = common.ConfigSettings.cached()
+ if settings and settings.service_hostname:
+ parts = settings.service_hostname.split('.')
+ trusted_domains = ('appspot', 'googleplex')
+ # Does not work for tainted versions.
+ if len(parts) > 2 and parts[-1] == 'com' and parts[-2] in trusted_domains:
+ trusted_config_account = (
+ '%s@%s.gserviceaccount.com' % (parts[-3], parts[-2]))
+ if identity.name == trusted_config_account:
+ return True
+
+ return False
+
+
+class ConfigPattern(messages.Message):
+ """A pattern for one config file. See MetadataResponseMessage."""
+ config_set = messages.StringField(1, required=True)
+ path = messages.StringField(2, required=True)
+
+
+class MetadataResponseMessage(messages.Message):
+ """Compatible with config service's ServiceDynamicMetadata messsage."""
Vadim Sh. 2015/07/08 03:05:58 Describe exactly what you mean by "compatible", e.
nodir 2015/07/08 15:24:47 Done.
+
+ class Validator(messages.Message):
+ patterns = messages.MessageField(ConfigPattern, 1, repeated=True)
+ url = messages.StringField(2, required=True)
+
+ version = messages.StringField(1, required=True)
Vadim Sh. 2015/07/08 03:05:58 Is it needed? Proto-flavored formats are supposed
nodir 2015/07/08 15:24:47 config services talks to different services that m
+ validation = messages.MessageField(Validator, 2)
+
+
@auth.endpoints_api(name='config', version='v1', title='Configuration service')
class ConfigApi(remote.Service):
"""Configuration service."""
@@ -85,3 +135,24 @@ class ConfigApi(remote.Service):
text=m.text,
))
return res
+
+ @auth.endpoints_method(
+ message_types.VoidMessage, MetadataResponseMessage, path='metadata')
+ @auth.require(is_trusted_requester)
+ def get_metadata(self, _request):
+ """Describes a service. Used by config service to discover other services.
+ """
+ meta = MetadataResponseMessage(version=METADATA_FORMAT_VERSION)
+ http_headers = dict(self.request_state.headers)
+ assert 'host' in http_headers, http_headers
+ meta.validation = meta.Validator(
+ url='https://{hostname}/_ah/api/{name}/{version}/{path}validate'.format(
+ hostname=http_headers['host'],
+ name=self.api_info.name,
+ version=self.api_info.version,
+ path=self.api_info.path or '',
+ )
+ )
+ for p in sorted(get_default_rule_set().patterns()):
+ meta.validation.patterns.append(ConfigPattern(**p._asdict()))
+ return meta

Powered by Google App Engine
This is Rietveld 408576698