xref: /aosp_15_r20/external/autotest/site_utils/deployment/cmdparse.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li# Copyright 2015 The Chromium OS Authors. All rights reserved.
2*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
3*9c5db199SXin Li# found in the LICENSE file.
4*9c5db199SXin Li
5*9c5db199SXin Li"""Command-line parsing for the DUT deployment tool.
6*9c5db199SXin Li
7*9c5db199SXin LiThis contains parsing for the legacy `repair_test` and `deployment_test`
8*9c5db199SXin Licommands, and for the new `deploy` command.
9*9c5db199SXin Li
10*9c5db199SXin LiThe syntax for the two legacy commands is identical; the difference in
11*9c5db199SXin Lithe two commands is merely slightly different default options.
12*9c5db199SXin Li
13*9c5db199SXin LiThe full deployment flow performs all of the following actions:
14*9c5db199SXin Li  * Stage the USB image:  Install the DUT's assigned repair image onto
15*9c5db199SXin Li    the Servo USB stick.
16*9c5db199SXin Li  * Install firmware:  Boot the DUT from the USB stick, and run
17*9c5db199SXin Li    `chromeos-firmwareupdate` to install dev-signed RO and RW firmware.
18*9c5db199SXin Li    The DUT must begin in dev-mode, with hardware write-protect
19*9c5db199SXin Li    disabled.  At successful completion, the DUT is in verified boot
20*9c5db199SXin Li    mode.
21*9c5db199SXin Li  * Install test image:  Boot the DUT in recovery mode from the USB
22*9c5db199SXin Li    stick, and run `chromeos-install` to install the OS.
23*9c5db199SXin Li
24*9c5db199SXin LiThe new `deploy` command chooses particular combinations of the steps
25*9c5db199SXin Liabove based on a subcommand and options:
26*9c5db199SXin Li    `deploy servo`:  Only stage the USB image.
27*9c5db199SXin Li    `deploy firmware`:  Install both the firmware and the test image,
28*9c5db199SXin Li        in that order.  Optionally, first stage the USB image.
29*9c5db199SXin Li    `deploy test-image`: Install the test image.  Optionally, first
30*9c5db199SXin Li        stage the USB image.
31*9c5db199SXin Li    `deploy repair`:  Equivalent to `deploy test-image`, except that
32*9c5db199SXin Li        by default it doesn't upload its logs to storage.
33*9c5db199SXin Li
34*9c5db199SXin LiThis module exports two functions, `parse_deprecated_command()` (for the
35*9c5db199SXin Litwo legacy commands) and `parse_command()` (for the new `deploy`
36*9c5db199SXin Licommand).  Although the functions parse slightly different syntaxes,
37*9c5db199SXin Lithey return `argparse.Namespace` objects with identical fields, described
38*9c5db199SXin Libelow.
39*9c5db199SXin Li
40*9c5db199SXin LiThe following fields represent parameter inputs to the underlying
41*9c5db199SXin Lideployment:
42*9c5db199SXin Li    `web`:  Server name (or URL) for the AFE RPC service.
43*9c5db199SXin Li    `logdir`:  The directory where logs are to be stored.
44*9c5db199SXin Li    `board`:  Specifies the board to be used when creating DUTs.
45*9c5db199SXin Li    `build`:  When provided, the repair image assigned to the board for
46*9c5db199SXin Li        the target DUT will be updated to this value prior to staging
47*9c5db199SXin Li        USB image.  The build is in a form like 'R66-10447.0.0'.
48*9c5db199SXin Li    `hostname_file`:  Name of a file in CSV format with information
49*9c5db199SXin Li        about the hosts and servos to be deployed/repaired.
50*9c5db199SXin Li    `hostnames`:  List of DUT host names.
51*9c5db199SXin Li
52*9c5db199SXin LiThe following fields specify options that are used to enable or disable
53*9c5db199SXin Lispecific deployment steps:
54*9c5db199SXin Li    `upload`:  When true, logs will be uploaded to googlestorage after
55*9c5db199SXin Li        the command completes.
56*9c5db199SXin Li    `dry_run`:  When true, disables operations with any kind of
57*9c5db199SXin Li        side-effect.  This option implicitly overrides and disables all
58*9c5db199SXin Li        of the deployment steps below.
59*9c5db199SXin Li    `stageusb`:  When true, enable staging the USB image.  Disabling
60*9c5db199SXin Li        this will speed up operations when the stick is known to already
61*9c5db199SXin Li        have the proper image.
62*9c5db199SXin Li    `install_firmware`:  When true, enable firmware installation.
63*9c5db199SXin Li    `install_test_image`:  When true, enable installing the test image via
64*9c5db199SXin Li     send ctrl_u to boot into USB, which only apply to initial DUT deployment.
65*9c5db199SXin Li    `reinstall test image`: when true, enable installing test image through
66*9c5db199SXin Li     recover mode.
67*9c5db199SXin Li     `labstation`: when true, deploy labstation instead of DUT.
68*9c5db199SXin Li
69*9c5db199SXin LiThe `dry_run` option is off by default.  The `upload` option is on by
70*9c5db199SXin Lidefault, except for `deploy repair` and `repair_test`.  The values for
71*9c5db199SXin Liall other options are determined by the subcommand.
72*9c5db199SXin Li"""
73*9c5db199SXin Li
74*9c5db199SXin Liimport argparse
75*9c5db199SXin Liimport os
76*9c5db199SXin Li
77*9c5db199SXin Li
78*9c5db199SXin Liclass _ArgumentParser(argparse.ArgumentParser):
79*9c5db199SXin Li    """`argparse.ArgumentParser` extended with boolean option pairs."""
80*9c5db199SXin Li
81*9c5db199SXin Li    def add_boolean_argument(self, name, default, **kwargs):
82*9c5db199SXin Li        """Add a pair of argument flags for a boolean option.
83*9c5db199SXin Li
84*9c5db199SXin Li        This add a pair of options, named `--<name>` and `--no<name>`.
85*9c5db199SXin Li        The actions of the two options are 'store_true' and
86*9c5db199SXin Li        'store_false', respectively, with the destination `<name>`.
87*9c5db199SXin Li
88*9c5db199SXin Li        If neither option is present on the command line, the default
89*9c5db199SXin Li        value for destination `<name>` is given by `default`.
90*9c5db199SXin Li
91*9c5db199SXin Li        The given `kwargs` may be any arguments accepted by
92*9c5db199SXin Li        `ArgumentParser.add_argument()`, except for `action` and `dest`.
93*9c5db199SXin Li
94*9c5db199SXin Li        @param name     The name of the boolean argument, used to
95*9c5db199SXin Li                        construct the option names and destination field
96*9c5db199SXin Li                        name.
97*9c5db199SXin Li        @param default  Default setting for the option when not present
98*9c5db199SXin Li                        on the command line.
99*9c5db199SXin Li        """
100*9c5db199SXin Li        exclusion_group = self.add_mutually_exclusive_group()
101*9c5db199SXin Li        exclusion_group.add_argument('--%s' % name, action='store_true',
102*9c5db199SXin Li                                     dest=name, **kwargs)
103*9c5db199SXin Li        exclusion_group.add_argument('--no%s' % name, action='store_false',
104*9c5db199SXin Li                                     dest=name, **kwargs)
105*9c5db199SXin Li        self.set_defaults(**{name: bool(default)})
106*9c5db199SXin Li
107*9c5db199SXin Li
108*9c5db199SXin Lidef _add_common_options(parser):
109*9c5db199SXin Li    # frontend.AFE(server=None) will use the default web server,
110*9c5db199SXin Li    # so default for --web is `None`.
111*9c5db199SXin Li    parser.add_argument('-w', '--web', metavar='SERVER', default=None,
112*9c5db199SXin Li                        help='specify web server')
113*9c5db199SXin Li    parser.add_argument('-d', '--dir', dest='logdir',
114*9c5db199SXin Li                        help='directory for logs')
115*9c5db199SXin Li    parser.add_argument('-n', '--dry-run', action='store_true',
116*9c5db199SXin Li                        help='apply no changes, install nothing')
117*9c5db199SXin Li    parser.add_argument('-i', '--build',
118*9c5db199SXin Li                        help='select stable test build version')
119*9c5db199SXin Li    parser.add_argument('-f', '--hostname_file',
120*9c5db199SXin Li                        help='CSV file that contains a list of hostnames and '
121*9c5db199SXin Li                             'their details to install with.')
122*9c5db199SXin Li
123*9c5db199SXin Li
124*9c5db199SXin Lidef _add_upload_option(parser, default):
125*9c5db199SXin Li    """Add a boolean option for whether to upload logs.
126*9c5db199SXin Li
127*9c5db199SXin Li    @param parser   _ArgumentParser instance.
128*9c5db199SXin Li    @param default  Default option value.
129*9c5db199SXin Li    """
130*9c5db199SXin Li    parser.add_boolean_argument('upload', default,
131*9c5db199SXin Li                                help='whether to upload logs to GS bucket')
132*9c5db199SXin Li
133*9c5db199SXin Li
134*9c5db199SXin Lidef _add_subcommand(subcommands, name, upload_default, description):
135*9c5db199SXin Li    """Add a subcommand plus standard arguments to the `deploy` command.
136*9c5db199SXin Li
137*9c5db199SXin Li    This creates a new argument parser for a subcommand (as for
138*9c5db199SXin Li    `subcommands.add_parser()`).  The parser is populated with the
139*9c5db199SXin Li    standard arguments required by all `deploy` subcommands.
140*9c5db199SXin Li
141*9c5db199SXin Li    @param subcommands      Subcommand object as returned by
142*9c5db199SXin Li                            `ArgumentParser.add_subcommands`
143*9c5db199SXin Li    @param name             Name of the new subcommand.
144*9c5db199SXin Li    @param upload_default   Default setting for the `--upload` option.
145*9c5db199SXin Li    @param description      Description for the subcommand, for help text.
146*9c5db199SXin Li    @returns The argument parser for the new subcommand.
147*9c5db199SXin Li    """
148*9c5db199SXin Li    subparser = subcommands.add_parser(name, description=description)
149*9c5db199SXin Li    _add_common_options(subparser)
150*9c5db199SXin Li    _add_upload_option(subparser, upload_default)
151*9c5db199SXin Li    subparser.add_argument('-b', '--board', metavar='BOARD',
152*9c5db199SXin Li                           help='board for DUTs to be installed')
153*9c5db199SXin Li    subparser.add_argument('-m', '--model', metavar='MODEL',
154*9c5db199SXin Li                           help='model for DUTs to be installed.')
155*9c5db199SXin Li    subparser.add_argument('hostnames', nargs='*', metavar='HOSTNAME',
156*9c5db199SXin Li                           help='host names of DUTs to be installed')
157*9c5db199SXin Li    return subparser
158*9c5db199SXin Li
159*9c5db199SXin Li
160*9c5db199SXin Lidef _add_servo_subcommand(subcommands):
161*9c5db199SXin Li    """Add the `servo` subcommand to `subcommands`.
162*9c5db199SXin Li
163*9c5db199SXin Li    @param subcommands  Subcommand object as returned by
164*9c5db199SXin Li                        `ArgumentParser.add_subcommands`
165*9c5db199SXin Li    """
166*9c5db199SXin Li    subparser = _add_subcommand(
167*9c5db199SXin Li        subcommands, 'servo', True,
168*9c5db199SXin Li        'Test servo and install the image on the USB stick')
169*9c5db199SXin Li    subparser.set_defaults(stageusb=True,
170*9c5db199SXin Li                           labstation=False,
171*9c5db199SXin Li                           install_firmware=False,
172*9c5db199SXin Li                           install_test_image=False,
173*9c5db199SXin Li                           reinstall_test_image=False)
174*9c5db199SXin Li
175*9c5db199SXin Li
176*9c5db199SXin Lidef _add_stageusb_option(parser):
177*9c5db199SXin Li    """Add a boolean option for whether to stage an image to USB.
178*9c5db199SXin Li
179*9c5db199SXin Li    @param parser   _ArgumentParser instance.
180*9c5db199SXin Li    """
181*9c5db199SXin Li    parser.add_boolean_argument('stageusb', False,
182*9c5db199SXin Li                                help='Include USB stick setup')
183*9c5db199SXin Li
184*9c5db199SXin Li
185*9c5db199SXin Lidef _add_firmware_subcommand(subcommands):
186*9c5db199SXin Li    """Add the `firmware` subcommand to `subcommands`.
187*9c5db199SXin Li
188*9c5db199SXin Li    @param subcommands  Subcommand object as returned by
189*9c5db199SXin Li                        `ArgumentParser.add_subcommands`
190*9c5db199SXin Li    """
191*9c5db199SXin Li    subparser = _add_subcommand(
192*9c5db199SXin Li        subcommands, 'firmware', True,
193*9c5db199SXin Li        'Install firmware and initial test image on DUT')
194*9c5db199SXin Li    _add_stageusb_option(subparser)
195*9c5db199SXin Li    subparser.add_argument(
196*9c5db199SXin Li            '--using-servo', action='store_true',
197*9c5db199SXin Li            help='Flash DUT firmware directly using servo')
198*9c5db199SXin Li    subparser.set_defaults(labstation=False,
199*9c5db199SXin Li                           install_firmware=True,
200*9c5db199SXin Li                           install_test_image=True,
201*9c5db199SXin Li                           reinstall_test_image=False)
202*9c5db199SXin Li
203*9c5db199SXin Li
204*9c5db199SXin Lidef _add_test_image_subcommand(subcommands):
205*9c5db199SXin Li    """Add the `test-image` subcommand to `subcommands`.
206*9c5db199SXin Li
207*9c5db199SXin Li    @param subcommands  Subcommand object as returned by
208*9c5db199SXin Li                        `ArgumentParser.add_subcommands`
209*9c5db199SXin Li    """
210*9c5db199SXin Li    subparser = _add_subcommand(
211*9c5db199SXin Li        subcommands, 'test-image', True,
212*9c5db199SXin Li        'Install initial test image on DUT from servo')
213*9c5db199SXin Li    _add_stageusb_option(subparser)
214*9c5db199SXin Li    subparser.set_defaults(labstation=False,
215*9c5db199SXin Li                           install_firmware=False,
216*9c5db199SXin Li                           install_test_image=True,
217*9c5db199SXin Li                           reinstall_test_image=False)
218*9c5db199SXin Li
219*9c5db199SXin Li
220*9c5db199SXin Lidef _add_repair_subcommand(subcommands):
221*9c5db199SXin Li    """Add the `repair` subcommand to `subcommands`.
222*9c5db199SXin Li
223*9c5db199SXin Li    @param subcommands  Subcommand object as returned by
224*9c5db199SXin Li                        `ArgumentParser.add_subcommands`
225*9c5db199SXin Li    """
226*9c5db199SXin Li    subparser = _add_subcommand(
227*9c5db199SXin Li        subcommands, 'repair', False,
228*9c5db199SXin Li        'Re-install test image on DUT from servo')
229*9c5db199SXin Li    _add_stageusb_option(subparser)
230*9c5db199SXin Li    subparser.set_defaults(labstation=False,
231*9c5db199SXin Li                           install_firmware=False,
232*9c5db199SXin Li                           install_test_image=False,
233*9c5db199SXin Li                           reinstall_test_image=True)
234*9c5db199SXin Li
235*9c5db199SXin Li
236*9c5db199SXin Lidef _add_labstation_subcommand(subcommands):
237*9c5db199SXin Li    """Add the `labstation` subcommand to `subcommands`.
238*9c5db199SXin Li
239*9c5db199SXin Li    @param subcommands  Subcommand object as returned by
240*9c5db199SXin Li                        `ArgumentParser.add_subcommands`
241*9c5db199SXin Li    """
242*9c5db199SXin Li    subparser = _add_subcommand(
243*9c5db199SXin Li        subcommands, 'labstation', False,
244*9c5db199SXin Li        'Deploy a labstation to autotest, the labstation must be already'
245*9c5db199SXin Li        ' imaged with a labstation test image.')
246*9c5db199SXin Li    subparser.set_defaults(labstation=True,
247*9c5db199SXin Li                           install_firmware=False,
248*9c5db199SXin Li                           install_test_image=False,
249*9c5db199SXin Li                           reinstall_test_image=False)
250*9c5db199SXin Li
251*9c5db199SXin Li
252*9c5db199SXin Lidef parse_command(argv):
253*9c5db199SXin Li    """Parse arguments for the `deploy` command.
254*9c5db199SXin Li
255*9c5db199SXin Li    Create an argument parser for the `deploy` command and its
256*9c5db199SXin Li    subcommands.  Then parse the command line arguments, and return an
257*9c5db199SXin Li    `argparse.Namespace` object with the results.
258*9c5db199SXin Li
259*9c5db199SXin Li    @param argv         Standard command line argument vector;
260*9c5db199SXin Li                        argv[0] is assumed to be the command name.
261*9c5db199SXin Li    @return `Namespace` object with standard fields as described in the
262*9c5db199SXin Li            module docstring.
263*9c5db199SXin Li    """
264*9c5db199SXin Li    parser = _ArgumentParser(
265*9c5db199SXin Li            prog=os.path.basename(argv[0]),
266*9c5db199SXin Li            description='DUT deployment and repair operations')
267*9c5db199SXin Li    subcommands = parser.add_subparsers()
268*9c5db199SXin Li    _add_servo_subcommand(subcommands)
269*9c5db199SXin Li    _add_firmware_subcommand(subcommands)
270*9c5db199SXin Li    _add_test_image_subcommand(subcommands)
271*9c5db199SXin Li    _add_repair_subcommand(subcommands)
272*9c5db199SXin Li    _add_labstation_subcommand(subcommands)
273*9c5db199SXin Li    return parser.parse_args(argv[1:])
274