blob: b7dee11b50ffadcc242a040369fd145cb09620f8 [file] [log] [blame]
Dan Shi888cfca2015-07-31 15:49:00 -07001import argparse
Simran Basi1bf60eb2015-12-01 16:39:29 -08002import ast
Dan Shi888cfca2015-07-31 15:49:00 -07003import logging
4import os
5import shlex
6import sys
Dan Shi07e09af2013-04-12 09:31:29 -07007
mblighb7dcc7f2008-06-02 19:34:25 +00008
Dan Shi888cfca2015-07-31 15:49:00 -07009class autoserv_parser(object):
jadmanski0afbb632008-06-06 21:10:57 +000010 """Custom command-line options parser for autoserv.
mblighb7dcc7f2008-06-02 19:34:25 +000011
jadmanski0afbb632008-06-06 21:10:57 +000012 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:]
Dan Shi888cfca2015-07-31 15:49:00 -070019 self.parser = argparse.ArgumentParser(
20 usage='%(prog)s [options] [control-file]')
jadmanski0afbb632008-06-06 21:10:57 +000021 self.setup_options()
mblighb7dcc7f2008-06-02 19:34:25 +000022
mblighf82a1822009-02-26 00:47:14 +000023 # 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
Dan Shi888cfca2015-07-31 15:49:00 -070027 self.options = self.parser.parse_args(args=[])
mblighf82a1822009-02-26 00:47:14 +000028
mblighb7dcc7f2008-06-02 19:34:25 +000029
jadmanski0afbb632008-06-06 21:10:57 +000030 def setup_options(self):
Dan Shi888cfca2015-07-31 15:49:00 -070031 """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='',
Prathmesh Prabhue0b70c62018-04-24 15:33:42 -070061 help=('DEPRECATED.'
62 ' Use --execution-tag instead.'))
Dan Shi888cfca2015-07-31 15:49:00 -070063 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.'))
Dan Shi888cfca2015-07-31 15:49:00 -070068 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')
Dan Shi888cfca2015-07-31 15:49:00 -0700113 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'))
Dan Shi888cfca2015-07-31 15:49:00 -0700136 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 '
Dan Shid7254862015-08-07 10:21:21 -0700152 'and 3 inclusive. '
153 '[default: %(default)s]'))
Dan Shi888cfca2015-07-31 15:49:00 -0700154 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'))
Dan Shi888cfca2015-07-31 15:49:00 -0700162 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.'))
Jacob Kopczynski9a3a0c32018-07-18 18:36:20 -0700166 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.'))
Dan Shi888cfca2015-07-31 15:49:00 -0700173 self.parser.add_argument('--test_source_build', action='store',
174 type=str, default='',
175 dest='test_source_build',
Richard Barnette71854c72018-03-30 14:22:09 -0700176 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.'))
Dan Shi888cfca2015-07-31 15:49:00 -0700180 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'))
Simran Basi1bf60eb2015-12-01 16:39:29 -0800185 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)
Paul Hobbse9fd5572017-08-22 02:48:25 -0700195 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.'))
Prathmesh Prabhu7fc39c52018-03-21 14:08:30 -0700204 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 )
Prathmesh Prabhu46047362018-03-16 10:33:19 -0700221 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
Dan Shi888cfca2015-07-31 15:49:00 -0700229 #
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 #
jadmanski0afbb632008-06-06 21:10:57 +0000243
244
245 def parse_args(self):
Dan Shi888cfca2015-07-31 15:49:00 -0700246 """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 = []
Allen Li498f57f2019-08-28 11:28:13 -0700253 while unknown_args and unknown_args[0] and unknown_args[0][0] == '-':
Dan Shi888cfca2015-07-31 15:49:00 -0700254 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)
mblighb7dcc7f2008-06-02 19:34:25 +0000261
Dan Shi888cfca2015-07-31 15:49:00 -0700262 self.args = unknown_args + shlex.split(self.options.args or '')
mblighb7dcc7f2008-06-02 19:34:25 +0000263
Simran Basi1bf60eb2015-12-01 16:39:29 -0800264 self.options.host_attributes = ast.literal_eval(
265 self.options.host_attributes)
Prathmesh Prabhucbeab122017-05-30 11:23:53 -0700266 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 = []
mblighb7dcc7f2008-06-02 19:34:25 +0000272
Prathmesh Prabhu7fc39c52018-03-21 14:08:30 -0700273 self.options.local_only_host_info = _interpret_bool_arg(
274 self.options.local_only_host_info)
Prathmesh Prabhue0b70c62018-04-24 15:33:42 -0700275 if not self.options.execution_tag:
276 self.options.execution_tag = self.options.parse_job
Prathmesh Prabhu7fc39c52018-03-21 14:08:30 -0700277
278
279def _interpret_bool_arg(value):
280 return value.lower() in {'yes', 'true'}
281
mblighb7dcc7f2008-06-02 19:34:25 +0000282
283# create the one and only one instance of autoserv_parser
284autoserv_parser = autoserv_parser()