comparison env/lib/python3.7/site-packages/boto/roboto/awsqueryrequest.py @ 0:26e78fe6e8c4 draft

"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author shellac
date Sat, 02 May 2020 07:14:21 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:26e78fe6e8c4
1 # Copyright (c) 2010 Mitch Garnaat http://garnaat.org/
2 # Copyright (c) 2010, Eucalyptus Systems, Inc.
3 #
4 # Permission is hereby granted, free of charge, to any person obtaining a
5 # copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish, dis-
8 # tribute, sublicense, and/or sell copies of the Software, and to permit
9 # persons to whom the Software is furnished to do so, subject to the fol-
10 # lowing conditions:
11 #
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
17 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
18 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 # IN THE SOFTWARE.
22 import sys
23 import os
24 import boto
25 import optparse
26 import copy
27 import boto.exception
28 import boto.roboto.awsqueryservice
29
30 import bdb
31 import traceback
32 try:
33 import epdb as debugger
34 except ImportError:
35 import pdb as debugger
36
37 def boto_except_hook(debugger_flag, debug_flag):
38 def excepthook(typ, value, tb):
39 if typ is bdb.BdbQuit:
40 sys.exit(1)
41 sys.excepthook = sys.__excepthook__
42
43 if debugger_flag and sys.stdout.isatty() and sys.stdin.isatty():
44 if debugger.__name__ == 'epdb':
45 debugger.post_mortem(tb, typ, value)
46 else:
47 debugger.post_mortem(tb)
48 elif debug_flag:
49 print(traceback.print_tb(tb))
50 sys.exit(1)
51 else:
52 print(value)
53 sys.exit(1)
54
55 return excepthook
56
57 class Line(object):
58
59 def __init__(self, fmt, data, label):
60 self.fmt = fmt
61 self.data = data
62 self.label = label
63 self.line = '%s\t' % label
64 self.printed = False
65
66 def append(self, datum):
67 self.line += '%s\t' % datum
68
69 def print_it(self):
70 if not self.printed:
71 print(self.line)
72 self.printed = True
73
74 class RequiredParamError(boto.exception.BotoClientError):
75
76 def __init__(self, required):
77 self.required = required
78 s = 'Required parameters are missing: %s' % self.required
79 super(RequiredParamError, self).__init__(s)
80
81 class EncoderError(boto.exception.BotoClientError):
82
83 def __init__(self, error_msg):
84 s = 'Error encoding value (%s)' % error_msg
85 super(EncoderError, self).__init__(s)
86
87 class FilterError(boto.exception.BotoClientError):
88
89 def __init__(self, filters):
90 self.filters = filters
91 s = 'Unknown filters: %s' % self.filters
92 super(FilterError, self).__init__(s)
93
94 class Encoder(object):
95
96 @classmethod
97 def encode(cls, p, rp, v, label=None):
98 if p.name.startswith('_'):
99 return
100 try:
101 mthd = getattr(cls, 'encode_'+p.ptype)
102 mthd(p, rp, v, label)
103 except AttributeError:
104 raise EncoderError('Unknown type: %s' % p.ptype)
105
106 @classmethod
107 def encode_string(cls, p, rp, v, l):
108 if l:
109 label = l
110 else:
111 label = p.name
112 rp[label] = v
113
114 encode_file = encode_string
115 encode_enum = encode_string
116
117 @classmethod
118 def encode_integer(cls, p, rp, v, l):
119 if l:
120 label = l
121 else:
122 label = p.name
123 rp[label] = '%d' % v
124
125 @classmethod
126 def encode_boolean(cls, p, rp, v, l):
127 if l:
128 label = l
129 else:
130 label = p.name
131 if v:
132 v = 'true'
133 else:
134 v = 'false'
135 rp[label] = v
136
137 @classmethod
138 def encode_datetime(cls, p, rp, v, l):
139 if l:
140 label = l
141 else:
142 label = p.name
143 rp[label] = v
144
145 @classmethod
146 def encode_array(cls, p, rp, v, l):
147 v = boto.utils.mklist(v)
148 if l:
149 label = l
150 else:
151 label = p.name
152 label = label + '.%d'
153 for i, value in enumerate(v):
154 rp[label%(i+1)] = value
155
156 class AWSQueryRequest(object):
157
158 ServiceClass = None
159
160 Description = ''
161 Params = []
162 Args = []
163 Filters = []
164 Response = {}
165
166 CLITypeMap = {'string' : 'string',
167 'integer' : 'int',
168 'int' : 'int',
169 'enum' : 'choice',
170 'datetime' : 'string',
171 'dateTime' : 'string',
172 'file' : 'string',
173 'boolean' : None}
174
175 @classmethod
176 def name(cls):
177 return cls.__name__
178
179 def __init__(self, **args):
180 self.args = args
181 self.parser = None
182 self.cli_options = None
183 self.cli_args = None
184 self.cli_output_format = None
185 self.connection = None
186 self.list_markers = []
187 self.item_markers = []
188 self.request_params = {}
189 self.connection_args = None
190
191 def __repr__(self):
192 return self.name()
193
194 def get_connection(self, **args):
195 if self.connection is None:
196 self.connection = self.ServiceClass(**args)
197 return self.connection
198
199 @property
200 def status(self):
201 retval = None
202 if self.http_response is not None:
203 retval = self.http_response.status
204 return retval
205
206 @property
207 def reason(self):
208 retval = None
209 if self.http_response is not None:
210 retval = self.http_response.reason
211 return retval
212
213 @property
214 def request_id(self):
215 retval = None
216 if self.aws_response is not None:
217 retval = getattr(self.aws_response, 'requestId')
218 return retval
219
220 def process_filters(self):
221 filters = self.args.get('filters', [])
222 filter_names = [f['name'] for f in self.Filters]
223 unknown_filters = [f for f in filters if f not in filter_names]
224 if unknown_filters:
225 raise FilterError('Unknown filters: %s' % unknown_filters)
226 for i, filter in enumerate(self.Filters):
227 name = filter['name']
228 if name in filters:
229 self.request_params['Filter.%d.Name' % (i+1)] = name
230 for j, value in enumerate(boto.utils.mklist(filters[name])):
231 Encoder.encode(filter, self.request_params, value,
232 'Filter.%d.Value.%d' % (i+1, j+1))
233
234 def process_args(self, **args):
235 """
236 Responsible for walking through Params defined for the request and:
237
238 * Matching them with keyword parameters passed to the request
239 constructor or via the command line.
240 * Checking to see if all required parameters have been specified
241 and raising an exception, if not.
242 * Encoding each value into the set of request parameters that will
243 be sent in the request to the AWS service.
244 """
245 self.args.update(args)
246 self.connection_args = copy.copy(self.args)
247 if 'debug' in self.args and self.args['debug'] >= 2:
248 boto.set_stream_logger(self.name())
249 required = [p.name for p in self.Params+self.Args if not p.optional]
250 for param in self.Params+self.Args:
251 if param.long_name:
252 python_name = param.long_name.replace('-', '_')
253 else:
254 python_name = boto.utils.pythonize_name(param.name, '_')
255 value = None
256 if python_name in self.args:
257 value = self.args[python_name]
258 if value is None:
259 value = param.default
260 if value is not None:
261 if param.name in required:
262 required.remove(param.name)
263 if param.request_param:
264 if param.encoder:
265 param.encoder(param, self.request_params, value)
266 else:
267 Encoder.encode(param, self.request_params, value)
268 if python_name in self.args:
269 del self.connection_args[python_name]
270 if required:
271 l = []
272 for p in self.Params+self.Args:
273 if p.name in required:
274 if p.short_name and p.long_name:
275 l.append('(%s, %s)' % (p.optparse_short_name,
276 p.optparse_long_name))
277 elif p.short_name:
278 l.append('(%s)' % p.optparse_short_name)
279 else:
280 l.append('(%s)' % p.optparse_long_name)
281 raise RequiredParamError(','.join(l))
282 boto.log.debug('request_params: %s' % self.request_params)
283 self.process_markers(self.Response)
284
285 def process_markers(self, fmt, prev_name=None):
286 if fmt and fmt['type'] == 'object':
287 for prop in fmt['properties']:
288 self.process_markers(prop, fmt['name'])
289 elif fmt and fmt['type'] == 'array':
290 self.list_markers.append(prev_name)
291 self.item_markers.append(fmt['name'])
292
293 def send(self, verb='GET', **args):
294 self.process_args(**args)
295 self.process_filters()
296 conn = self.get_connection(**self.connection_args)
297 self.http_response = conn.make_request(self.name(),
298 self.request_params,
299 verb=verb)
300 self.body = self.http_response.read()
301 boto.log.debug(self.body)
302 if self.http_response.status == 200:
303 self.aws_response = boto.jsonresponse.Element(list_marker=self.list_markers,
304 item_marker=self.item_markers)
305 h = boto.jsonresponse.XmlHandler(self.aws_response, self)
306 h.parse(self.body)
307 return self.aws_response
308 else:
309 boto.log.error('%s %s' % (self.http_response.status,
310 self.http_response.reason))
311 boto.log.error('%s' % self.body)
312 raise conn.ResponseError(self.http_response.status,
313 self.http_response.reason,
314 self.body)
315
316 def add_standard_options(self):
317 group = optparse.OptionGroup(self.parser, 'Standard Options')
318 # add standard options that all commands get
319 group.add_option('-D', '--debug', action='store_true',
320 help='Turn on all debugging output')
321 group.add_option('--debugger', action='store_true',
322 default=False,
323 help='Enable interactive debugger on error')
324 group.add_option('-U', '--url', action='store',
325 help='Override service URL with value provided')
326 group.add_option('--region', action='store',
327 help='Name of the region to connect to')
328 group.add_option('-I', '--access-key-id', action='store',
329 help='Override access key value')
330 group.add_option('-S', '--secret-key', action='store',
331 help='Override secret key value')
332 group.add_option('--version', action='store_true',
333 help='Display version string')
334 if self.Filters:
335 self.group.add_option('--help-filters', action='store_true',
336 help='Display list of available filters')
337 self.group.add_option('--filter', action='append',
338 metavar=' name=value',
339 help='A filter for limiting the results')
340 self.parser.add_option_group(group)
341
342 def process_standard_options(self, options, args, d):
343 if hasattr(options, 'help_filters') and options.help_filters:
344 print('Available filters:')
345 for filter in self.Filters:
346 print('%s\t%s' % (filter.name, filter.doc))
347 sys.exit(0)
348 if options.debug:
349 self.args['debug'] = 2
350 if options.url:
351 self.args['url'] = options.url
352 if options.region:
353 self.args['region'] = options.region
354 if options.access_key_id:
355 self.args['aws_access_key_id'] = options.access_key_id
356 if options.secret_key:
357 self.args['aws_secret_access_key'] = options.secret_key
358 if options.version:
359 # TODO - Where should the version # come from?
360 print('version x.xx')
361 exit(0)
362 sys.excepthook = boto_except_hook(options.debugger,
363 options.debug)
364
365 def get_usage(self):
366 s = 'usage: %prog [options] '
367 l = [ a.long_name for a in self.Args ]
368 s += ' '.join(l)
369 for a in self.Args:
370 if a.doc:
371 s += '\n\n\t%s - %s' % (a.long_name, a.doc)
372 return s
373
374 def build_cli_parser(self):
375 self.parser = optparse.OptionParser(description=self.Description,
376 usage=self.get_usage())
377 self.add_standard_options()
378 for param in self.Params:
379 ptype = action = choices = None
380 if param.ptype in self.CLITypeMap:
381 ptype = self.CLITypeMap[param.ptype]
382 action = 'store'
383 if param.ptype == 'boolean':
384 action = 'store_true'
385 elif param.ptype == 'array':
386 if len(param.items) == 1:
387 ptype = param.items[0]['type']
388 action = 'append'
389 elif param.cardinality != 1:
390 action = 'append'
391 if ptype or action == 'store_true':
392 if param.short_name:
393 self.parser.add_option(param.optparse_short_name,
394 param.optparse_long_name,
395 action=action, type=ptype,
396 choices=param.choices,
397 help=param.doc)
398 elif param.long_name:
399 self.parser.add_option(param.optparse_long_name,
400 action=action, type=ptype,
401 choices=param.choices,
402 help=param.doc)
403
404 def do_cli(self):
405 if not self.parser:
406 self.build_cli_parser()
407 self.cli_options, self.cli_args = self.parser.parse_args()
408 d = {}
409 self.process_standard_options(self.cli_options, self.cli_args, d)
410 for param in self.Params:
411 if param.long_name:
412 p_name = param.long_name.replace('-', '_')
413 else:
414 p_name = boto.utils.pythonize_name(param.name)
415 value = getattr(self.cli_options, p_name)
416 if param.ptype == 'file' and value:
417 if value == '-':
418 value = sys.stdin.read()
419 else:
420 path = os.path.expanduser(value)
421 path = os.path.expandvars(path)
422 if os.path.isfile(path):
423 fp = open(path)
424 value = fp.read()
425 fp.close()
426 else:
427 self.parser.error('Unable to read file: %s' % path)
428 d[p_name] = value
429 for arg in self.Args:
430 if arg.long_name:
431 p_name = arg.long_name.replace('-', '_')
432 else:
433 p_name = boto.utils.pythonize_name(arg.name)
434 value = None
435 if arg.cardinality == 1:
436 if len(self.cli_args) >= 1:
437 value = self.cli_args[0]
438 else:
439 value = self.cli_args
440 d[p_name] = value
441 self.args.update(d)
442 if hasattr(self.cli_options, 'filter') and self.cli_options.filter:
443 d = {}
444 for filter in self.cli_options.filter:
445 name, value = filter.split('=')
446 d[name] = value
447 if 'filters' in self.args:
448 self.args['filters'].update(d)
449 else:
450 self.args['filters'] = d
451 try:
452 response = self.main()
453 self.cli_formatter(response)
454 except RequiredParamError as e:
455 print(e)
456 sys.exit(1)
457 except self.ServiceClass.ResponseError as err:
458 print('Error(%s): %s' % (err.error_code, err.error_message))
459 sys.exit(1)
460 except boto.roboto.awsqueryservice.NoCredentialsError as err:
461 print('Unable to find credentials.')
462 sys.exit(1)
463 except Exception as e:
464 print(e)
465 sys.exit(1)
466
467 def _generic_cli_formatter(self, fmt, data, label=''):
468 if fmt['type'] == 'object':
469 for prop in fmt['properties']:
470 if 'name' in fmt:
471 if fmt['name'] in data:
472 data = data[fmt['name']]
473 if fmt['name'] in self.list_markers:
474 label = fmt['name']
475 if label[-1] == 's':
476 label = label[0:-1]
477 label = label.upper()
478 self._generic_cli_formatter(prop, data, label)
479 elif fmt['type'] == 'array':
480 for item in data:
481 line = Line(fmt, item, label)
482 if isinstance(item, dict):
483 for field_name in item:
484 line.append(item[field_name])
485 elif isinstance(item, basestring):
486 line.append(item)
487 line.print_it()
488
489 def cli_formatter(self, data):
490 """
491 This method is responsible for formatting the output for the
492 command line interface. The default behavior is to call the
493 generic CLI formatter which attempts to print something
494 reasonable. If you want specific formatting, you should
495 override this method and do your own thing.
496
497 :type data: dict
498 :param data: The data returned by AWS.
499 """
500 if data:
501 self._generic_cli_formatter(self.Response, data)
502
503