| Index: appengine/monorail/services/client_config_svc.py
|
| diff --git a/appengine/monorail/services/client_config_svc.py b/appengine/monorail/services/client_config_svc.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..4a92cdcd0d398335274e29b873cfc6e063c4fbbe
|
| --- /dev/null
|
| +++ b/appengine/monorail/services/client_config_svc.py
|
| @@ -0,0 +1,134 @@
|
| +# Copyright 2016 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is govered by a BSD-style
|
| +# license that can be found in the LICENSE file or at
|
| +# https://developers.google.com/open-source/licenses/bsd
|
| +
|
| +import base64
|
| +import json
|
| +import logging
|
| +import os
|
| +import time
|
| +import urllib
|
| +
|
| +from google import protobuf
|
| +from google.appengine.api import app_identity
|
| +from google.appengine.api import urlfetch
|
| +
|
| +import settings
|
| +from framework import framework_constants
|
| +from proto import api_clients_config_pb2
|
| +
|
| +
|
| +CONFIG_FILE_PATH = os.path.join(
|
| + os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
|
| + 'testing', 'api_clients.cfg')
|
| +MONORAIL_CONFIG_SET = urllib.quote(
|
| + 'services/%s' % app_identity.get_application_id(), safe='')
|
| +LUCI_CONFIG_URL = (
|
| + 'https://luci-config.appspot.com/_ah/api/config/v1/config_sets'
|
| + '/%s/config/api_clients.cfg') % MONORAIL_CONFIG_SET
|
| +
|
| +
|
| +client_config_svc = None
|
| +service_account_map = None
|
| +
|
| +
|
| +class ClientConfigService(object):
|
| + """The persistence layer for client config data."""
|
| +
|
| + # One hour
|
| + EXPIRES_IN = 3600
|
| +
|
| + def __init__(self):
|
| + self.client_configs = None
|
| + self.load_time = 0
|
| +
|
| + def GetConfigs(self, use_cache=True, cur_time=None):
|
| + """Read client configs."""
|
| +
|
| + cur_time = cur_time or int(time.time())
|
| + force_load = False
|
| + if not self.client_configs:
|
| + force_load = True
|
| + elif not use_cache:
|
| + force_load = True
|
| + elif cur_time - self.load_time > self.EXPIRES_IN:
|
| + force_load = True
|
| +
|
| + if force_load:
|
| + if settings.dev_mode or settings.unit_test_mode:
|
| + self._ReadFromLocal()
|
| + else:
|
| + self._ReadFromLuciConfig()
|
| +
|
| + return self.client_configs
|
| +
|
| + def _ReadFromLocal(self):
|
| + try:
|
| + with open(CONFIG_FILE_PATH, 'r') as f:
|
| + content_text = f.read()
|
| + logging.info('Read client configs from local file.')
|
| + cfg = api_clients_config_pb2.ClientCfg()
|
| + protobuf.text_format.Merge(content_text, cfg)
|
| + self.client_configs = cfg
|
| + self.load_time = int(time.time())
|
| + except Exception as ex:
|
| + logging.exception(
|
| + 'Failed to read client configs: %s',
|
| + str(ex))
|
| +
|
| + def _ReadFromLuciConfig(self):
|
| + try:
|
| + authorization_token, _ = app_identity.get_access_token(
|
| + framework_constants.OAUTH_SCOPE)
|
| + response = urlfetch.fetch(
|
| + LUCI_CONFIG_URL,
|
| + method=urlfetch.GET,
|
| + follow_redirects=False,
|
| + headers={'Content-Type': 'application/json; charset=UTF-8',
|
| + 'Authorization': 'Bearer ' + authorization_token})
|
| + if response.status_code == 200:
|
| + content = json.loads(response.content)
|
| + config_content = content['content']
|
| + content_text = base64.b64decode(config_content)
|
| + logging.info('luci-config content decoded: %r.', content_text)
|
| + cfg = api_clients_config_pb2.ClientCfg()
|
| + protobuf.text_format.Merge(content_text, cfg)
|
| + self.client_configs = cfg
|
| + self.load_time = int(time.time())
|
| + else:
|
| + logging.error('Invalid response from luci-config: %r', response)
|
| + except Exception as ex:
|
| + logging.exception(
|
| + 'Failed to retrieve client configs from luci-config: %s',
|
| + str(ex))
|
| +
|
| + def GetClientIDEmails(self):
|
| + """Get client IDs and Emails."""
|
| + self.GetConfigs(use_cache=True)
|
| + client_ids = [c.client_id for c in self.client_configs.clients]
|
| + client_emails = [c.client_email for c in self.client_configs.clients]
|
| + return client_ids, client_emails
|
| +
|
| + def GetDisplayNames(self):
|
| + """Get client display names."""
|
| + self.GetConfigs(use_cache=True)
|
| + names_dict = {}
|
| + for client in self.client_configs.clients:
|
| + if client.display_name:
|
| + names_dict[client.client_email] = client.display_name
|
| + return names_dict
|
| +
|
| +
|
| +def GetClientConfigSvc():
|
| + global client_config_svc
|
| + if client_config_svc is None:
|
| + client_config_svc = ClientConfigService()
|
| + return client_config_svc
|
| +
|
| +def GetServiceAccountMap():
|
| + global service_account_map
|
| + if service_account_map is None:
|
| + service_account_map = GetClientConfigSvc().GetDisplayNames()
|
| + return service_account_map
|
| +
|
|
|