blob: d449cead412844ed962a263b29d723aff8e46b0f [file] [log] [blame]
Keun Soo Yimb293fdb2016-09-21 16:03:44 -07001#!/usr/bin/env python
2#
3# Copyright 2016 - The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
Sam Chiu42ac7c52018-10-22 12:27:34 +080016r"""
17Welcome to
18 ___ _______ ____ __ _____
19 / _ |/ ___/ / / __ \/ / / / _ \
20 / __ / /__/ /__/ /_/ / /_/ / // /
21/_/ |_\___/____/\____/\____/____/
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070022
Sam Chiu42ac7c52018-10-22 12:27:34 +080023
24This a tool to create Android Virtual Devices locally/remotely.
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070025
26- Prerequisites:
Sam Chiu42ac7c52018-10-22 12:27:34 +080027 The manual will be available at
28 https://android.googlesource.com/platform/tools/acloud/+/master/README.md
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070029
Sam Chiu42ac7c52018-10-22 12:27:34 +080030- To get started:
31 - Create instances:
32 1) To create a remote cuttlefish instance with the local built image.
33 Example:
34 $ acloud create --local_image /tmp/image_dir
35 2) To create a local cuttlefish instance using the image which has been
36 built out in your workspace.
37 Example:
38 $ acloud create --local-instance --local-image
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070039
Sam Chiu42ac7c52018-10-22 12:27:34 +080040 - Delete instances:
41 $ acloud delete
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070042
Sam Chiu42ac7c52018-10-22 12:27:34 +080043Try $acloud [cmd] --help for further details.
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070044
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070045"""
46import argparse
47import getpass
48import logging
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070049import sys
50
Kevin Chengf4137c62018-05-22 16:06:58 -070051# Needed to silence oauth2client.
Sam Chiu29d858f2018-08-14 20:06:25 +080052# This is a workaround to get rid of below warning message:
53# 'No handlers could be found for logger "oauth2client.contrib.multistore_file'
54# TODO(b/112803893): Remove this code once bug is fixed.
55OAUTH2_LOGGER = logging.getLogger('oauth2client.contrib.multistore_file')
56OAUTH2_LOGGER.setLevel(logging.CRITICAL)
57OAUTH2_LOGGER.addHandler(logging.FileHandler("/dev/null"))
Kevin Chengb5963882018-05-09 00:06:27 -070058
Kevin Chengf4137c62018-05-22 16:06:58 -070059# pylint: disable=wrong-import-position
Kevin Cheng6001db32018-10-23 12:34:20 -070060from acloud.create import create
61from acloud.create import create_args
62from acloud.delete import delete
63from acloud.delete import delete_args
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070064from acloud.internal import constants
Kevin Cheng6001db32018-10-23 12:34:20 -070065from acloud.metrics import metrics
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070066from acloud.public import acloud_common
67from acloud.public import config
68from acloud.public import device_driver
69from acloud.public import errors
Kevin Chengb5963882018-05-09 00:06:27 -070070from acloud.public.actions import create_cuttlefish_action
71from acloud.public.actions import create_goldfish_action
Kevin Chengee6030f2018-06-26 10:55:30 -070072from acloud.setup import setup
73from acloud.setup import setup_args
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070074
Sam Chiu445941f2018-10-04 11:54:40 +080075LOGGING_FMT = "%(asctime)s |%(levelname)s| %(module)s:%(lineno)s| %(message)s"
Sam Chiu29d858f2018-08-14 20:06:25 +080076ACLOUD_LOGGER = "acloud"
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070077
78# Commands
Kevin Chengb5963882018-05-09 00:06:27 -070079CMD_CREATE_CUTTLEFISH = "create_cf"
80CMD_CREATE_GOLDFISH = "create_gf"
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070081CMD_DELETE = "delete"
82CMD_CLEANUP = "cleanup"
Fang Deng69498c32017-03-02 14:29:30 -080083CMD_SSHKEY = "project_sshkey"
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070084
85
Kevin Cheng3031f8a2018-05-16 13:21:51 -070086# pylint: disable=too-many-statements
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070087def _ParseArgs(args):
88 """Parse args.
89
90 Args:
91 args: Argument list passed from main.
92
93 Returns:
94 Parsed args.
95 """
Kevin Cheng3031f8a2018-05-16 13:21:51 -070096 usage = ",".join([
Sam Chiue669ef72018-10-16 16:23:37 +080097 setup_args.CMD_SETUP,
98 create_args.CMD_CREATE,
Kevin Chengab0b36b2018-08-02 14:38:30 -070099 CMD_CREATE_CUTTLEFISH,
100 CMD_CREATE_GOLDFISH,
Kevin Chengeb85e862018-10-09 15:35:13 -0700101 delete_args.CMD_DELETE,
Kevin Cheng3031f8a2018-05-16 13:21:51 -0700102 ])
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700103 parser = argparse.ArgumentParser(
104 description=__doc__,
105 formatter_class=argparse.RawDescriptionHelpFormatter,
Sam Chiu42ac7c52018-10-22 12:27:34 +0800106 usage="acloud {" + usage + "} ...")
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700107 subparsers = parser.add_subparsers()
108 subparser_list = []
109
Kevin Chengb5963882018-05-09 00:06:27 -0700110 # Command "create_cf", create cuttlefish instances
111 create_cf_parser = subparsers.add_parser(CMD_CREATE_CUTTLEFISH)
112 create_cf_parser.required = False
113 create_cf_parser.set_defaults(which=CMD_CREATE_CUTTLEFISH)
114 create_cf_parser.add_argument(
115 "--build_target",
116 type=str,
117 dest="build_target",
118 help="Android build target, should be a cuttlefish target name.")
119 create_cf_parser.add_argument(
120 "--branch",
121 type=str,
122 dest="branch",
123 help="Android branch, e.g. git_master")
124 create_cf_parser.add_argument(
125 "--build_id",
126 type=str,
127 dest="build_id",
128 help="Android build id, e.g. 2145099, P2804227")
129 create_cf_parser.add_argument(
130 "--kernel_build_id",
131 type=str,
132 dest="kernel_build_id",
133 required=False,
134 help="Android kernel build id, e.g. 4586590. This is to test a new"
135 " kernel build with a particular Android build (--build_id). If not"
136 " specified, the kernel that's bundled with the Android build would"
137 " be used.")
Kevin Chengb5963882018-05-09 00:06:27 -0700138
Kevin Cheng3087af52018-08-13 13:26:50 -0700139 create_args.AddCommonCreateArgs(create_cf_parser)
Kevin Chengb5963882018-05-09 00:06:27 -0700140 subparser_list.append(create_cf_parser)
141
142 # Command "create_gf", create goldfish instances
143 # In order to create a goldfish device we need the following parameters:
144 # 1. The emulator build we wish to use, this is the binary that emulates
145 # an android device. See go/emu-dev for more
146 # 2. A system-image. This is the android release we wish to run on the
147 # emulated hardware.
148 create_gf_parser = subparsers.add_parser(CMD_CREATE_GOLDFISH)
149 create_gf_parser.required = False
150 create_gf_parser.set_defaults(which=CMD_CREATE_GOLDFISH)
151 create_gf_parser.add_argument(
152 "--build_target",
153 type=str,
154 dest="build_target",
155 help="Android build target, should be a goldfish target name.")
156 create_gf_parser.add_argument(
157 "--branch",
158 type=str,
159 dest="branch",
160 help="Android branch, e.g. git_master")
161 create_gf_parser.add_argument(
162 "--build_id",
163 type=str,
164 dest="build_id",
165 help="Android build id, e.g. 4669424, P2804227")
166 create_gf_parser.add_argument(
167 "--emulator_build_id",
168 type=str,
169 dest="emulator_build_id",
170 required=False,
171 help="Emulator build used to run the images. e.g. 4669466.")
172 create_gf_parser.add_argument(
173 "--gpu",
174 type=str,
175 dest="gpu",
176 required=False,
177 default=None,
178 help="GPU accelerator to use if any."
179 " e.g. nvidia-tesla-k80, omit to use swiftshader")
180 create_gf_parser.add_argument(
Kevin Chengbced4af2018-06-26 10:35:01 -0700181 "--base_image",
182 type=str,
183 dest="base_image",
184 required=False,
185 help="Name of the goldfish base image to be used to create the instance. "
186 "This will override stable_goldfish_host_image_name from config. "
187 "e.g. emu-dev-cts-061118")
Kevin Chengb5963882018-05-09 00:06:27 -0700188
Kevin Cheng3087af52018-08-13 13:26:50 -0700189 create_args.AddCommonCreateArgs(create_gf_parser)
Kevin Chengb5963882018-05-09 00:06:27 -0700190 subparser_list.append(create_gf_parser)
191
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700192 # Command "cleanup"
193 cleanup_parser = subparsers.add_parser(CMD_CLEANUP)
194 cleanup_parser.required = False
195 cleanup_parser.set_defaults(which=CMD_CLEANUP)
196 cleanup_parser.add_argument(
197 "--expiration_mins",
198 type=int,
199 dest="expiration_mins",
200 required=True,
201 help="Garbage collect all gce instances, gce images, cached disk "
202 "images that are older than |expiration_mins|.")
203 subparser_list.append(cleanup_parser)
204
Fang Deng69498c32017-03-02 14:29:30 -0800205 # Command "project_sshkey"
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700206 sshkey_parser = subparsers.add_parser(CMD_SSHKEY)
207 sshkey_parser.required = False
208 sshkey_parser.set_defaults(which=CMD_SSHKEY)
209 sshkey_parser.add_argument(
210 "--user",
211 type=str,
212 dest="user",
213 default=getpass.getuser(),
214 help="The user name which the sshkey belongs to, default to: %s." %
215 getpass.getuser())
216 sshkey_parser.add_argument(
217 "--ssh_rsa_path",
218 type=str,
219 dest="ssh_rsa_path",
220 required=True,
Fang Deng69498c32017-03-02 14:29:30 -0800221 help="Absolute path to the file that contains the public rsa key "
Kevin Cheng3031f8a2018-05-16 13:21:51 -0700222 "that will be added as project-wide ssh key.")
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700223 subparser_list.append(sshkey_parser)
224
Kevin Chengeb85e862018-10-09 15:35:13 -0700225 # Command "create"
226 subparser_list.append(create_args.GetCreateArgParser(subparsers))
227
Kevin Chengee6030f2018-06-26 10:55:30 -0700228 # Command "setup"
229 subparser_list.append(setup_args.GetSetupArgParser(subparsers))
230
Kevin Chengeb85e862018-10-09 15:35:13 -0700231 # Command "Delete"
232 subparser_list.append(delete_args.GetDeleteArgParser(subparsers))
233
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700234 # Add common arguments.
Kevin Chengb21d7712018-05-24 14:54:55 -0700235 for subparser in subparser_list:
236 acloud_common.AddCommonArguments(subparser)
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700237
238 return parser.parse_args(args)
239
240
herbertxueb617e8a2018-08-22 10:02:19 +0800241# TODO(b/112803893): Delete this method once the new create method has been completed.
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700242def _TranslateAlias(parsed_args):
243 """Translate alias to Launch Control compatible values.
244
245 This method translates alias to Launch Control compatible values.
246 - branch: "git_" prefix will be added if branch name doesn't have it.
247 - build_target: For example, "phone" will be translated to full target
248 name "git_x86_phone-userdebug",
249
250 Args:
251 parsed_args: Parsed args.
252
253 Returns:
254 Parsed args with its values being translated.
255 """
Kevin Cheng3087af52018-08-13 13:26:50 -0700256 if parsed_args.which == create_args.CMD_CREATE:
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700257 if (parsed_args.branch and
258 not parsed_args.branch.startswith(constants.BRANCH_PREFIX)):
259 parsed_args.branch = constants.BRANCH_PREFIX + parsed_args.branch
260 parsed_args.build_target = constants.BUILD_TARGET_MAPPING.get(
261 parsed_args.build_target, parsed_args.build_target)
262 return parsed_args
263
264
herbertxue2625b042018-08-16 23:28:20 +0800265# pylint: disable=too-many-branches
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700266def _VerifyArgs(parsed_args):
267 """Verify args.
268
269 Args:
270 parsed_args: Parsed args.
271
272 Raises:
273 errors.CommandArgError: If args are invalid.
274 """
herbertxue2625b042018-08-16 23:28:20 +0800275 if parsed_args.which == create_args.CMD_CREATE:
276 create_args.VerifyArgs(parsed_args)
277
Kevin Cheng3087af52018-08-13 13:26:50 -0700278 if (parsed_args.which == create_args.CMD_CREATE
279 and parsed_args.avd_type == constants.TYPE_GCE):
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700280 if (parsed_args.spec and parsed_args.spec not in constants.SPEC_NAMES):
281 raise errors.CommandArgError(
282 "%s is not valid. Choose from: %s" %
283 (parsed_args.spec, ", ".join(constants.SPEC_NAMES)))
Kevin Cheng3031f8a2018-05-16 13:21:51 -0700284 if not ((parsed_args.build_id and parsed_args.build_target)
285 or parsed_args.gce_image or parsed_args.local_disk_image):
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700286 raise errors.CommandArgError(
287 "At least one of the following should be specified: "
288 "--build_id and --build_target, or --gce_image, or "
289 "--local_disk_image.")
290 if bool(parsed_args.build_id) != bool(parsed_args.build_target):
291 raise errors.CommandArgError(
292 "Must specify --build_id and --build_target at the same time.")
Kevin Chengb5963882018-05-09 00:06:27 -0700293
Kevin Cheng84d3eed2018-08-16 15:16:00 -0700294 if parsed_args.which == CMD_CREATE_CUTTLEFISH:
Kevin Chengb5963882018-05-09 00:06:27 -0700295 if not parsed_args.build_id or not parsed_args.build_target:
Kevin Cheng3031f8a2018-05-16 13:21:51 -0700296 raise errors.CommandArgError(
297 "Must specify --build_id and --build_target")
Kevin Chengb5963882018-05-09 00:06:27 -0700298
299 if parsed_args.which == CMD_CREATE_GOLDFISH:
Kevin Cheng84d3eed2018-08-16 15:16:00 -0700300 if not parsed_args.emulator_build_id and not parsed_args.build_id:
301 raise errors.CommandArgError("Must specify either "
302 "--emulator_build_id or --build_id")
303 if not parsed_args.build_target:
304 raise errors.CommandArgError("Must specify --build_target")
Kevin Chengb5963882018-05-09 00:06:27 -0700305
306 if parsed_args.which in [
Kevin Cheng3087af52018-08-13 13:26:50 -0700307 create_args.CMD_CREATE, CMD_CREATE_CUTTLEFISH, CMD_CREATE_GOLDFISH
Kevin Chengb5963882018-05-09 00:06:27 -0700308 ]:
Kevin Cheng3031f8a2018-05-16 13:21:51 -0700309 if (parsed_args.serial_log_file
310 and not parsed_args.serial_log_file.endswith(".tar.gz")):
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700311 raise errors.CommandArgError(
312 "--serial_log_file must ends with .tar.gz")
Kevin Cheng3031f8a2018-05-16 13:21:51 -0700313 if (parsed_args.logcat_file
314 and not parsed_args.logcat_file.endswith(".tar.gz")):
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700315 raise errors.CommandArgError(
316 "--logcat_file must ends with .tar.gz")
317
318
Sam Chiu29d858f2018-08-14 20:06:25 +0800319def _SetupLogging(log_file, verbose):
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700320 """Setup logging.
321
Sam Chiu29d858f2018-08-14 20:06:25 +0800322 This function define the logging policy in below manners.
323 - without -v , -vv ,--log_file:
324 Only display critical log and print() message on screen.
325
326 - with -v:
327 Display INFO log and set StreamHandler to acloud parent logger to turn on
328 ONLY acloud modules logging.(silence all 3p libraries)
329
330 - with -vv:
331 Display INFO/DEBUG log and set StreamHandler to root logger to turn on all
332 acloud modules and 3p libraries logging.
333
334 - with --log_file.
335 Dump logs to FileHandler with DEBUG level.
336
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700337 Args:
Sam Chiu29d858f2018-08-14 20:06:25 +0800338 log_file: String, if not None, dump the log to log file.
339 verbose: Int, if verbose = 1(-v), log at INFO level and turn on
340 logging on libraries to a StreamHandler.
341 If verbose = 2(-vv), log at DEBUG level and turn on logging on
342 all libraries and 3rd party libraries to a StreamHandler.
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700343 """
Sam Chiu29d858f2018-08-14 20:06:25 +0800344 # Define logging level and hierarchy by verbosity.
345 shandler_level = None
346 logger = None
347 if verbose == 0:
348 shandler_level = logging.CRITICAL
349 logger = logging.getLogger(ACLOUD_LOGGER)
350 elif verbose == 1:
351 shandler_level = logging.INFO
352 logger = logging.getLogger(ACLOUD_LOGGER)
353 elif verbose > 1:
354 shandler_level = logging.DEBUG
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700355 logger = logging.getLogger()
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700356
Sam Chiu29d858f2018-08-14 20:06:25 +0800357 # Add StreamHandler by default.
358 shandler = logging.StreamHandler()
359 shandler.setFormatter(logging.Formatter(LOGGING_FMT))
360 shandler.setLevel(shandler_level)
361 logger.addHandler(shandler)
362 # Set the default level to DEBUG, the other handlers will handle
363 # their own levels via the args supplied (-v and --log_file).
364 logger.setLevel(logging.DEBUG)
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700365
Sam Chiu29d858f2018-08-14 20:06:25 +0800366 # Add FileHandler if log_file is provided.
Sam Chiufde41e92018-08-07 18:37:02 +0800367 if log_file:
Sam Chiu29d858f2018-08-14 20:06:25 +0800368 fhandler = logging.FileHandler(filename=log_file)
369 fhandler.setFormatter(logging.Formatter(LOGGING_FMT))
370 fhandler.setLevel(logging.DEBUG)
371 logger.addHandler(fhandler)
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700372
373
374def main(argv):
375 """Main entry.
376
377 Args:
378 argv: A list of system arguments.
379
380 Returns:
381 0 if success. None-zero if fails.
382 """
383 args = _ParseArgs(argv)
Sam Chiu29d858f2018-08-14 20:06:25 +0800384 _SetupLogging(args.log_file, args.verbose)
herbertxueb617e8a2018-08-22 10:02:19 +0800385 # Translation of the branch will happen in AvdSpec(), skip it for now.
386 #args = _TranslateAlias(args)
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700387 _VerifyArgs(args)
388
Sam Chiuc64f3432018-08-17 11:19:06 +0800389 cfg = config.GetAcloudConfig(args)
Kevin Cheng3087af52018-08-13 13:26:50 -0700390 # TODO: Move this check into the functions it is actually needed.
Fang Dengcef4b112017-03-02 11:20:17 -0800391 # Check access.
Kevin Cheng3087af52018-08-13 13:26:50 -0700392 # device_driver.CheckAccess(cfg)
Fang Dengcef4b112017-03-02 11:20:17 -0800393
Kevin Cheng6001db32018-10-23 12:34:20 -0700394 metrics.LogUsage()
Kevin Chengee6030f2018-06-26 10:55:30 -0700395 report = None
Kevin Cheng3087af52018-08-13 13:26:50 -0700396 if (args.which == create_args.CMD_CREATE
397 and args.avd_type == constants.TYPE_GCE):
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700398 report = device_driver.CreateAndroidVirtualDevices(
399 cfg,
400 args.build_target,
401 args.build_id,
402 args.num,
403 args.gce_image,
404 args.local_disk_image,
405 cleanup=not args.no_cleanup,
406 serial_log_file=args.serial_log_file,
Kevin Chengb5963882018-05-09 00:06:27 -0700407 logcat_file=args.logcat_file,
Kevin Cheng86d43c72018-08-30 10:59:14 -0700408 autoconnect=args.autoconnect,
409 report_internal_ip=args.report_internal_ip)
Kevin Cheng3087af52018-08-13 13:26:50 -0700410 elif args.which == create_args.CMD_CREATE:
Kevin Chengc3d0d5e2018-08-14 14:22:44 -0700411 create.Run(args)
Kevin Chengb5963882018-05-09 00:06:27 -0700412 elif args.which == CMD_CREATE_CUTTLEFISH:
413 report = create_cuttlefish_action.CreateDevices(
414 cfg=cfg,
415 build_target=args.build_target,
416 build_id=args.build_id,
417 kernel_build_id=args.kernel_build_id,
418 num=args.num,
419 serial_log_file=args.serial_log_file,
420 logcat_file=args.logcat_file,
Kevin Cheng86d43c72018-08-30 10:59:14 -0700421 autoconnect=args.autoconnect,
422 report_internal_ip=args.report_internal_ip)
Kevin Chengb5963882018-05-09 00:06:27 -0700423 elif args.which == CMD_CREATE_GOLDFISH:
424 report = create_goldfish_action.CreateDevices(
425 cfg=cfg,
426 build_target=args.build_target,
427 build_id=args.build_id,
428 emulator_build_id=args.emulator_build_id,
429 gpu=args.gpu,
430 num=args.num,
431 serial_log_file=args.serial_log_file,
432 logcat_file=args.logcat_file,
Kevin Cheng84d3eed2018-08-16 15:16:00 -0700433 autoconnect=args.autoconnect,
Kevin Cheng86d43c72018-08-30 10:59:14 -0700434 branch=args.branch,
435 report_internal_ip=args.report_internal_ip)
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700436 elif args.which == CMD_DELETE:
Kevin Chengeb85e862018-10-09 15:35:13 -0700437 report = delete.Run(args)
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700438 elif args.which == CMD_CLEANUP:
439 report = device_driver.Cleanup(cfg, args.expiration_mins)
440 elif args.which == CMD_SSHKEY:
441 report = device_driver.AddSshRsa(cfg, args.user, args.ssh_rsa_path)
Kevin Chengee6030f2018-06-26 10:55:30 -0700442 elif args.which == setup_args.CMD_SETUP:
herbertxue34776bb2018-07-03 21:57:48 +0800443 setup.Run(args)
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700444 else:
445 sys.stderr.write("Invalid command %s" % args.which)
446 return 2
447
Kevin Chengee6030f2018-06-26 10:55:30 -0700448 if report:
449 report.Dump(args.report_file)
450 if report.errors:
451 msg = "\n".join(report.errors)
452 sys.stderr.write("Encountered the following errors:\n%s\n" % msg)
453 return 1
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700454 return 0
Tri Vo8e292532016-10-01 16:55:51 -0700455
456
457if __name__ == "__main__":
458 main(sys.argv[1:])