blob: 82f66891412dd116dcc9b53bedd1bda69e861f73 [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='',
61 help=('Parse the results of the job using this'
62 ' execution tag. Accessible in control '
63 'files as job.tag.'))
64 self.parser.add_argument('--execution-tag', action='store',
65 type=str, dest='execution_tag',
66 default='',
67 help=('Accessible in control files as job.tag;'
68 ' Defaults to the value passed to -P.'))
69 self.parser.add_argument('-i', action='store_true',
70 dest='install_before', default=False,
71 help=('reinstall machines before running the '
72 'job'))
73 self.parser.add_argument('-I', action='store_true',
74 dest='install_after', default=False,
75 help=('reinstall machines after running the '
76 'job'))
77 self.parser.add_argument('-v', action='store_true',
78 dest='verify', default=False,
79 help='verify the machines only')
80 self.parser.add_argument('-R', action='store_true',
81 dest='repair', default=False,
82 help='repair the machines')
83 self.parser.add_argument('-C', '--cleanup', action='store_true',
84 default=False,
85 help='cleanup all machines after the job')
86 self.parser.add_argument('--provision', action='store_true',
87 default=False,
88 help='Provision the machine.')
89 self.parser.add_argument('--job-labels', action='store',
90 help='Comma seperated job labels.')
91 self.parser.add_argument('-T', '--reset', action='store_true',
92 default=False,
93 help=('Reset (cleanup and verify) all machines'
94 ' after the job'))
95 self.parser.add_argument('-n', action='store_true',
96 dest='no_tee', default=False,
97 help='no teeing the status to stdout/err')
98 self.parser.add_argument('-N', action='store_true',
99 dest='no_logging', default=False,
100 help='no logging')
101 self.parser.add_argument('--verbose', action='store_true',
102 help=('Include DEBUG messages in console '
103 'output'))
104 self.parser.add_argument('--no_console_prefix', action='store_true',
105 help=('Disable the logging prefix on console '
106 'output'))
107 self.parser.add_argument('-p', '--write-pidfile', action='store_true',
108 dest='write_pidfile', default=False,
109 help=('write pidfile (pidfile name is '
110 'determined by --pidfile-label'))
111 self.parser.add_argument('--pidfile-label', action='store',
112 default='autoserv',
113 help=('Determines filename to use as pidfile '
114 '(if -p is specified). Pidfile will be '
115 '.<label>_execute. Default to '
116 'autoserv.'))
117 self.parser.add_argument('--use-existing-results', action='store_true',
118 help=('Indicates that autoserv is working with'
119 ' an existing results directory'))
120 self.parser.add_argument('-a', '--args', dest='args',
121 help='additional args to pass to control file')
Dan Shi888cfca2015-07-31 15:49:00 -0700122 self.parser.add_argument('--ssh-user', action='store',
123 type=str, dest='ssh_user', default='root',
124 help='specify the user for ssh connections')
125 self.parser.add_argument('--ssh-port', action='store',
126 type=int, dest='ssh_port', default=22,
127 help=('specify the port to use for ssh '
128 'connections'))
129 self.parser.add_argument('--ssh-pass', action='store',
130 type=str, dest='ssh_pass',
131 default='',
132 help=('specify the password to use for ssh '
133 'connections'))
134 self.parser.add_argument('--install-in-tmpdir', action='store_true',
135 dest='install_in_tmpdir', default=False,
136 help=('by default install autotest clients in '
137 'a temporary directory'))
138 self.parser.add_argument('--collect-crashinfo', action='store_true',
139 dest='collect_crashinfo', default=False,
140 help='just run crashinfo collection')
141 self.parser.add_argument('--control-filename', action='store',
142 type=str, default=None,
143 help=('filename to use for the server control '
144 'file in the results directory'))
145 self.parser.add_argument('--test-retry', action='store',
146 type=int, default=0,
147 help=('Num of times to retry a test that '
Dan Shid7254862015-08-07 10:21:21 -0700148 'failed [default: %(default)d]'))
Dan Shi888cfca2015-07-31 15:49:00 -0700149 self.parser.add_argument('--verify_job_repo_url', action='store_true',
150 dest='verify_job_repo_url', default=False,
151 help=('Verify that the job_repo_url of the '
152 'host has staged packages for the job.'))
153 self.parser.add_argument('--no_collect_crashinfo', action='store_true',
154 dest='skip_crash_collection', default=False,
155 help=('Turns off crash collection to shave '
156 'time off test runs.'))
157 self.parser.add_argument('--disable_sysinfo', action='store_true',
158 dest='disable_sysinfo', default=False,
159 help=('Turns off sysinfo collection to shave '
160 'time off test runs.'))
161 self.parser.add_argument('--ssh_verbosity', action='store',
162 dest='ssh_verbosity', default=0,
163 type=str, choices=['0', '1', '2', '3'],
164 help=('Verbosity level for ssh, between 0 '
Dan Shid7254862015-08-07 10:21:21 -0700165 'and 3 inclusive. '
166 '[default: %(default)s]'))
Dan Shi888cfca2015-07-31 15:49:00 -0700167 self.parser.add_argument('--ssh_options', action='store',
168 dest='ssh_options', default='',
169 help=('A string giving command line flags '
170 'that will be included in ssh commands'))
171 self.parser.add_argument('--require-ssp', action='store_true',
172 dest='require_ssp', default=False,
173 help=('Force the autoserv process to run with '
174 'server-side packaging'))
175 self.parser.add_argument('--warn-no-ssp', action='store_true',
176 dest='warn_no_ssp', default=False,
177 help=('Post a warning in autoserv log that '
178 'the process runs in a drone without '
179 'server-side packaging support, even '
180 'though the job requires server-side '
181 'packaging'))
182 self.parser.add_argument('--no_use_packaging', action='store_true',
183 dest='no_use_packaging', default=False,
184 help=('Disable install modes that use the '
185 'packaging system.'))
186 self.parser.add_argument('--test_source_build', action='store',
187 type=str, default='',
188 dest='test_source_build',
189 help=('Name of the build that contains the '
190 'test code. Default is empty, that is, '
191 'use the build specified in --image to '
192 'retrieve tests.'))
193 self.parser.add_argument('--parent_job_id', action='store',
194 type=str, default=None,
195 dest='parent_job_id',
196 help=('ID of the parent job. Default to None '
197 'if the job does not have a parent job'))
198 self.parser.add_argument('--image', action='store', type=str,
199 default='', dest='image',
200 help=('Full path of an OS image to install, e.g.'
201 ' http://devserver/update/alex-release/'
202 'R27-3837.0.0 or a build name: '
203 'x86-alex-release/R27-3837.0.0 to '
204 'utilize lab devservers automatically.'))
Simran Basi1bf60eb2015-12-01 16:39:29 -0800205 self.parser.add_argument('--host_attributes', action='store',
206 dest='host_attributes', default='{}',
207 help=('Host attribute to be applied to all '
208 'machines/hosts for this autoserv run. '
209 'Must be a string-encoded dict. '
210 'Example: {"key1":"value1", "key2":'
211 '"value2"}'))
212 self.parser.add_argument('--lab', action='store', type=str,
213 dest='lab', default='',
214 help=argparse.SUPPRESS)
Dan Shi888cfca2015-07-31 15:49:00 -0700215 #
216 # Warning! Please read before adding any new arguments!
217 #
218 # New arguments will be ignored if a test runs with server-side
219 # packaging and if the test source build does not have the new
220 # arguments.
221 #
222 # New argument should NOT set action to `store_true`. A workaround is to
223 # use string value of `True` or `False`, then convert them to boolean in
224 # code.
225 # The reason is that parse_args will always ignore the argument name and
226 # value. An unknown argument without a value will lead to positional
227 # argument being removed unexpectedly.
228 #
jadmanski0afbb632008-06-06 21:10:57 +0000229
230
231 def parse_args(self):
Dan Shi888cfca2015-07-31 15:49:00 -0700232 """Parse and process command line arguments.
233 """
234 # Positional arguments from the end of the command line will be included
235 # in the list of unknown_args.
236 self.options, unknown_args = self.parser.parse_known_args()
237 # Filter out none-positional arguments
238 removed_args = []
239 while unknown_args and unknown_args[0][0] == '-':
240 removed_args.append(unknown_args.pop(0))
241 # Always assume the argument has a value.
242 if unknown_args:
243 removed_args.append(unknown_args.pop(0))
244 if removed_args:
245 logging.warn('Unknown arguments are removed from the options: %s',
246 removed_args)
mblighb7dcc7f2008-06-02 19:34:25 +0000247
Dan Shi888cfca2015-07-31 15:49:00 -0700248 self.args = unknown_args + shlex.split(self.options.args or '')
mblighb7dcc7f2008-06-02 19:34:25 +0000249
Dan Shi888cfca2015-07-31 15:49:00 -0700250 if self.options.image:
251 self.options.install_before = True
252 self.options.image = self.options.image.strip()
Simran Basi1bf60eb2015-12-01 16:39:29 -0800253 self.options.host_attributes = ast.literal_eval(
254 self.options.host_attributes)
mblighb7dcc7f2008-06-02 19:34:25 +0000255
256
257# create the one and only one instance of autoserv_parser
258autoserv_parser = autoserv_parser()