blob: 3072e5418c29a13f8760db634b848e2cfd7eaf9c [file] [log] [blame]
# Copyright 2015 The LUCI Authors. All rights reserved.
# Use of this source code is governed under the Apache License, Version 2.0
# that can be found in the LICENSE file.
"""Administration API accessible only by service admins.
Defined as Endpoints API mostly to abuse API Explorer UI and not to write our
own admin UI. Note that all methods are publicly visible (though the source code
itself is also publicly visible, so not a big deal).
Callers have to be in 'administrators' group.
"""
import logging
from google.appengine.ext import ndb
from google.appengine.ext.ndb import msgprop
from protorpc import message_types
from protorpc import messages
from protorpc import remote
from components import auth
from components.datastore_utils import config
import acl
# This is used by endpoints indirectly.
package = 'luci-config'
class ServiceConfigStorageType(messages.Enum):
"""Type of repository where service configs are stored."""
GITILES = 0
class GlobalConfig(config.GlobalConfig):
"""Server-wide static configuration stored in datastore.
Typically it is set once during service setup and is never changed.
"""
# Type of repository where service configs are stored.
services_config_storage_type = msgprop.EnumProperty(ServiceConfigStorageType)
# If config storage type is Gitiles, URL to the root of service configs
# directory.
services_config_location = ndb.StringProperty()
class GlobalConfigMessage(messages.Message):
"""GlobalConfig as a RPC message."""
services_config_storage_type = messages.EnumField(ServiceConfigStorageType, 1)
services_config_location = messages.StringField(2)
@auth.endpoints_api(name='admin', version='v1', title='Administration API')
class AdminApi(remote.Service):
"""Administration API accessible only by the service admins."""
@auth.endpoints_method(
message_types.VoidMessage, GlobalConfigMessage, name='readGlobalConfig')
@auth.require(lambda: auth.is_superuser() or acl.is_admin())
def read_global_config(self, request):
"""Reads global configuration."""
conf = GlobalConfig.fetch()
if not conf:
conf = GlobalConfig()
return GlobalConfigMessage(
services_config_location=conf.services_config_location,
services_config_storage_type=conf.services_config_storage_type)
@auth.endpoints_method(
GlobalConfigMessage, GlobalConfigMessage, name='writeGlobalConfig')
@auth.require(lambda: auth.is_superuser() or acl.is_admin())
def write_global_config(self, request):
"""Writes global configuration."""
conf = GlobalConfig.fetch()
if not conf:
conf = GlobalConfig()
changed = conf.modify(
updated_by=auth.get_current_identity().to_bytes(),
services_config_storage_type=request.services_config_storage_type,
services_config_location=request.services_config_location)
if changed:
logging.warning('Updated global configuration')
return GlobalConfigMessage(
services_config_location=conf.services_config_location,
services_config_storage_type=conf.services_config_storage_type)