• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import argparse
2import ast
3import logging
4import os
5import shlex
6import sys
7
8
9class autoserv_parser(object):
10    """Custom command-line options parser for autoserv.
11
12    We can't use the general getopt methods here, as there will be unknown
13    extra arguments that we pass down into the control file instead.
14    Thus we process the arguments by hand, for which we are duly repentant.
15    Making a single function here just makes it harder to read. Suck it up.
16    """
17    def __init__(self):
18        self.args = sys.argv[1:]
19        self.parser = argparse.ArgumentParser(
20                usage='%(prog)s [options] [control-file]')
21        self.setup_options()
22
23        # parse an empty list of arguments in order to set self.options
24        # to default values so that codepaths that assume they are always
25        # reached from an autoserv process (when they actually are not)
26        # will still work
27        self.options = self.parser.parse_args(args=[])
28
29
30    def setup_options(self):
31        """Setup options to call autoserv command.
32        """
33        self.parser.add_argument('-m', action='store', type=str,
34                                 dest='machines',
35                                 help='list of machines')
36        self.parser.add_argument('-M', action='store', type=str,
37                                 dest='machines_file',
38                                 help='list of machines from file')
39        self.parser.add_argument('-c', action='store_true',
40                                 dest='client', default=False,
41                                 help='control file is client side')
42        self.parser.add_argument('-s', action='store_true',
43                                 dest='server', default=False,
44                                 help='control file is server side')
45        self.parser.add_argument('-r', action='store', type=str,
46                                 dest='results', default=None,
47                                 help='specify results directory')
48        self.parser.add_argument('-l', action='store', type=str,
49                                 dest='label', default='',
50                                 help='label for the job')
51        self.parser.add_argument('-G', action='store', type=str,
52                                 dest='group_name', default='',
53                                 help='The host_group_name to store in keyvals')
54        self.parser.add_argument('-u', action='store', type=str,
55                                 dest='user',
56                                 default=os.environ.get('USER'),
57                                 help='username for the job')
58        self.parser.add_argument('-P', action='store', type=str,
59                                 dest='parse_job',
60                                 default='',
61                                 help=('DEPRECATED.'
62                                       ' Use --execution-tag instead.'))
63        self.parser.add_argument('--execution-tag', action='store',
64                                 type=str, dest='execution_tag',
65                                 default='',
66                                 help=('Accessible in control files as job.tag;'
67                                       ' Defaults to the value passed to -P.'))
68        self.parser.add_argument('-v', action='store_true',
69                                 dest='verify', default=False,
70                                 help='verify the machines only')
71        self.parser.add_argument('-R', action='store_true',
72                                 dest='repair', default=False,
73                                 help='repair the machines')
74        self.parser.add_argument('-C', '--cleanup', action='store_true',
75                                 default=False,
76                                 help='cleanup all machines after the job')
77        self.parser.add_argument('--provision', action='store_true',
78                                 default=False,
79                                 help='Provision the machine.')
80        self.parser.add_argument('--job-labels', action='store',
81                                 help='Comma seperated job labels.')
82        self.parser.add_argument('-T', '--reset', action='store_true',
83                                 default=False,
84                                 help=('Reset (cleanup and verify) all machines'
85                                       ' after the job'))
86        self.parser.add_argument('-n', action='store_true',
87                                 dest='no_tee', default=False,
88                                 help='no teeing the status to stdout/err')
89        self.parser.add_argument('-N', action='store_true',
90                                 dest='no_logging', default=False,
91                                 help='no logging')
92        self.parser.add_argument('--verbose', action='store_true',
93                                 help=('Include DEBUG messages in console '
94                                       'output'))
95        self.parser.add_argument('--no_console_prefix', action='store_true',
96                                 help=('Disable the logging prefix on console '
97                                       'output'))
98        self.parser.add_argument('-p', '--write-pidfile', action='store_true',
99                                 dest='write_pidfile', default=False,
100                                 help=('write pidfile (pidfile name is '
101                                       'determined by --pidfile-label'))
102        self.parser.add_argument('--pidfile-label', action='store',
103                                 default='autoserv',
104                                 help=('Determines filename to use as pidfile '
105                                       '(if -p is specified). Pidfile will be '
106                                       '.<label>_execute. Default to '
107                                       'autoserv.'))
108        self.parser.add_argument('--use-existing-results', action='store_true',
109                                 help=('Indicates that autoserv is working with'
110                                       ' an existing results directory'))
111        self.parser.add_argument('-a', '--args', dest='args',
112                                 help='additional args to pass to control file')
113        self.parser.add_argument('--ssh-user', action='store',
114                                 type=str, dest='ssh_user', default='root',
115                                 help='specify the user for ssh connections')
116        self.parser.add_argument('--ssh-port', action='store',
117                                 type=int, dest='ssh_port', default=22,
118                                 help=('specify the port to use for ssh '
119                                       'connections'))
120        self.parser.add_argument('--ssh-pass', action='store',
121                                 type=str, dest='ssh_pass',
122                                 default='',
123                                 help=('specify the password to use for ssh '
124                                       'connections'))
125        self.parser.add_argument('--install-in-tmpdir', action='store_true',
126                                 dest='install_in_tmpdir', default=False,
127                                 help=('by default install autotest clients in '
128                                       'a temporary directory'))
129        self.parser.add_argument('--collect-crashinfo', action='store_true',
130                                 dest='collect_crashinfo', default=False,
131                                 help='just run crashinfo collection')
132        self.parser.add_argument('--control-filename', action='store',
133                                 type=str, default=None,
134                                 help=('filename to use for the server control '
135                                       'file in the results directory'))
136        self.parser.add_argument('--verify_job_repo_url', action='store_true',
137                                 dest='verify_job_repo_url', default=False,
138                                 help=('Verify that the job_repo_url of the '
139                                       'host has staged packages for the job.'))
140        self.parser.add_argument('--no_collect_crashinfo', action='store_true',
141                                 dest='skip_crash_collection', default=False,
142                                 help=('Turns off crash collection to shave '
143                                       'time off test runs.'))
144        self.parser.add_argument('--disable_sysinfo', action='store_true',
145                                 dest='disable_sysinfo', default=False,
146                                 help=('Turns off sysinfo collection to shave '
147                                       'time off test runs.'))
148        self.parser.add_argument('--ssh_verbosity', action='store',
149                                 dest='ssh_verbosity', default=0,
150                                 type=str, choices=['0', '1', '2', '3'],
151                                 help=('Verbosity level for ssh, between 0 '
152                                       'and 3 inclusive. '
153                                       '[default: %(default)s]'))
154        self.parser.add_argument('--ssh_options', action='store',
155                                 dest='ssh_options', default='',
156                                 help=('A string giving command line flags '
157                                       'that will be included in ssh commands'))
158        self.parser.add_argument('--require-ssp', action='store_true',
159                                 dest='require_ssp', default=False,
160                                 help=('Force the autoserv process to run with '
161                                       'server-side packaging'))
162        self.parser.add_argument('--no_use_packaging', action='store_true',
163                                 dest='no_use_packaging', default=False,
164                                 help=('Disable install modes that use the '
165                                       'packaging system.'))
166        self.parser.add_argument('--source_isolate', action='store',
167                                 type=str, default='',
168                                 dest='isolate',
169                                 help=('Hash for isolate containing build '
170                                       'contents needed for server-side '
171                                       'packaging. Takes precedence over '
172                                       'test_source_build, if present.'))
173        self.parser.add_argument('--test_source_build', action='store',
174                                 type=str, default='',
175                                 dest='test_source_build',
176                                 help=('Alternative build that contains the '
177                                       'test code for server-side packaging. '
178                                       'Default is to use the build on the '
179                                       'target DUT.'))
180        self.parser.add_argument('--parent_job_id', action='store',
181                                 type=str, default=None,
182                                 dest='parent_job_id',
183                                 help=('ID of the parent job. Default to None '
184                                       'if the job does not have a parent job'))
185        self.parser.add_argument('--host_attributes', action='store',
186                                 dest='host_attributes', default='{}',
187                                 help=('Host attribute to be applied to all '
188                                       'machines/hosts for this autoserv run. '
189                                       'Must be a string-encoded dict. '
190                                       'Example: {"key1":"value1", "key2":'
191                                       '"value2"}'))
192        self.parser.add_argument('--lab', action='store', type=str,
193                                 dest='lab', default='',
194                                 help=argparse.SUPPRESS)
195        self.parser.add_argument('--cloud_trace_context', type=str, default='',
196                                 action='store', dest='cloud_trace_context',
197                                 help=('Global trace context to configure '
198                                       'emission of data to Cloud Trace.'))
199        self.parser.add_argument('--cloud_trace_context_enabled', type=str,
200                                 default='False', action='store',
201                                 dest='cloud_trace_context_enabled',
202                                 help=('Global trace context to configure '
203                                       'emission of data to Cloud Trace.'))
204        self.parser.add_argument(
205                '--host-info-subdir',
206                default='host_info_store',
207                help='Optional path to a directory containing host '
208                     'information for the machines. The path is relative to '
209                     'the results directory (see -r) and must be inside '
210                     'the directory.'
211        )
212        self.parser.add_argument(
213                '--local-only-host-info',
214                default='False',
215                help='By default, host status are immediately reported back to '
216                     'the AFE, shadowing the updates to disk. This flag '
217                     'disables the AFE interaction completely, and assumes '
218                     'that initial host information is supplied to autoserv. '
219                     'See also: --host-info-subdir',
220        )
221        self.parser.add_argument(
222                '--control-name',
223                action='store',
224                help='NAME attribute of the control file to stage and run. '
225                     'This overrides the control file provided via the '
226                     'positional args.',
227        )
228
229        #
230        # Warning! Please read before adding any new arguments!
231        #
232        # New arguments will be ignored if a test runs with server-side
233        # packaging and if the test source build does not have the new
234        # arguments.
235        #
236        # New argument should NOT set action to `store_true`. A workaround is to
237        # use string value of `True` or `False`, then convert them to boolean in
238        # code.
239        # The reason is that parse_args will always ignore the argument name and
240        # value. An unknown argument without a value will lead to positional
241        # argument being removed unexpectedly.
242        #
243
244
245    def parse_args(self):
246        """Parse and process command line arguments.
247        """
248        # Positional arguments from the end of the command line will be included
249        # in the list of unknown_args.
250        self.options, unknown_args = self.parser.parse_known_args()
251        # Filter out none-positional arguments
252        removed_args = []
253        while unknown_args and unknown_args[0] and unknown_args[0][0] == '-':
254            removed_args.append(unknown_args.pop(0))
255            # Always assume the argument has a value.
256            if unknown_args:
257                removed_args.append(unknown_args.pop(0))
258        if removed_args:
259            logging.warn('Unknown arguments are removed from the options: %s',
260                         removed_args)
261
262        self.args = unknown_args + shlex.split(self.options.args or '')
263
264        self.options.host_attributes = ast.literal_eval(
265                self.options.host_attributes)
266        if self.options.lab and self.options.host_attributes:
267            logging.warn(
268                    '--lab and --host-attributes are mutually exclusive. '
269                    'Ignoring custom host attributes: %s',
270                    str(self.options.host_attributes))
271            self.options.host_attributes = []
272
273        self.options.local_only_host_info = _interpret_bool_arg(
274                self.options.local_only_host_info)
275        if not self.options.execution_tag:
276            self.options.execution_tag = self.options.parse_job
277
278
279def _interpret_bool_arg(value):
280    return value.lower() in {'yes', 'true'}
281
282
283# create the one and only one instance of autoserv_parser
284autoserv_parser = autoserv_parser()
285