blob: c4f4fd9ea872b0b7335c5b1d7cbcf12a5d90f1a2 [file] [log] [blame]
Alex Klein146d4772019-06-20 13:48:25 -06001# Copyright 2019 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Alex Kleine0fa6422019-06-21 12:01:39 -06005"""Router class for the Build API.
6
7Handles routing requests to the appropriate controller and handles service
8registration.
9"""
Alex Klein146d4772019-06-20 13:48:25 -060010
Alex Klein92341cd2020-02-27 14:11:04 -070011import collections
Alex Klein146d4772019-06-20 13:48:25 -060012import importlib
Chris McDonald1672ddb2021-07-21 11:48:23 -060013import logging
Alex Klein146d4772019-06-20 13:48:25 -060014import os
Tomasz Tylendab4292302021-08-08 18:59:36 +090015from types import ModuleType
16from typing import Callable, List, TYPE_CHECKING
Alex Klein146d4772019-06-20 13:48:25 -060017
Mike Frysinger2c024062021-05-22 15:43:22 -040018from chromite.third_party.google.protobuf import symbol_database
Alex Klein146d4772019-06-20 13:48:25 -060019
20from chromite.api import controller
21from chromite.api import field_handler
Alex Klein4de25e82019-08-05 15:58:39 -060022from chromite.api.gen.chromite.api import android_pb2
Alex Klein54e38e32019-06-21 14:54:17 -060023from chromite.api.gen.chromite.api import api_pb2
Alex Klein146d4772019-06-20 13:48:25 -060024from chromite.api.gen.chromite.api import artifacts_pb2
25from chromite.api.gen.chromite.api import binhost_pb2
26from chromite.api.gen.chromite.api import build_api_pb2
27from chromite.api.gen.chromite.api import depgraph_pb2
Jett Rink17ed0f52020-09-25 17:14:31 -060028from chromite.api.gen.chromite.api import firmware_pb2
Alex Klein146d4772019-06-20 13:48:25 -060029from chromite.api.gen.chromite.api import image_pb2
Alex Kleind4d9caa2021-11-10 15:44:52 -070030from chromite.api.gen.chromite.api import metadata_pb2
Alex Kleineb77ffa2019-05-28 14:47:44 -060031from chromite.api.gen.chromite.api import packages_pb2
George Engelbrechtfe63c8c2019-08-31 22:51:29 -060032from chromite.api.gen.chromite.api import payload_pb2
Alexander Liu008389c2022-06-27 18:30:11 +000033from chromite.api.gen.chromite.api import portage_explorer_pb2
Alex Klein146d4772019-06-20 13:48:25 -060034from chromite.api.gen.chromite.api import sdk_pb2
35from chromite.api.gen.chromite.api import sysroot_pb2
36from chromite.api.gen.chromite.api import test_pb2
Tiancong Wangaf050172019-07-10 11:52:03 -070037from chromite.api.gen.chromite.api import toolchain_pb2
Alex Klein146d4772019-06-20 13:48:25 -060038from chromite.lib import cros_build_lib
Alex Klein146d4772019-06-20 13:48:25 -060039from chromite.lib import osutils
Alex Klein92341cd2020-02-27 14:11:04 -070040from chromite.utils import memoize
Alex Klein146d4772019-06-20 13:48:25 -060041
Mike Frysinger1cc8f1f2022-04-28 22:40:40 -040042
Tomasz Tylendab4292302021-08-08 18:59:36 +090043if TYPE_CHECKING:
Mike Frysinger1cc8f1f2022-04-28 22:40:40 -040044 from chromite.third_party import google
45
Tomasz Tylendab4292302021-08-08 18:59:36 +090046 from chromite.api import api_config
47 from chromite.api import message_util
Mike Frysinger88770ef2021-05-21 11:04:00 -040048
Alex Klein92341cd2020-02-27 14:11:04 -070049MethodData = collections.namedtuple(
50 'MethodData', ('service_descriptor', 'module_name', 'method_descriptor'))
Alex Klein146d4772019-06-20 13:48:25 -060051
Mike Frysingeref94e4c2020-02-10 23:59:54 -050052
Alex Klein146d4772019-06-20 13:48:25 -060053class Error(Exception):
54 """Base error class for the module."""
55
56
Alex Kleind3394c22020-06-16 14:05:06 -060057class InvalidSdkError(Error):
58 """Raised when the SDK is invalid or does not exist."""
59
60
Alex Klein146d4772019-06-20 13:48:25 -060061class CrosSdkNotRunError(Error):
62 """Raised when the cros_sdk command could not be run to enter the chroot."""
63
64
65# API Service Errors.
66class UnknownServiceError(Error):
67 """Error raised when the requested service has not been registered."""
68
69
70class ControllerModuleNotDefinedError(Error):
Alex Klein92341cd2020-02-27 14:11:04 -070071 """Error class for when no controller has been defined for a service."""
Alex Klein146d4772019-06-20 13:48:25 -060072
73
74class ServiceControllerNotFoundError(Error):
75 """Error raised when the service's controller cannot be imported."""
76
77
78# API Method Errors.
79class UnknownMethodError(Error):
Alex Klein92341cd2020-02-27 14:11:04 -070080 """The service has been defined in the proto, but the method has not."""
Alex Klein146d4772019-06-20 13:48:25 -060081
82
83class MethodNotFoundError(Error):
84 """The method's implementation cannot be found in the service's controller."""
85
86
87class Router(object):
88 """Encapsulates the request dispatching logic."""
89
Alex Kleine191ed62020-02-27 15:59:55 -070090 REEXEC_INPUT_FILE = 'input_proto'
91 REEXEC_OUTPUT_FILE = 'output_proto'
92 REEXEC_CONFIG_FILE = 'config_proto'
Alex Kleinbd6edf82019-07-18 10:30:49 -060093
Alex Klein146d4772019-06-20 13:48:25 -060094 def __init__(self):
95 self._services = {}
96 self._aliases = {}
97 # All imported generated messages get added to this symbol db.
98 self._sym_db = symbol_database.Default()
99
Alex Klein92341cd2020-02-27 14:11:04 -0700100 # Save the service and method extension info for looking up
101 # configured extension data.
Alex Klein146d4772019-06-20 13:48:25 -0600102 extensions = build_api_pb2.DESCRIPTOR.extensions_by_name
Alex Klein92341cd2020-02-27 14:11:04 -0700103 self._svc_options_ext = extensions['service_options']
104 self._method_options_ext = extensions['method_options']
105
106 @memoize.Memoize
107 def _get_method_data(self, service_name, method_name):
108 """Get the descriptors and module name for the given Service/Method."""
109 try:
110 svc, module_name = self._services[service_name]
111 except KeyError:
112 raise UnknownServiceError(
113 'The %s service has not been registered.' % service_name)
114
115 try:
116 method_desc = svc.methods_by_name[method_name]
117 except KeyError:
118 raise UnknownMethodError('The %s method has not been defined in the %s '
119 'service.' % (method_name, service_name))
120
121 return MethodData(
122 service_descriptor=svc,
123 module_name=module_name,
124 method_descriptor=method_desc)
125
Alex Kleina0bd45c2022-03-15 10:59:47 -0600126 def get_input_message_instance(self, service_name, method_name):
Alex Klein92341cd2020-02-27 14:11:04 -0700127 """Get an empty input message instance for the specified method."""
128 method_data = self._get_method_data(service_name, method_name)
129 return self._sym_db.GetPrototype(method_data.method_descriptor.input_type)()
130
131 def _get_output_message_instance(self, service_name, method_name):
132 """Get an empty output message instance for the specified method."""
133 method_data = self._get_method_data(service_name, method_name)
134 return self._sym_db.GetPrototype(
135 method_data.method_descriptor.output_type)()
136
137 def _get_module_name(self, service_name, method_name):
138 """Get the name of the module containing the endpoint implementation."""
139 return self._get_method_data(service_name, method_name).module_name
140
141 def _get_service_options(self, service_name, method_name):
142 """Get the configured service options for the endpoint."""
143 method_data = self._get_method_data(service_name, method_name)
144 svc_extensions = method_data.service_descriptor.GetOptions().Extensions
145 return svc_extensions[self._svc_options_ext]
146
147 def _get_method_options(self, service_name, method_name):
148 """Get the configured method options for the endpoint."""
149 method_data = self._get_method_data(service_name, method_name)
150 method_extensions = method_data.method_descriptor.GetOptions().Extensions
151 return method_extensions[self._method_options_ext]
Alex Klein146d4772019-06-20 13:48:25 -0600152
Tomasz Tylendab4292302021-08-08 18:59:36 +0900153 def Register(self, proto_module: ModuleType):
Alex Klein146d4772019-06-20 13:48:25 -0600154 """Register the services from a generated proto module.
155
156 Args:
Tomasz Tylendab4292302021-08-08 18:59:36 +0900157 proto_module: The generated proto module to register.
Alex Klein146d4772019-06-20 13:48:25 -0600158
159 Raises:
160 ServiceModuleNotDefinedError when the service cannot be found in the
161 provided module.
162 """
163 services = proto_module.DESCRIPTOR.services_by_name
164 for service_name, svc in services.items():
Alex Klein92341cd2020-02-27 14:11:04 -0700165 module_name = svc.GetOptions().Extensions[self._svc_options_ext].module
Alex Klein146d4772019-06-20 13:48:25 -0600166
167 if not module_name:
168 raise ControllerModuleNotDefinedError(
169 'The module must be defined in the service definition: %s.%s' %
170 (proto_module, service_name))
171
172 self._services[svc.full_name] = (svc, module_name)
173
174 def ListMethods(self):
175 """List all methods registered with the router."""
176 services = []
177 for service_name, (svc, _module) in self._services.items():
Alex Klein6cce6f62021-03-02 14:24:05 -0700178 svc_visibility = getattr(
179 svc.GetOptions().Extensions[self._svc_options_ext],
180 'service_visibility', build_api_pb2.LV_VISIBLE)
181 if svc_visibility == build_api_pb2.LV_HIDDEN:
182 continue
183
Alex Klein146d4772019-06-20 13:48:25 -0600184 for method_name in svc.methods_by_name.keys():
Alex Klein6cce6f62021-03-02 14:24:05 -0700185 method_options = self._get_method_options(service_name, method_name)
186 method_visibility = getattr(method_options, 'method_visibility',
187 build_api_pb2.LV_VISIBLE)
188 if method_visibility == build_api_pb2.LV_HIDDEN:
189 continue
190
Alex Klein146d4772019-06-20 13:48:25 -0600191 services.append('%s/%s' % (service_name, method_name))
192
193 return sorted(services)
194
Tomasz Tylendab4292302021-08-08 18:59:36 +0900195 def Route(self, service_name: str, method_name: str,
196 config: 'api_config.ApiConfig',
197 input_handler: 'message_util.MessageHandler',
198 output_handlers: List['message_util.MessageHandler'],
199 config_handler: 'message_util.MessageHandler') -> int:
Alex Klein146d4772019-06-20 13:48:25 -0600200 """Dispatch the request.
201
202 Args:
Tomasz Tylendab4292302021-08-08 18:59:36 +0900203 service_name: The fully qualified service name.
204 method_name: The name of the method being called.
205 config: The call configs.
206 input_handler: The request message handler.
207 output_handlers: The response message handlers.
208 config_handler: The config message handler.
Alex Klein146d4772019-06-20 13:48:25 -0600209
210 Returns:
Tomasz Tylendab4292302021-08-08 18:59:36 +0900211 The return code.
Alex Klein146d4772019-06-20 13:48:25 -0600212
213 Raises:
214 InvalidInputFileError when the input file cannot be read.
215 InvalidOutputFileError when the output file cannot be written.
216 ServiceModuleNotFoundError when the service module cannot be imported.
217 MethodNotFoundError when the method cannot be retrieved from the module.
218 """
Alex Kleina0bd45c2022-03-15 10:59:47 -0600219 input_msg = self.get_input_message_instance(service_name, method_name)
Alex Kleine191ed62020-02-27 15:59:55 -0700220 input_handler.read_into(input_msg)
Alex Klein146d4772019-06-20 13:48:25 -0600221
222 # Get an empty output message instance.
Alex Klein92341cd2020-02-27 14:11:04 -0700223 output_msg = self._get_output_message_instance(service_name, method_name)
Alex Klein146d4772019-06-20 13:48:25 -0600224
Alex Kleinbd6edf82019-07-18 10:30:49 -0600225 # Fetch the method options for chroot and method name overrides.
Alex Klein92341cd2020-02-27 14:11:04 -0700226 method_options = self._get_method_options(service_name, method_name)
Alex Klein146d4772019-06-20 13:48:25 -0600227
228 # Check the chroot settings before running.
Alex Klein92341cd2020-02-27 14:11:04 -0700229 service_options = self._get_service_options(service_name, method_name)
Alex Kleind1e9e5c2020-12-14 12:32:32 -0700230 if self._ChrootCheck(service_options, method_options, config):
Alex Klein146d4772019-06-20 13:48:25 -0600231 # Run inside the chroot instead.
232 logging.info('Re-executing the endpoint inside the chroot.')
Alex Kleine191ed62020-02-27 15:59:55 -0700233 return self._ReexecuteInside(input_msg, output_msg, config, input_handler,
234 output_handlers, config_handler,
235 service_name, method_name)
Alex Kleinbd6edf82019-07-18 10:30:49 -0600236
237 # Allow proto-based method name override.
238 if method_options.HasField('implementation_name'):
Alex Klein92341cd2020-02-27 14:11:04 -0700239 implementation_name = method_options.implementation_name
240 else:
241 implementation_name = method_name
Alex Klein146d4772019-06-20 13:48:25 -0600242
243 # Import the module and get the method.
Alex Klein92341cd2020-02-27 14:11:04 -0700244 module_name = self._get_module_name(service_name, method_name)
245 method_impl = self._GetMethod(module_name, implementation_name)
Alex Klein146d4772019-06-20 13:48:25 -0600246
247 # Successfully located; call and return.
Alex Klein69339cc2019-07-22 14:08:35 -0600248 return_code = method_impl(input_msg, output_msg, config)
Alex Klein146d4772019-06-20 13:48:25 -0600249 if return_code is None:
250 return_code = controller.RETURN_CODE_SUCCESS
251
Alex Kleine191ed62020-02-27 15:59:55 -0700252 for h in output_handlers:
253 h.write_from(output_msg)
Alex Klein146d4772019-06-20 13:48:25 -0600254
255 return return_code
256
Tomasz Tylendab4292302021-08-08 18:59:36 +0900257 def _ChrootCheck(self, service_options: 'google.protobuf.Message',
258 method_options: 'google.protobuf.Message',
259 config: 'api_config.ApiConfig') -> bool:
Alex Klein146d4772019-06-20 13:48:25 -0600260 """Check the chroot options, and execute assertion or note reexec as needed.
261
262 Args:
Tomasz Tylendab4292302021-08-08 18:59:36 +0900263 service_options: The service options.
264 method_options: The method options.
Alex Kleind1e9e5c2020-12-14 12:32:32 -0700265 config: The Build API call config instance.
Alex Klein146d4772019-06-20 13:48:25 -0600266
267 Returns:
Tomasz Tylendab4292302021-08-08 18:59:36 +0900268 True iff it needs to be reexeced inside the chroot.
Alex Klein146d4772019-06-20 13:48:25 -0600269
270 Raises:
271 cros_build_lib.DieSystemExit when the chroot setting cannot be satisfied.
272 """
Alex Kleind1e9e5c2020-12-14 12:32:32 -0700273 if not config.run_endpoint:
274 # Do not enter the chroot for validate only and mock calls.
275 return False
276
Alex Klein146d4772019-06-20 13:48:25 -0600277 chroot_assert = build_api_pb2.NO_ASSERTION
278 if method_options.HasField('method_chroot_assert'):
279 # Prefer the method option when set.
280 chroot_assert = method_options.method_chroot_assert
281 elif service_options.HasField('service_chroot_assert'):
282 # Fall back to the service option.
283 chroot_assert = service_options.service_chroot_assert
284
285 if chroot_assert == build_api_pb2.INSIDE:
286 return not cros_build_lib.IsInsideChroot()
287 elif chroot_assert == build_api_pb2.OUTSIDE:
288 # If it must be run outside we have to already be outside.
289 cros_build_lib.AssertOutsideChroot()
290
291 return False
292
Tomasz Tylendab4292302021-08-08 18:59:36 +0900293 def _ReexecuteInside(self, input_msg: 'google.protobuf.Message',
294 output_msg: 'google.protobuf.Message',
295 config: 'api_config.ApiConfig',
296 input_handler: 'message_util.MessageHandler',
297 output_handlers: List['message_util.MessageHandler'],
298 config_handler: 'message_util.MessageHandler',
299 service_name: str,
300 method_name: str):
Alex Klein146d4772019-06-20 13:48:25 -0600301 """Re-execute the service inside the chroot.
302
303 Args:
Tomasz Tylendab4292302021-08-08 18:59:36 +0900304 input_msg: The parsed input message.
305 output_msg: The empty output message instance.
306 config: The call configs.
307 input_handler: Input message handler.
308 output_handlers: Output message handlers.
309 config_handler: Config message handler.
310 service_name: The name of the service to run.
311 method_name: The name of the method to run.
Alex Klein146d4772019-06-20 13:48:25 -0600312 """
Alex Kleinc7d647f2020-01-06 12:00:48 -0700313 # Parse the chroot and clear the chroot field in the input message.
314 chroot = field_handler.handle_chroot(input_msg)
Alex Klein915cce92019-12-17 14:19:50 -0700315
Alex Kleind3394c22020-06-16 14:05:06 -0600316 if not chroot.exists():
317 raise InvalidSdkError('Chroot does not exist.')
318
Alex Kleinc7d647f2020-01-06 12:00:48 -0700319 # Use a ContextManagerStack to avoid the deep nesting this many
320 # context managers introduces.
321 with cros_build_lib.ContextManagerStack() as stack:
322 # TempDirs setup.
323 tempdir = stack.Add(chroot.tempdir).tempdir
324 sync_tempdir = stack.Add(chroot.tempdir).tempdir
325 # The copy-paths-in context manager to handle Path messages.
Alex Klein92341cd2020-02-27 14:11:04 -0700326 stack.Add(
327 field_handler.copy_paths_in,
328 input_msg,
329 chroot.tmp,
330 prefix=chroot.path)
Alex Kleinc7d647f2020-01-06 12:00:48 -0700331 # The sync-directories context manager to handle SyncedDir messages.
Alex Klein92341cd2020-02-27 14:11:04 -0700332 stack.Add(
333 field_handler.sync_dirs, input_msg, sync_tempdir, prefix=chroot.path)
Alex Klein146d4772019-06-20 13:48:25 -0600334
Alex Klein4089a492020-06-30 10:59:36 -0600335 # Parse goma.
Alex Kleinc7d647f2020-01-06 12:00:48 -0700336 chroot.goma = field_handler.handle_goma(input_msg, chroot.path)
Alex Klein9b7331e2019-12-30 14:37:21 -0700337
Joanna Wang92cad812021-11-03 14:52:08 -0700338 # Parse remoteexec.
339 chroot.remoteexec = field_handler.handle_remoteexec(input_msg)
340
Alex Klein4089a492020-06-30 10:59:36 -0600341 # Build inside-chroot paths for the input, output, and config messages.
Alex Kleinc7d647f2020-01-06 12:00:48 -0700342 new_input = os.path.join(tempdir, self.REEXEC_INPUT_FILE)
343 chroot_input = '/%s' % os.path.relpath(new_input, chroot.path)
344 new_output = os.path.join(tempdir, self.REEXEC_OUTPUT_FILE)
345 chroot_output = '/%s' % os.path.relpath(new_output, chroot.path)
Alex Kleind815ca62020-01-10 12:21:30 -0700346 new_config = os.path.join(tempdir, self.REEXEC_CONFIG_FILE)
347 chroot_config = '/%s' % os.path.relpath(new_config, chroot.path)
Alex Klein9b7331e2019-12-30 14:37:21 -0700348
Alex Klein4089a492020-06-30 10:59:36 -0600349 # Setup the inside-chroot message files.
Alex Kleinc7d647f2020-01-06 12:00:48 -0700350 logging.info('Writing input message to: %s', new_input)
Alex Kleine191ed62020-02-27 15:59:55 -0700351 input_handler.write_from(input_msg, path=new_input)
Alex Kleinc7d647f2020-01-06 12:00:48 -0700352 osutils.Touch(new_output)
Alex Kleind815ca62020-01-10 12:21:30 -0700353 logging.info('Writing config message to: %s', new_config)
Alex Kleine191ed62020-02-27 15:59:55 -0700354 config_handler.write_from(config.get_proto(), path=new_config)
Alex Klein146d4772019-06-20 13:48:25 -0600355
Alex Kleine191ed62020-02-27 15:59:55 -0700356 # We can use a single output to write the rest of them. Use the
357 # first one as the reexec output and just translate its output in
358 # the rest of the handlers after.
359 output_handler = output_handlers[0]
360
361 cmd = [
362 'build_api',
363 '%s/%s' % (service_name, method_name),
364 input_handler.input_arg,
365 chroot_input,
366 output_handler.output_arg,
367 chroot_output,
368 config_handler.config_arg,
369 chroot_config,
Alex Klein0b9edda2020-05-20 10:35:01 -0600370 '--debug',
Alex Kleine191ed62020-02-27 15:59:55 -0700371 ]
Alex Klein146d4772019-06-20 13:48:25 -0600372
Alex Kleinc7d647f2020-01-06 12:00:48 -0700373 try:
374 result = cros_build_lib.run(
375 cmd,
376 enter_chroot=True,
377 chroot_args=chroot.get_enter_args(),
378 check=False,
379 extra_env=chroot.env)
380 except cros_build_lib.RunCommandError:
381 # A non-zero return code will not result in an error, but one
382 # is still thrown when the command cannot be run in the first
383 # place. This is known to happen at least when the PATH does
384 # not include the chromite bin dir.
385 raise CrosSdkNotRunError('Unable to enter the chroot.')
Alex Klein69339cc2019-07-22 14:08:35 -0600386
Alex Kleinc7d647f2020-01-06 12:00:48 -0700387 logging.info('Endpoint execution completed, return code: %d',
388 result.returncode)
Alex Klein146d4772019-06-20 13:48:25 -0600389
Alex Kleinc7d647f2020-01-06 12:00:48 -0700390 # Transfer result files out of the chroot.
Alex Kleine191ed62020-02-27 15:59:55 -0700391 output_handler.read_into(output_msg, path=new_output)
392 field_handler.extract_results(input_msg, output_msg, chroot)
Alex Klein146d4772019-06-20 13:48:25 -0600393
Alex Kleine191ed62020-02-27 15:59:55 -0700394 # Write out all of the response formats.
395 for handler in output_handlers:
396 handler.write_from(output_msg)
Alex Kleinbd6edf82019-07-18 10:30:49 -0600397
Alex Kleinc7d647f2020-01-06 12:00:48 -0700398 return result.returncode
Alex Klein146d4772019-06-20 13:48:25 -0600399
Tomasz Tylendab4292302021-08-08 18:59:36 +0900400 def _GetMethod(self, module_name: str, method_name: str) -> Callable:
Alex Klein146d4772019-06-20 13:48:25 -0600401 """Get the implementation of the method for the service module.
402
403 Args:
Tomasz Tylendab4292302021-08-08 18:59:36 +0900404 module_name: The name of the service module.
405 method_name: The name of the method.
Alex Klein146d4772019-06-20 13:48:25 -0600406
407 Returns:
Tomasz Tylendab4292302021-08-08 18:59:36 +0900408 The method.
Alex Klein146d4772019-06-20 13:48:25 -0600409
410 Raises:
411 MethodNotFoundError when the method cannot be found in the module.
412 ServiceModuleNotFoundError when the service module cannot be imported.
413 """
414 try:
415 module = importlib.import_module(controller.IMPORT_PATTERN % module_name)
416 except ImportError as e:
Mike Frysinger6b5c3cd2019-08-27 16:51:00 -0400417 raise ServiceControllerNotFoundError(str(e))
Alex Klein146d4772019-06-20 13:48:25 -0600418 try:
419 return getattr(module, method_name)
420 except AttributeError as e:
Mike Frysinger6b5c3cd2019-08-27 16:51:00 -0400421 raise MethodNotFoundError(str(e))
Alex Klein146d4772019-06-20 13:48:25 -0600422
423
Tomasz Tylendab4292302021-08-08 18:59:36 +0900424def RegisterServices(router: Router):
Alex Klein146d4772019-06-20 13:48:25 -0600425 """Register all the services.
426
427 Args:
Tomasz Tylendab4292302021-08-08 18:59:36 +0900428 router: The router.
Alex Klein146d4772019-06-20 13:48:25 -0600429 """
Alex Klein4de25e82019-08-05 15:58:39 -0600430 router.Register(android_pb2)
Alex Klein54e38e32019-06-21 14:54:17 -0600431 router.Register(api_pb2)
Alex Klein146d4772019-06-20 13:48:25 -0600432 router.Register(artifacts_pb2)
433 router.Register(binhost_pb2)
434 router.Register(depgraph_pb2)
Jett Rink17ed0f52020-09-25 17:14:31 -0600435 router.Register(firmware_pb2)
Alex Klein146d4772019-06-20 13:48:25 -0600436 router.Register(image_pb2)
Alex Kleind4d9caa2021-11-10 15:44:52 -0700437 router.Register(metadata_pb2)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600438 router.Register(packages_pb2)
George Engelbrechtfe63c8c2019-08-31 22:51:29 -0600439 router.Register(payload_pb2)
Alexander Liu008389c2022-06-27 18:30:11 +0000440 router.Register(portage_explorer_pb2)
Alex Klein146d4772019-06-20 13:48:25 -0600441 router.Register(sdk_pb2)
442 router.Register(sysroot_pb2)
443 router.Register(test_pb2)
Tiancong Wangaf050172019-07-10 11:52:03 -0700444 router.Register(toolchain_pb2)
Alex Klein146d4772019-06-20 13:48:25 -0600445 logging.debug('Services registered successfully.')
446
447
448def GetRouter():
449 """Get a router that has had all of the services registered."""
450 router = Router()
451 RegisterServices(router)
452
453 return router