blob: a89773bd9e93012e50db9088c482aadef68ec22b [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
Alex Klein146d4772019-06-20 13:48:25 -060033from chromite.api.gen.chromite.api import sdk_pb2
34from chromite.api.gen.chromite.api import sysroot_pb2
35from chromite.api.gen.chromite.api import test_pb2
Tiancong Wangaf050172019-07-10 11:52:03 -070036from chromite.api.gen.chromite.api import toolchain_pb2
Alex Klein146d4772019-06-20 13:48:25 -060037from chromite.lib import cros_build_lib
Alex Klein146d4772019-06-20 13:48:25 -060038from chromite.lib import osutils
Alex Klein92341cd2020-02-27 14:11:04 -070039from chromite.utils import memoize
Alex Klein146d4772019-06-20 13:48:25 -060040
Tomasz Tylendab4292302021-08-08 18:59:36 +090041if TYPE_CHECKING:
42 from chromite.api import api_config
43 from chromite.api import message_util
44 from chromite.third_party import google
Mike Frysinger88770ef2021-05-21 11:04:00 -040045
Alex Klein92341cd2020-02-27 14:11:04 -070046MethodData = collections.namedtuple(
47 'MethodData', ('service_descriptor', 'module_name', 'method_descriptor'))
Alex Klein146d4772019-06-20 13:48:25 -060048
Mike Frysingeref94e4c2020-02-10 23:59:54 -050049
Alex Klein146d4772019-06-20 13:48:25 -060050class Error(Exception):
51 """Base error class for the module."""
52
53
Alex Kleind3394c22020-06-16 14:05:06 -060054class InvalidSdkError(Error):
55 """Raised when the SDK is invalid or does not exist."""
56
57
Alex Klein146d4772019-06-20 13:48:25 -060058class CrosSdkNotRunError(Error):
59 """Raised when the cros_sdk command could not be run to enter the chroot."""
60
61
62# API Service Errors.
63class UnknownServiceError(Error):
64 """Error raised when the requested service has not been registered."""
65
66
67class ControllerModuleNotDefinedError(Error):
Alex Klein92341cd2020-02-27 14:11:04 -070068 """Error class for when no controller has been defined for a service."""
Alex Klein146d4772019-06-20 13:48:25 -060069
70
71class ServiceControllerNotFoundError(Error):
72 """Error raised when the service's controller cannot be imported."""
73
74
75# API Method Errors.
76class UnknownMethodError(Error):
Alex Klein92341cd2020-02-27 14:11:04 -070077 """The service has been defined in the proto, but the method has not."""
Alex Klein146d4772019-06-20 13:48:25 -060078
79
80class MethodNotFoundError(Error):
81 """The method's implementation cannot be found in the service's controller."""
82
83
84class Router(object):
85 """Encapsulates the request dispatching logic."""
86
Alex Kleine191ed62020-02-27 15:59:55 -070087 REEXEC_INPUT_FILE = 'input_proto'
88 REEXEC_OUTPUT_FILE = 'output_proto'
89 REEXEC_CONFIG_FILE = 'config_proto'
Alex Kleinbd6edf82019-07-18 10:30:49 -060090
Alex Klein146d4772019-06-20 13:48:25 -060091 def __init__(self):
92 self._services = {}
93 self._aliases = {}
94 # All imported generated messages get added to this symbol db.
95 self._sym_db = symbol_database.Default()
96
Alex Klein92341cd2020-02-27 14:11:04 -070097 # Save the service and method extension info for looking up
98 # configured extension data.
Alex Klein146d4772019-06-20 13:48:25 -060099 extensions = build_api_pb2.DESCRIPTOR.extensions_by_name
Alex Klein92341cd2020-02-27 14:11:04 -0700100 self._svc_options_ext = extensions['service_options']
101 self._method_options_ext = extensions['method_options']
102
103 @memoize.Memoize
104 def _get_method_data(self, service_name, method_name):
105 """Get the descriptors and module name for the given Service/Method."""
106 try:
107 svc, module_name = self._services[service_name]
108 except KeyError:
109 raise UnknownServiceError(
110 'The %s service has not been registered.' % service_name)
111
112 try:
113 method_desc = svc.methods_by_name[method_name]
114 except KeyError:
115 raise UnknownMethodError('The %s method has not been defined in the %s '
116 'service.' % (method_name, service_name))
117
118 return MethodData(
119 service_descriptor=svc,
120 module_name=module_name,
121 method_descriptor=method_desc)
122
123 def _get_input_message_instance(self, service_name, method_name):
124 """Get an empty input message instance for the specified method."""
125 method_data = self._get_method_data(service_name, method_name)
126 return self._sym_db.GetPrototype(method_data.method_descriptor.input_type)()
127
128 def _get_output_message_instance(self, service_name, method_name):
129 """Get an empty output message instance for the specified method."""
130 method_data = self._get_method_data(service_name, method_name)
131 return self._sym_db.GetPrototype(
132 method_data.method_descriptor.output_type)()
133
134 def _get_module_name(self, service_name, method_name):
135 """Get the name of the module containing the endpoint implementation."""
136 return self._get_method_data(service_name, method_name).module_name
137
138 def _get_service_options(self, service_name, method_name):
139 """Get the configured service options for the endpoint."""
140 method_data = self._get_method_data(service_name, method_name)
141 svc_extensions = method_data.service_descriptor.GetOptions().Extensions
142 return svc_extensions[self._svc_options_ext]
143
144 def _get_method_options(self, service_name, method_name):
145 """Get the configured method options for the endpoint."""
146 method_data = self._get_method_data(service_name, method_name)
147 method_extensions = method_data.method_descriptor.GetOptions().Extensions
148 return method_extensions[self._method_options_ext]
Alex Klein146d4772019-06-20 13:48:25 -0600149
Tomasz Tylendab4292302021-08-08 18:59:36 +0900150 def Register(self, proto_module: ModuleType):
Alex Klein146d4772019-06-20 13:48:25 -0600151 """Register the services from a generated proto module.
152
153 Args:
Tomasz Tylendab4292302021-08-08 18:59:36 +0900154 proto_module: The generated proto module to register.
Alex Klein146d4772019-06-20 13:48:25 -0600155
156 Raises:
157 ServiceModuleNotDefinedError when the service cannot be found in the
158 provided module.
159 """
160 services = proto_module.DESCRIPTOR.services_by_name
161 for service_name, svc in services.items():
Alex Klein92341cd2020-02-27 14:11:04 -0700162 module_name = svc.GetOptions().Extensions[self._svc_options_ext].module
Alex Klein146d4772019-06-20 13:48:25 -0600163
164 if not module_name:
165 raise ControllerModuleNotDefinedError(
166 'The module must be defined in the service definition: %s.%s' %
167 (proto_module, service_name))
168
169 self._services[svc.full_name] = (svc, module_name)
170
171 def ListMethods(self):
172 """List all methods registered with the router."""
173 services = []
174 for service_name, (svc, _module) in self._services.items():
Alex Klein6cce6f62021-03-02 14:24:05 -0700175 svc_visibility = getattr(
176 svc.GetOptions().Extensions[self._svc_options_ext],
177 'service_visibility', build_api_pb2.LV_VISIBLE)
178 if svc_visibility == build_api_pb2.LV_HIDDEN:
179 continue
180
Alex Klein146d4772019-06-20 13:48:25 -0600181 for method_name in svc.methods_by_name.keys():
Alex Klein6cce6f62021-03-02 14:24:05 -0700182 method_options = self._get_method_options(service_name, method_name)
183 method_visibility = getattr(method_options, 'method_visibility',
184 build_api_pb2.LV_VISIBLE)
185 if method_visibility == build_api_pb2.LV_HIDDEN:
186 continue
187
Alex Klein146d4772019-06-20 13:48:25 -0600188 services.append('%s/%s' % (service_name, method_name))
189
190 return sorted(services)
191
Tomasz Tylendab4292302021-08-08 18:59:36 +0900192 def Route(self, service_name: str, method_name: str,
193 config: 'api_config.ApiConfig',
194 input_handler: 'message_util.MessageHandler',
195 output_handlers: List['message_util.MessageHandler'],
196 config_handler: 'message_util.MessageHandler') -> int:
Alex Klein146d4772019-06-20 13:48:25 -0600197 """Dispatch the request.
198
199 Args:
Tomasz Tylendab4292302021-08-08 18:59:36 +0900200 service_name: The fully qualified service name.
201 method_name: The name of the method being called.
202 config: The call configs.
203 input_handler: The request message handler.
204 output_handlers: The response message handlers.
205 config_handler: The config message handler.
Alex Klein146d4772019-06-20 13:48:25 -0600206
207 Returns:
Tomasz Tylendab4292302021-08-08 18:59:36 +0900208 The return code.
Alex Klein146d4772019-06-20 13:48:25 -0600209
210 Raises:
211 InvalidInputFileError when the input file cannot be read.
212 InvalidOutputFileError when the output file cannot be written.
213 ServiceModuleNotFoundError when the service module cannot be imported.
214 MethodNotFoundError when the method cannot be retrieved from the module.
215 """
Alex Klein92341cd2020-02-27 14:11:04 -0700216 input_msg = self._get_input_message_instance(service_name, method_name)
Alex Kleine191ed62020-02-27 15:59:55 -0700217 input_handler.read_into(input_msg)
Alex Klein146d4772019-06-20 13:48:25 -0600218
219 # Get an empty output message instance.
Alex Klein92341cd2020-02-27 14:11:04 -0700220 output_msg = self._get_output_message_instance(service_name, method_name)
Alex Klein146d4772019-06-20 13:48:25 -0600221
Alex Kleinbd6edf82019-07-18 10:30:49 -0600222 # Fetch the method options for chroot and method name overrides.
Alex Klein92341cd2020-02-27 14:11:04 -0700223 method_options = self._get_method_options(service_name, method_name)
Alex Klein146d4772019-06-20 13:48:25 -0600224
225 # Check the chroot settings before running.
Alex Klein92341cd2020-02-27 14:11:04 -0700226 service_options = self._get_service_options(service_name, method_name)
Alex Kleind1e9e5c2020-12-14 12:32:32 -0700227 if self._ChrootCheck(service_options, method_options, config):
Alex Klein146d4772019-06-20 13:48:25 -0600228 # Run inside the chroot instead.
229 logging.info('Re-executing the endpoint inside the chroot.')
Alex Kleine191ed62020-02-27 15:59:55 -0700230 return self._ReexecuteInside(input_msg, output_msg, config, input_handler,
231 output_handlers, config_handler,
232 service_name, method_name)
Alex Kleinbd6edf82019-07-18 10:30:49 -0600233
234 # Allow proto-based method name override.
235 if method_options.HasField('implementation_name'):
Alex Klein92341cd2020-02-27 14:11:04 -0700236 implementation_name = method_options.implementation_name
237 else:
238 implementation_name = method_name
Alex Klein146d4772019-06-20 13:48:25 -0600239
240 # Import the module and get the method.
Alex Klein92341cd2020-02-27 14:11:04 -0700241 module_name = self._get_module_name(service_name, method_name)
242 method_impl = self._GetMethod(module_name, implementation_name)
Alex Klein146d4772019-06-20 13:48:25 -0600243
244 # Successfully located; call and return.
Alex Klein69339cc2019-07-22 14:08:35 -0600245 return_code = method_impl(input_msg, output_msg, config)
Alex Klein146d4772019-06-20 13:48:25 -0600246 if return_code is None:
247 return_code = controller.RETURN_CODE_SUCCESS
248
Alex Kleine191ed62020-02-27 15:59:55 -0700249 for h in output_handlers:
250 h.write_from(output_msg)
Alex Klein146d4772019-06-20 13:48:25 -0600251
252 return return_code
253
Tomasz Tylendab4292302021-08-08 18:59:36 +0900254 def _ChrootCheck(self, service_options: 'google.protobuf.Message',
255 method_options: 'google.protobuf.Message',
256 config: 'api_config.ApiConfig') -> bool:
Alex Klein146d4772019-06-20 13:48:25 -0600257 """Check the chroot options, and execute assertion or note reexec as needed.
258
259 Args:
Tomasz Tylendab4292302021-08-08 18:59:36 +0900260 service_options: The service options.
261 method_options: The method options.
Alex Kleind1e9e5c2020-12-14 12:32:32 -0700262 config: The Build API call config instance.
Alex Klein146d4772019-06-20 13:48:25 -0600263
264 Returns:
Tomasz Tylendab4292302021-08-08 18:59:36 +0900265 True iff it needs to be reexeced inside the chroot.
Alex Klein146d4772019-06-20 13:48:25 -0600266
267 Raises:
268 cros_build_lib.DieSystemExit when the chroot setting cannot be satisfied.
269 """
Alex Kleind1e9e5c2020-12-14 12:32:32 -0700270 if not config.run_endpoint:
271 # Do not enter the chroot for validate only and mock calls.
272 return False
273
Alex Klein146d4772019-06-20 13:48:25 -0600274 chroot_assert = build_api_pb2.NO_ASSERTION
275 if method_options.HasField('method_chroot_assert'):
276 # Prefer the method option when set.
277 chroot_assert = method_options.method_chroot_assert
278 elif service_options.HasField('service_chroot_assert'):
279 # Fall back to the service option.
280 chroot_assert = service_options.service_chroot_assert
281
282 if chroot_assert == build_api_pb2.INSIDE:
283 return not cros_build_lib.IsInsideChroot()
284 elif chroot_assert == build_api_pb2.OUTSIDE:
285 # If it must be run outside we have to already be outside.
286 cros_build_lib.AssertOutsideChroot()
287
288 return False
289
Tomasz Tylendab4292302021-08-08 18:59:36 +0900290 def _ReexecuteInside(self, input_msg: 'google.protobuf.Message',
291 output_msg: 'google.protobuf.Message',
292 config: 'api_config.ApiConfig',
293 input_handler: 'message_util.MessageHandler',
294 output_handlers: List['message_util.MessageHandler'],
295 config_handler: 'message_util.MessageHandler',
296 service_name: str,
297 method_name: str):
Alex Klein146d4772019-06-20 13:48:25 -0600298 """Re-execute the service inside the chroot.
299
300 Args:
Tomasz Tylendab4292302021-08-08 18:59:36 +0900301 input_msg: The parsed input message.
302 output_msg: The empty output message instance.
303 config: The call configs.
304 input_handler: Input message handler.
305 output_handlers: Output message handlers.
306 config_handler: Config message handler.
307 service_name: The name of the service to run.
308 method_name: The name of the method to run.
Alex Klein146d4772019-06-20 13:48:25 -0600309 """
Alex Kleinc7d647f2020-01-06 12:00:48 -0700310 # Parse the chroot and clear the chroot field in the input message.
311 chroot = field_handler.handle_chroot(input_msg)
Alex Klein915cce92019-12-17 14:19:50 -0700312
Alex Kleind3394c22020-06-16 14:05:06 -0600313 if not chroot.exists():
314 raise InvalidSdkError('Chroot does not exist.')
315
Alex Kleinc7d647f2020-01-06 12:00:48 -0700316 # Use a ContextManagerStack to avoid the deep nesting this many
317 # context managers introduces.
318 with cros_build_lib.ContextManagerStack() as stack:
319 # TempDirs setup.
320 tempdir = stack.Add(chroot.tempdir).tempdir
321 sync_tempdir = stack.Add(chroot.tempdir).tempdir
322 # The copy-paths-in context manager to handle Path messages.
Alex Klein92341cd2020-02-27 14:11:04 -0700323 stack.Add(
324 field_handler.copy_paths_in,
325 input_msg,
326 chroot.tmp,
327 prefix=chroot.path)
Alex Kleinc7d647f2020-01-06 12:00:48 -0700328 # The sync-directories context manager to handle SyncedDir messages.
Alex Klein92341cd2020-02-27 14:11:04 -0700329 stack.Add(
330 field_handler.sync_dirs, input_msg, sync_tempdir, prefix=chroot.path)
Alex Klein146d4772019-06-20 13:48:25 -0600331
Alex Klein4089a492020-06-30 10:59:36 -0600332 # Parse goma.
Alex Kleinc7d647f2020-01-06 12:00:48 -0700333 chroot.goma = field_handler.handle_goma(input_msg, chroot.path)
Alex Klein9b7331e2019-12-30 14:37:21 -0700334
Joanna Wang92cad812021-11-03 14:52:08 -0700335 # Parse remoteexec.
336 chroot.remoteexec = field_handler.handle_remoteexec(input_msg)
337
Alex Klein4089a492020-06-30 10:59:36 -0600338 # Build inside-chroot paths for the input, output, and config messages.
Alex Kleinc7d647f2020-01-06 12:00:48 -0700339 new_input = os.path.join(tempdir, self.REEXEC_INPUT_FILE)
340 chroot_input = '/%s' % os.path.relpath(new_input, chroot.path)
341 new_output = os.path.join(tempdir, self.REEXEC_OUTPUT_FILE)
342 chroot_output = '/%s' % os.path.relpath(new_output, chroot.path)
Alex Kleind815ca62020-01-10 12:21:30 -0700343 new_config = os.path.join(tempdir, self.REEXEC_CONFIG_FILE)
344 chroot_config = '/%s' % os.path.relpath(new_config, chroot.path)
Alex Klein9b7331e2019-12-30 14:37:21 -0700345
Alex Klein4089a492020-06-30 10:59:36 -0600346 # Setup the inside-chroot message files.
Alex Kleinc7d647f2020-01-06 12:00:48 -0700347 logging.info('Writing input message to: %s', new_input)
Alex Kleine191ed62020-02-27 15:59:55 -0700348 input_handler.write_from(input_msg, path=new_input)
Alex Kleinc7d647f2020-01-06 12:00:48 -0700349 osutils.Touch(new_output)
Alex Kleind815ca62020-01-10 12:21:30 -0700350 logging.info('Writing config message to: %s', new_config)
Alex Kleine191ed62020-02-27 15:59:55 -0700351 config_handler.write_from(config.get_proto(), path=new_config)
Alex Klein146d4772019-06-20 13:48:25 -0600352
Alex Kleine191ed62020-02-27 15:59:55 -0700353 # We can use a single output to write the rest of them. Use the
354 # first one as the reexec output and just translate its output in
355 # the rest of the handlers after.
356 output_handler = output_handlers[0]
357
358 cmd = [
359 'build_api',
360 '%s/%s' % (service_name, method_name),
361 input_handler.input_arg,
362 chroot_input,
363 output_handler.output_arg,
364 chroot_output,
365 config_handler.config_arg,
366 chroot_config,
Alex Klein0b9edda2020-05-20 10:35:01 -0600367 '--debug',
Alex Kleine191ed62020-02-27 15:59:55 -0700368 ]
Alex Klein146d4772019-06-20 13:48:25 -0600369
Alex Kleinc7d647f2020-01-06 12:00:48 -0700370 try:
371 result = cros_build_lib.run(
372 cmd,
373 enter_chroot=True,
374 chroot_args=chroot.get_enter_args(),
375 check=False,
376 extra_env=chroot.env)
377 except cros_build_lib.RunCommandError:
378 # A non-zero return code will not result in an error, but one
379 # is still thrown when the command cannot be run in the first
380 # place. This is known to happen at least when the PATH does
381 # not include the chromite bin dir.
382 raise CrosSdkNotRunError('Unable to enter the chroot.')
Alex Klein69339cc2019-07-22 14:08:35 -0600383
Alex Kleinc7d647f2020-01-06 12:00:48 -0700384 logging.info('Endpoint execution completed, return code: %d',
385 result.returncode)
Alex Klein146d4772019-06-20 13:48:25 -0600386
Alex Kleinc7d647f2020-01-06 12:00:48 -0700387 # Transfer result files out of the chroot.
Alex Kleine191ed62020-02-27 15:59:55 -0700388 output_handler.read_into(output_msg, path=new_output)
389 field_handler.extract_results(input_msg, output_msg, chroot)
Alex Klein146d4772019-06-20 13:48:25 -0600390
Alex Kleine191ed62020-02-27 15:59:55 -0700391 # Write out all of the response formats.
392 for handler in output_handlers:
393 handler.write_from(output_msg)
Alex Kleinbd6edf82019-07-18 10:30:49 -0600394
Alex Kleinc7d647f2020-01-06 12:00:48 -0700395 return result.returncode
Alex Klein146d4772019-06-20 13:48:25 -0600396
Tomasz Tylendab4292302021-08-08 18:59:36 +0900397 def _GetMethod(self, module_name: str, method_name: str) -> Callable:
Alex Klein146d4772019-06-20 13:48:25 -0600398 """Get the implementation of the method for the service module.
399
400 Args:
Tomasz Tylendab4292302021-08-08 18:59:36 +0900401 module_name: The name of the service module.
402 method_name: The name of the method.
Alex Klein146d4772019-06-20 13:48:25 -0600403
404 Returns:
Tomasz Tylendab4292302021-08-08 18:59:36 +0900405 The method.
Alex Klein146d4772019-06-20 13:48:25 -0600406
407 Raises:
408 MethodNotFoundError when the method cannot be found in the module.
409 ServiceModuleNotFoundError when the service module cannot be imported.
410 """
411 try:
412 module = importlib.import_module(controller.IMPORT_PATTERN % module_name)
413 except ImportError as e:
Mike Frysinger6b5c3cd2019-08-27 16:51:00 -0400414 raise ServiceControllerNotFoundError(str(e))
Alex Klein146d4772019-06-20 13:48:25 -0600415 try:
416 return getattr(module, method_name)
417 except AttributeError as e:
Mike Frysinger6b5c3cd2019-08-27 16:51:00 -0400418 raise MethodNotFoundError(str(e))
Alex Klein146d4772019-06-20 13:48:25 -0600419
420
Tomasz Tylendab4292302021-08-08 18:59:36 +0900421def RegisterServices(router: Router):
Alex Klein146d4772019-06-20 13:48:25 -0600422 """Register all the services.
423
424 Args:
Tomasz Tylendab4292302021-08-08 18:59:36 +0900425 router: The router.
Alex Klein146d4772019-06-20 13:48:25 -0600426 """
Alex Klein4de25e82019-08-05 15:58:39 -0600427 router.Register(android_pb2)
Alex Klein54e38e32019-06-21 14:54:17 -0600428 router.Register(api_pb2)
Alex Klein146d4772019-06-20 13:48:25 -0600429 router.Register(artifacts_pb2)
430 router.Register(binhost_pb2)
431 router.Register(depgraph_pb2)
Jett Rink17ed0f52020-09-25 17:14:31 -0600432 router.Register(firmware_pb2)
Alex Klein146d4772019-06-20 13:48:25 -0600433 router.Register(image_pb2)
Alex Kleind4d9caa2021-11-10 15:44:52 -0700434 router.Register(metadata_pb2)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600435 router.Register(packages_pb2)
George Engelbrechtfe63c8c2019-08-31 22:51:29 -0600436 router.Register(payload_pb2)
Alex Klein146d4772019-06-20 13:48:25 -0600437 router.Register(sdk_pb2)
438 router.Register(sysroot_pb2)
439 router.Register(test_pb2)
Tiancong Wangaf050172019-07-10 11:52:03 -0700440 router.Register(toolchain_pb2)
Alex Klein146d4772019-06-20 13:48:25 -0600441 logging.debug('Services registered successfully.')
442
443
444def GetRouter():
445 """Get a router that has had all of the services registered."""
446 router = Router()
447 RegisterServices(router)
448
449 return router