blob: 8b585d7340937b63bf5a0999d37ffc40b300e3aa [file] [log] [blame]
# 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
"""Main program for Bugdroid."""
import endpoints
import json
import logging
import os
import cloudstorage as gcs
from endpoints import ResourceContainer
from google.appengine.api import app_identity
from protorpc import messages
from protorpc import message_types
from protorpc import remote
from components import endpoints_webapp2
ALLOWED_CLIENT_IDS = [
endpoints.API_EXPLORER_CLIENT_ID,
'768213250012.apps.googleusercontent.com']
ENTITY_KEY = 'bugdroid_data'
class BugdroidData(messages.Message):
"""Collection of repo data files."""
data_files = messages.StringField(1)
DATA_UPDATE_REQUEST_RESOURCE_CONTAINER = ResourceContainer(
BugdroidData,
)
class BugdroidDataFile(messages.Message):
"""Base64-encoded data file for one repo."""
file_content= messages.StringField(1)
DATAFILE_UPDATE_REQUEST_RESOURCE_CONTAINER = ResourceContainer(
BugdroidDataFile,
filename=messages.StringField(2, required=True)
)
DATAFILE_GET_REQUEST_RESOURCE_CONTAINER = ResourceContainer(
# The request body should be empty.
message_types.VoidMessage,
filename=messages.StringField(1, required=True)
)
@endpoints.api(name='bugdroid', version='v1',
description='bugdroid API to manage data configs.',
allowed_client_ids=ALLOWED_CLIENT_IDS)
class BugdroidApi(remote.Service): # pragma: no cover
@endpoints.method(
DATAFILE_GET_REQUEST_RESOURCE_CONTAINER,
BugdroidDataFile,
path='datafile/{filename}',
http_method='GET',
name='datafile.get')
def datafile_get(self, request):
bucket_name = app_identity.get_default_gcs_bucket_name()
object_path = '/' + bucket_name + '/' + request.filename
file_content = None
try:
with gcs.open(object_path) as f:
file_content = f.read().decode('utf-8')
except gcs.NotFoundError:
raise endpoints.NotFoundException()
if file_content:
return BugdroidDataFile(file_content=file_content)
else:
raise endpoints.NotFoundException()
@endpoints.method(
DATAFILE_UPDATE_REQUEST_RESOURCE_CONTAINER,
message_types.VoidMessage,
path='datafile/{filename}',
http_method='POST',
name='datafile.update')
def datafile_update(self, request):
bucket_name = app_identity.get_default_gcs_bucket_name()
object_path = '/' + bucket_name + '/' + request.filename
with gcs.open(object_path, 'w') as f:
f.write(request.file_content.encode('utf-8') )
return message_types.VoidMessage()
@endpoints.method(
message_types.VoidMessage,
BugdroidData,
path='data',
http_method='GET',
name='data.get')
def data_get(self, _):
bucket_name = app_identity.get_default_gcs_bucket_name()
object_path = '/' + bucket_name
filestats = gcs.listbucket(object_path)
if filestats:
data_files = []
for filestat in filestats:
# Ignore dirs (although there really shouldn't be any).
if filestat.is_dir:
continue
# Skip the old, consolidated data file (which should be deleted at some
# point).
if filestat.filename == '/'.join([object_path, ENTITY_KEY]):
continue
data_file = {'file_name': filestat.filename.split('/')[-1]}
with gcs.open(filestat.filename) as f:
data_file['file_content'] = f.read().decode('utf-8')
data_files.append(data_file)
if data_files:
return BugdroidData(data_files=json.dumps(data_files))
else:
raise endpoints.NotFoundException()
else:
raise endpoints.NotFoundException()
@endpoints.method(
DATA_UPDATE_REQUEST_RESOURCE_CONTAINER,
message_types.VoidMessage,
path='data',
http_method='POST',
name='data.update')
def data_update(self, _):
return endpoints.InternalServerErrorException(
'Bulk bugdroid data POST is obsolete due to excessive data size. '
'See also crbug.com/880103.')
endpoint_list = endpoints_webapp2.api_server([BugdroidApi])