OLD | NEW |
(Empty) | |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is govered by a BSD-style |
| 3 # license that can be found in the LICENSE file or at |
| 4 # https://developers.google.com/open-source/licenses/bsd |
| 5 |
| 6 import base64 |
| 7 import json |
| 8 import logging |
| 9 import os |
| 10 import time |
| 11 import urllib |
| 12 |
| 13 from google import protobuf |
| 14 from google.appengine.api import app_identity |
| 15 from google.appengine.api import urlfetch |
| 16 |
| 17 import settings |
| 18 from framework import framework_constants |
| 19 from proto import api_clients_config_pb2 |
| 20 |
| 21 |
| 22 CONFIG_FILE_PATH = os.path.join( |
| 23 os.path.dirname(os.path.dirname(os.path.realpath(__file__))), |
| 24 'testing', 'api_clients.cfg') |
| 25 MONORAIL_CONFIG_SET = urllib.quote( |
| 26 'services/%s' % app_identity.get_application_id(), safe='') |
| 27 LUCI_CONFIG_URL = ( |
| 28 'https://luci-config.appspot.com/_ah/api/config/v1/config_sets' |
| 29 '/%s/config/api_clients.cfg') % MONORAIL_CONFIG_SET |
| 30 |
| 31 |
| 32 client_config_svc = None |
| 33 service_account_map = None |
| 34 |
| 35 |
| 36 class ClientConfigService(object): |
| 37 """The persistence layer for client config data.""" |
| 38 |
| 39 # One hour |
| 40 EXPIRES_IN = 3600 |
| 41 |
| 42 def __init__(self): |
| 43 self.client_configs = None |
| 44 self.load_time = 0 |
| 45 |
| 46 def GetConfigs(self, use_cache=True, cur_time=None): |
| 47 """Read client configs.""" |
| 48 |
| 49 cur_time = cur_time or int(time.time()) |
| 50 force_load = False |
| 51 if not self.client_configs: |
| 52 force_load = True |
| 53 elif not use_cache: |
| 54 force_load = True |
| 55 elif cur_time - self.load_time > self.EXPIRES_IN: |
| 56 force_load = True |
| 57 |
| 58 if force_load: |
| 59 if settings.dev_mode or settings.unit_test_mode: |
| 60 self._ReadFromLocal() |
| 61 else: |
| 62 self._ReadFromLuciConfig() |
| 63 |
| 64 return self.client_configs |
| 65 |
| 66 def _ReadFromLocal(self): |
| 67 try: |
| 68 with open(CONFIG_FILE_PATH, 'r') as f: |
| 69 content_text = f.read() |
| 70 logging.info('Read client configs from local file.') |
| 71 cfg = api_clients_config_pb2.ClientCfg() |
| 72 protobuf.text_format.Merge(content_text, cfg) |
| 73 self.client_configs = cfg |
| 74 self.load_time = int(time.time()) |
| 75 except Exception as ex: |
| 76 logging.exception( |
| 77 'Failed to read client configs: %s', |
| 78 str(ex)) |
| 79 |
| 80 def _ReadFromLuciConfig(self): |
| 81 try: |
| 82 authorization_token, _ = app_identity.get_access_token( |
| 83 framework_constants.OAUTH_SCOPE) |
| 84 response = urlfetch.fetch( |
| 85 LUCI_CONFIG_URL, |
| 86 method=urlfetch.GET, |
| 87 follow_redirects=False, |
| 88 headers={'Content-Type': 'application/json; charset=UTF-8', |
| 89 'Authorization': 'Bearer ' + authorization_token}) |
| 90 if response.status_code == 200: |
| 91 content = json.loads(response.content) |
| 92 config_content = content['content'] |
| 93 content_text = base64.b64decode(config_content) |
| 94 logging.info('luci-config content decoded: %r.', content_text) |
| 95 cfg = api_clients_config_pb2.ClientCfg() |
| 96 protobuf.text_format.Merge(content_text, cfg) |
| 97 self.client_configs = cfg |
| 98 self.load_time = int(time.time()) |
| 99 else: |
| 100 logging.error('Invalid response from luci-config: %r', response) |
| 101 except Exception as ex: |
| 102 logging.exception( |
| 103 'Failed to retrieve client configs from luci-config: %s', |
| 104 str(ex)) |
| 105 |
| 106 def GetClientIDEmails(self): |
| 107 """Get client IDs and Emails.""" |
| 108 self.GetConfigs(use_cache=True) |
| 109 client_ids = [c.client_id for c in self.client_configs.clients] |
| 110 client_emails = [c.client_email for c in self.client_configs.clients] |
| 111 return client_ids, client_emails |
| 112 |
| 113 def GetDisplayNames(self): |
| 114 """Get client display names.""" |
| 115 self.GetConfigs(use_cache=True) |
| 116 names_dict = {} |
| 117 for client in self.client_configs.clients: |
| 118 if client.display_name: |
| 119 names_dict[client.client_email] = client.display_name |
| 120 return names_dict |
| 121 |
| 122 |
| 123 def GetClientConfigSvc(): |
| 124 global client_config_svc |
| 125 if client_config_svc is None: |
| 126 client_config_svc = ClientConfigService() |
| 127 return client_config_svc |
| 128 |
| 129 def GetServiceAccountMap(): |
| 130 global service_account_map |
| 131 if service_account_map is None: |
| 132 service_account_map = GetClientConfigSvc().GetDisplayNames() |
| 133 return service_account_map |
| 134 |
OLD | NEW |