blob: b7d8d94c581b065a02202828eaaff3c73b184b28 [file] [log] [blame]
Alex Kleinf4dc4f52018-12-05 13:55:12 -07001# Copyright 2018 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 Kleind815ca62020-01-10 12:21:30 -07005"""The Build API entry point."""
Alex Kleinf4dc4f52018-12-05 13:55:12 -07006
Chris McDonald59650c32021-07-20 15:29:28 -06007import logging
Alex Klein5bcb4d22019-03-21 13:51:54 -06008import os
Cindy Linc88eba32022-08-10 04:45:03 +00009import sys
Alex Kleind815ca62020-01-10 12:21:30 -070010
Alex Klein69339cc2019-07-22 14:08:35 -060011from chromite.api import api_config as api_config_lib
Alex Klein2008aee2019-08-20 16:25:27 -060012from chromite.api import controller
Alex Kleine191ed62020-02-27 15:59:55 -070013from chromite.api import message_util
Alex Klein146d4772019-06-20 13:48:25 -060014from chromite.api import router as router_lib
Alex Kleind815ca62020-01-10 12:21:30 -070015from chromite.api.gen.chromite.api import build_api_config_pb2
Alex Kleinf4dc4f52018-12-05 13:55:12 -070016from chromite.lib import commandline
Alex Klein2bfacb22019-02-04 11:42:17 -070017from chromite.lib import cros_build_lib
Cindy Linc88eba32022-08-10 04:45:03 +000018from chromite.lib import namespaces
Alex Klein00b1f1e2019-02-08 13:53:42 -070019from chromite.utils import matching
Alex Kleinf4dc4f52018-12-05 13:55:12 -070020
Mike Frysinger898265b2020-02-10 23:49:12 -050021
Alex Kleinf4dc4f52018-12-05 13:55:12 -070022def GetParser():
Alex Klein00b1f1e2019-02-08 13:53:42 -070023 """Build the argument parser."""
Alex Kleinf4dc4f52018-12-05 13:55:12 -070024 parser = commandline.ArgumentParser(description=__doc__)
25
Alex Kleind815ca62020-01-10 12:21:30 -070026 parser.add_argument(
Alex Klein2008aee2019-08-20 16:25:27 -060027 'service_method',
Alex Klein2008aee2019-08-20 16:25:27 -060028 help='The "chromite.api.Service/Method" that is being called.')
Alex Kleine191ed62020-02-27 15:59:55 -070029 # Input arguments.
30 input_args = parser.add_mutually_exclusive_group(required=True)
31 input_args.add_argument(
32 '--input-binary',
33 type='path',
34 help='Path to the protobuf binary serialization of the input message.')
35 input_args.add_argument(
Alex Klein2008aee2019-08-20 16:25:27 -060036 '--input-json',
37 type='path',
Alex Kleinf4dc4f52018-12-05 13:55:12 -070038 help='Path to the JSON serialized input argument protobuf message.')
Alex Kleine191ed62020-02-27 15:59:55 -070039 # Output options.
40 parser.add_argument(
41 '--output-binary',
42 type='path',
43 help='The path to which the protobuf binary serialization of the '
44 'response message should be written.')
Alex Kleind815ca62020-01-10 12:21:30 -070045 parser.add_argument(
Alex Klein2008aee2019-08-20 16:25:27 -060046 '--output-json',
47 type='path',
Alex Kleine191ed62020-02-27 15:59:55 -070048 help='The path to which the JSON serialization of the response message '
49 'should be written.')
50 # Config options.
51 config_args = parser.add_mutually_exclusive_group()
52 config_args.add_argument(
53 '--config-binary',
54 type='path',
55 help='The path to the protobuf binary serialization of the Build API '
56 'call configs.')
57 config_args.add_argument(
Alex Kleind815ca62020-01-10 12:21:30 -070058 '--config-json',
59 type='path',
Alex Kleine191ed62020-02-27 15:59:55 -070060 help='The path to the JSON encoded Build API call configs.')
Alex Klein2008aee2019-08-20 16:25:27 -060061
Alex Kleinf4dc4f52018-12-05 13:55:12 -070062 return parser
63
64
Alex Klein00b1f1e2019-02-08 13:53:42 -070065def _ParseArgs(argv, router):
Alex Kleinf4dc4f52018-12-05 13:55:12 -070066 """Parse and validate arguments."""
67 parser = GetParser()
Alex Klein7cc434f2019-12-17 14:58:57 -070068 opts, unknown = parser.parse_known_args(
69 argv, namespace=commandline.ArgumentNamespace())
70 parser.DoPostParseSetup(opts, unknown)
71
72 if unknown:
73 logging.warning('Unknown args ignored: %s', ' '.join(unknown))
Alex Kleinf4dc4f52018-12-05 13:55:12 -070074
Alex Klein00b1f1e2019-02-08 13:53:42 -070075 methods = router.ListMethods()
George Engelbrechtd3de8df2019-09-04 18:15:05 -060076
Alex Klein2008aee2019-08-20 16:25:27 -060077 # Positional service_method argument validation.
George Engelbrechtd3de8df2019-09-04 18:15:05 -060078 parts = opts.service_method.split('/')
79 if len(parts) != 2:
Alex Kleind815ca62020-01-10 12:21:30 -070080 parser.error('Invalid service/method specification format. It should be '
81 'something like chromite.api.SdkService/Create.')
George Engelbrechtd3de8df2019-09-04 18:15:05 -060082
Alex Klein00b1f1e2019-02-08 13:53:42 -070083 if opts.service_method not in methods:
Alex Klein00aa8072019-04-15 16:36:00 -060084 # Unknown method, try to match against known methods and make a suggestion.
Sloan Johnsona1c89eb2022-06-07 22:49:05 +000085 # This is just for developer assistance, e.g. misspellings when testing.
Alex Klein2008aee2019-08-20 16:25:27 -060086 matched = matching.GetMostLikelyMatchedObject(
87 methods, opts.service_method, matched_score_threshold=0.6)
Alex Klein00b1f1e2019-02-08 13:53:42 -070088 error = 'Unrecognized service name.'
89 if matched:
90 error += '\nDid you mean: \n%s' % '\n'.join(matched)
91 parser.error(error)
92
Alex Kleinf4dc4f52018-12-05 13:55:12 -070093 opts.service = parts[0]
94 opts.method = parts[1]
95
Alex Kleine191ed62020-02-27 15:59:55 -070096 # Input and output validation.
97 if not opts.output_binary and not opts.output_json:
98 parser.error('At least one output file must be specified.')
Alex Klein2008aee2019-08-20 16:25:27 -060099
Alex Kleine191ed62020-02-27 15:59:55 -0700100 if not os.path.exists(opts.input_binary or opts.input_json):
Alex Klein5bcb4d22019-03-21 13:51:54 -0600101 parser.error('Input file does not exist.')
102
Alex Kleind815ca62020-01-10 12:21:30 -0700103 config_msg = build_api_config_pb2.BuildApiConfig()
104 if opts.config_json:
Alex Kleine191ed62020-02-27 15:59:55 -0700105 handler = message_util.get_message_handler(opts.config_json,
106 message_util.FORMAT_JSON)
107 else:
108 handler = message_util.get_message_handler(opts.config_binary,
109 message_util.FORMAT_BINARY)
110
111 if opts.config_json or opts.config_binary:
112 # We have been given a config, so read it.
Alex Kleind815ca62020-01-10 12:21:30 -0700113 try:
Alex Kleine191ed62020-02-27 15:59:55 -0700114 handler.read_into(config_msg)
115 except message_util.Error as e:
116 parser.error(str(e))
Alex Kleind815ca62020-01-10 12:21:30 -0700117
118 opts.config = api_config_lib.build_config_from_proto(config_msg)
Alex Kleine191ed62020-02-27 15:59:55 -0700119 opts.config_handler = handler
Alex Klein69339cc2019-07-22 14:08:35 -0600120
Alex Kleinf4dc4f52018-12-05 13:55:12 -0700121 opts.Freeze()
122 return opts
123
124
Alex Kleine191ed62020-02-27 15:59:55 -0700125def _get_io_handlers(opts):
126 """Build the input and output handlers."""
127 if opts.input_binary:
128 input_handler = message_util.get_message_handler(opts.input_binary,
129 message_util.FORMAT_BINARY)
130 else:
131 input_handler = message_util.get_message_handler(opts.input_json,
132 message_util.FORMAT_JSON)
133
134 output_handlers = []
135 if opts.output_binary:
136 handler = message_util.get_message_handler(opts.output_binary,
137 message_util.FORMAT_BINARY)
138 output_handlers.append(handler)
139 if opts.output_json:
140 handler = message_util.get_message_handler(opts.output_json,
141 message_util.FORMAT_JSON)
142 output_handlers.append(handler)
143
144 return input_handler, output_handlers
145
146
Alex Kleinf4dc4f52018-12-05 13:55:12 -0700147def main(argv):
Mike Frysingerda928de2021-06-21 12:49:40 -0400148 router = router_lib.GetRouter()
149 opts = _ParseArgs(argv, router)
Alex Klein00b1f1e2019-02-08 13:53:42 -0700150
Cindy Linc88eba32022-08-10 04:45:03 +0000151 # For build_image, make sure we run with network disabled to prevent leakage.
152 if opts.service_method == 'chromite.api.ImageService/Create':
153 namespaces.ReExecuteWithNamespace(sys.argv)
154
Mike Frysingerda928de2021-06-21 12:49:40 -0400155 if opts.config.log_path:
156 logging.warning('Ignoring log_path config option')
157 if 'BUILD_API_TEE_LOG_FILE' in os.environ:
158 logging.warning('Ignoring $BUILD_API_TEE_LOG_FILE env var')
Alex Klein2008aee2019-08-20 16:25:27 -0600159
Mike Frysingerda928de2021-06-21 12:49:40 -0400160 if opts.config.mock_invalid:
161 # --mock-invalid handling. We print error messages, but no output is ever
162 # set for validation errors, so we can handle it by just giving back the
163 # correct return code here.
164 return controller.RETURN_CODE_INVALID_INPUT
Michael Mortensen3e86c1e2019-11-21 15:51:54 -0700165
Mike Frysingerda928de2021-06-21 12:49:40 -0400166 input_handler, output_handlers = _get_io_handlers(opts)
Alex Kleine191ed62020-02-27 15:59:55 -0700167
Mike Frysingerda928de2021-06-21 12:49:40 -0400168 try:
169 return router.Route(opts.service, opts.method, opts.config, input_handler,
170 output_handlers, opts.config_handler)
171 except router_lib.Error as e:
172 # Handle router_lib.Error derivatives nicely, but let anything else bubble
173 # up.
174 cros_build_lib.Die(e)