| OLD | NEW |
| 1 # Copyright (c) 2010 Mitch Garnaat http://garnaat.org/ | 1 # Copyright (c) 2010 Mitch Garnaat http://garnaat.org/ |
| 2 # Copyright (c) 2010, Eucalyptus Systems, Inc. | 2 # Copyright (c) 2010, Eucalyptus Systems, Inc. |
| 3 # | 3 # |
| 4 # Permission is hereby granted, free of charge, to any person obtaining a | 4 # Permission is hereby granted, free of charge, to any person obtaining a |
| 5 # copy of this software and associated documentation files (the | 5 # copy of this software and associated documentation files (the |
| 6 # "Software"), to deal in the Software without restriction, including | 6 # "Software"), to deal in the Software without restriction, including |
| 7 # without limitation the rights to use, copy, modify, merge, publish, dis- | 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 | 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- | 9 # persons to whom the Software is furnished to do so, subject to the fol- |
| 10 # lowing conditions: | 10 # lowing conditions: |
| 11 # | 11 # |
| 12 # The above copyright notice and this permission notice shall be included | 12 # The above copyright notice and this permission notice shall be included |
| 13 # in all copies or substantial portions of the Software. | 13 # in all copies or substantial portions of the Software. |
| 14 # | 14 # |
| 15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | 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- | 16 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- |
| 17 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | 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, | 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, | 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 | 20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| 21 # IN THE SOFTWARE. | 21 # IN THE SOFTWARE. |
| 22 | 22 |
| 23 import sys | 23 import sys |
| 24 import os | 24 import os |
| 25 import boto | 25 import boto |
| 26 import optparse | 26 import optparse |
| 27 import copy | 27 import copy |
| 28 import boto.exception | 28 import boto.exception |
| 29 import boto.roboto.awsqueryservice |
| 30 |
| 31 import bdb |
| 32 import traceback |
| 33 try: |
| 34 import epdb as debugger |
| 35 except ImportError: |
| 36 import pdb as debugger |
| 37 |
| 38 def boto_except_hook(debugger_flag, debug_flag): |
| 39 def excepthook(typ, value, tb): |
| 40 if typ is bdb.BdbQuit: |
| 41 sys.exit(1) |
| 42 sys.excepthook = sys.__excepthook__ |
| 43 |
| 44 if debugger_flag and sys.stdout.isatty() and sys.stdin.isatty(): |
| 45 if debugger.__name__ == 'epdb': |
| 46 debugger.post_mortem(tb, typ, value) |
| 47 else: |
| 48 debugger.post_mortem(tb) |
| 49 elif debug_flag: |
| 50 print traceback.print_tb(tb) |
| 51 sys.exit(1) |
| 52 else: |
| 53 print value |
| 54 sys.exit(1) |
| 55 |
| 56 return excepthook |
| 29 | 57 |
| 30 class Line(object): | 58 class Line(object): |
| 31 | 59 |
| 32 def __init__(self, fmt, data, label): | 60 def __init__(self, fmt, data, label): |
| 33 self.fmt = fmt | 61 self.fmt = fmt |
| 34 self.data = data | 62 self.data = data |
| 35 self.label = label | 63 self.label = label |
| 36 self.line = '%s\t' % label | 64 self.line = '%s\t' % label |
| 37 self.printed = False | 65 self.printed = False |
| 38 | 66 |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 234 if param.name in required: | 262 if param.name in required: |
| 235 required.remove(param.name) | 263 required.remove(param.name) |
| 236 if param.request_param: | 264 if param.request_param: |
| 237 if param.encoder: | 265 if param.encoder: |
| 238 param.encoder(param, self.request_params, value) | 266 param.encoder(param, self.request_params, value) |
| 239 else: | 267 else: |
| 240 Encoder.encode(param, self.request_params, value) | 268 Encoder.encode(param, self.request_params, value) |
| 241 if python_name in self.args: | 269 if python_name in self.args: |
| 242 del self.connection_args[python_name] | 270 del self.connection_args[python_name] |
| 243 if required: | 271 if required: |
| 244 raise RequiredParamError(required) | 272 l = [] |
| 273 for p in self.Params+self.Args: |
| 274 if p.name in required: |
| 275 if p.short_name and p.long_name: |
| 276 l.append('(%s, %s)' % (p.optparse_short_name, |
| 277 p.optparse_long_name)) |
| 278 elif p.short_name: |
| 279 l.append('(%s)' % p.optparse_short_name) |
| 280 else: |
| 281 l.append('(%s)' % p.optparse_long_name) |
| 282 raise RequiredParamError(','.join(l)) |
| 245 boto.log.debug('request_params: %s' % self.request_params) | 283 boto.log.debug('request_params: %s' % self.request_params) |
| 246 self.process_markers(self.Response) | 284 self.process_markers(self.Response) |
| 247 | 285 |
| 248 def process_markers(self, fmt, prev_name=None): | 286 def process_markers(self, fmt, prev_name=None): |
| 249 if fmt and fmt['type'] == 'object': | 287 if fmt and fmt['type'] == 'object': |
| 250 for prop in fmt['properties']: | 288 for prop in fmt['properties']: |
| 251 self.process_markers(prop, fmt['name']) | 289 self.process_markers(prop, fmt['name']) |
| 252 elif fmt and fmt['type'] == 'array': | 290 elif fmt and fmt['type'] == 'array': |
| 253 self.list_markers.append(prev_name) | 291 self.list_markers.append(prev_name) |
| 254 self.item_markers.append(fmt['name']) | 292 self.item_markers.append(fmt['name']) |
| (...skipping 19 matching lines...) Expand all Loading... |
| 274 boto.log.error('%s' % self.body) | 312 boto.log.error('%s' % self.body) |
| 275 raise conn.ResponseError(self.http_response.status, | 313 raise conn.ResponseError(self.http_response.status, |
| 276 self.http_response.reason, | 314 self.http_response.reason, |
| 277 self.body) | 315 self.body) |
| 278 | 316 |
| 279 def add_standard_options(self): | 317 def add_standard_options(self): |
| 280 group = optparse.OptionGroup(self.parser, 'Standard Options') | 318 group = optparse.OptionGroup(self.parser, 'Standard Options') |
| 281 # add standard options that all commands get | 319 # add standard options that all commands get |
| 282 group.add_option('-D', '--debug', action='store_true', | 320 group.add_option('-D', '--debug', action='store_true', |
| 283 help='Turn on all debugging output') | 321 help='Turn on all debugging output') |
| 322 group.add_option('--debugger', action='store_true', |
| 323 default=False, |
| 324 help='Enable interactive debugger on error') |
| 284 group.add_option('-U', '--url', action='store', | 325 group.add_option('-U', '--url', action='store', |
| 285 help='Override service URL with value provided') | 326 help='Override service URL with value provided') |
| 286 group.add_option('--region', action='store', | 327 group.add_option('--region', action='store', |
| 287 help='Name of the region to connect to') | 328 help='Name of the region to connect to') |
| 288 group.add_option('-I', '--access-key-id', action='store', | 329 group.add_option('-I', '--access-key-id', action='store', |
| 289 help='Override access key value') | 330 help='Override access key value') |
| 290 group.add_option('-S', '--secret-key', action='store', | 331 group.add_option('-S', '--secret-key', action='store', |
| 291 help='Override secret key value') | 332 help='Override secret key value') |
| 292 group.add_option('--version', action='store_true', | 333 group.add_option('--version', action='store_true', |
| 293 help='Display version string') | 334 help='Display version string') |
| (...skipping 18 matching lines...) Expand all Loading... |
| 312 if options.region: | 353 if options.region: |
| 313 self.args['region'] = options.region | 354 self.args['region'] = options.region |
| 314 if options.access_key_id: | 355 if options.access_key_id: |
| 315 self.args['aws_access_key_id'] = options.access_key_id | 356 self.args['aws_access_key_id'] = options.access_key_id |
| 316 if options.secret_key: | 357 if options.secret_key: |
| 317 self.args['aws_secret_access_key'] = options.secret_key | 358 self.args['aws_secret_access_key'] = options.secret_key |
| 318 if options.version: | 359 if options.version: |
| 319 # TODO - Where should the version # come from? | 360 # TODO - Where should the version # come from? |
| 320 print 'version x.xx' | 361 print 'version x.xx' |
| 321 exit(0) | 362 exit(0) |
| 363 sys.excepthook = boto_except_hook(options.debugger, |
| 364 options.debug) |
| 322 | 365 |
| 366 def get_usage(self): |
| 367 s = 'usage: %prog [options] ' |
| 368 l = [ a.long_name for a in self.Args ] |
| 369 s += ' '.join(l) |
| 370 for a in self.Args: |
| 371 if a.doc: |
| 372 s += '\n\n\t%s - %s' % (a.long_name, a.doc) |
| 373 return s |
| 374 |
| 323 def build_cli_parser(self): | 375 def build_cli_parser(self): |
| 324 self.parser = optparse.OptionParser() | 376 self.parser = optparse.OptionParser(description=self.Description, |
| 377 usage=self.get_usage()) |
| 325 self.add_standard_options() | 378 self.add_standard_options() |
| 326 for param in self.Params: | 379 for param in self.Params: |
| 327 ptype = action = choices = None | 380 ptype = action = choices = None |
| 328 if param.ptype in self.CLITypeMap: | 381 if param.ptype in self.CLITypeMap: |
| 329 ptype = self.CLITypeMap[param.ptype] | 382 ptype = self.CLITypeMap[param.ptype] |
| 330 action = 'store' | 383 action = 'store' |
| 331 if param.ptype == 'boolean': | 384 if param.ptype == 'boolean': |
| 332 action = 'store_true' | 385 action = 'store_true' |
| 333 elif param.ptype == 'array': | 386 elif param.ptype == 'array': |
| 334 if len(param.items) == 1: | 387 if len(param.items) == 1: |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 else: | 450 else: |
| 398 self.args['filters'] = d | 451 self.args['filters'] = d |
| 399 try: | 452 try: |
| 400 response = self.main() | 453 response = self.main() |
| 401 self.cli_formatter(response) | 454 self.cli_formatter(response) |
| 402 except RequiredParamError, e: | 455 except RequiredParamError, e: |
| 403 print e | 456 print e |
| 404 sys.exit(1) | 457 sys.exit(1) |
| 405 except self.ServiceClass.ResponseError, err: | 458 except self.ServiceClass.ResponseError, err: |
| 406 print 'Error(%s): %s' % (err.error_code, err.error_message) | 459 print 'Error(%s): %s' % (err.error_code, err.error_message) |
| 460 sys.exit(1) |
| 461 except boto.roboto.awsqueryservice.NoCredentialsError, err: |
| 462 print 'Unable to find credentials.' |
| 463 sys.exit(1) |
| 464 except Exception, e: |
| 465 print e |
| 466 sys.exit(1) |
| 407 | 467 |
| 408 def _generic_cli_formatter(self, fmt, data, label=''): | 468 def _generic_cli_formatter(self, fmt, data, label=''): |
| 409 if fmt['type'] == 'object': | 469 if fmt['type'] == 'object': |
| 410 for prop in fmt['properties']: | 470 for prop in fmt['properties']: |
| 411 if 'name' in fmt: | 471 if 'name' in fmt: |
| 412 if fmt['name'] in data: | 472 if fmt['name'] in data: |
| 413 data = data[fmt['name']] | 473 data = data[fmt['name']] |
| 414 if fmt['name'] in self.list_markers: | 474 if fmt['name'] in self.list_markers: |
| 415 label = fmt['name'] | 475 label = fmt['name'] |
| 416 if label[-1] == 's': | 476 if label[-1] == 's': |
| (...skipping 18 matching lines...) Expand all Loading... |
| 435 reasonable. If you want specific formatting, you should | 495 reasonable. If you want specific formatting, you should |
| 436 override this method and do your own thing. | 496 override this method and do your own thing. |
| 437 | 497 |
| 438 :type data: dict | 498 :type data: dict |
| 439 :param data: The data returned by AWS. | 499 :param data: The data returned by AWS. |
| 440 """ | 500 """ |
| 441 if data: | 501 if data: |
| 442 self._generic_cli_formatter(self.Response, data) | 502 self._generic_cli_formatter(self.Response, data) |
| 443 | 503 |
| 444 | 504 |
| OLD | NEW |