Revision df79206f kamaki/cli.py
b/kamaki/cli.py | ||
---|---|---|
77 | 77 |
from pwd import getpwuid |
78 | 78 |
from sys import argv, exit, stdout |
79 | 79 |
|
80 |
from clint.textui import puts, puts_err, indent |
|
80 |
from clint import args |
|
81 |
from clint.textui import puts, puts_err, indent, progress |
|
82 |
from clint.textui.colored import magenta, red, yellow |
|
81 | 83 |
from clint.textui.cols import columns |
82 | 84 |
|
85 |
from requests.exceptions import ConnectionError |
|
86 |
|
|
83 | 87 |
from kamaki import clients |
84 | 88 |
from kamaki.config import Config |
85 | 89 |
from kamaki.utils import OrderedDict, print_addresses, print_dict, print_items |
... | ... | |
116 | 120 |
cls.api = api |
117 | 121 |
cls.group = group or grp |
118 | 122 |
cls.name = name or cmd |
119 |
cls.description = description or cls.__doc__ |
|
120 |
cls.syntax = syntax |
|
121 | 123 |
|
122 | 124 |
short_description, sep, long_description = cls.__doc__.partition('\n') |
123 | 125 |
cls.description = short_description |
... | ... | |
194 | 196 |
|
195 | 197 |
@command(api='compute') |
196 | 198 |
class server_list(object): |
197 |
"""list servers"""
|
|
199 |
"""List servers"""
|
|
198 | 200 |
|
199 | 201 |
def update_parser(cls, parser): |
200 | 202 |
parser.add_option('-l', dest='detail', action='store_true', |
... | ... | |
207 | 209 |
|
208 | 210 |
@command(api='compute') |
209 | 211 |
class server_info(object): |
210 |
"""get server details"""
|
|
212 |
"""Get server details"""
|
|
211 | 213 |
|
212 | 214 |
def main(self, server_id): |
213 | 215 |
server = self.client.get_server_details(int(server_id)) |
... | ... | |
216 | 218 |
|
217 | 219 |
@command(api='compute') |
218 | 220 |
class server_create(object): |
219 |
"""create server"""
|
|
221 |
"""Create a server"""
|
|
220 | 222 |
|
221 | 223 |
def update_parser(cls, parser): |
222 | 224 |
parser.add_option('--personality', dest='personalities', |
223 |
action='append', default=[], |
|
224 |
metavar='PATH[,SERVER PATH[,OWNER[,GROUP,[MODE]]]]', |
|
225 |
help='add a personality file') |
|
225 |
action='append', default=[],
|
|
226 |
metavar='PATH[,SERVER PATH[,OWNER[,GROUP,[MODE]]]]',
|
|
227 |
help='add a personality file')
|
|
226 | 228 |
parser.epilog = "If missing, optional personality values will be " \ |
227 |
"filled based on the file at PATH if missing."
|
|
229 |
"filled based on the file at PATH."
|
|
228 | 230 |
|
229 | 231 |
def main(self, name, flavor_id, image_id): |
230 | 232 |
personalities = [] |
... | ... | |
259 | 261 |
|
260 | 262 |
@command(api='compute') |
261 | 263 |
class server_rename(object): |
262 |
"""update server name"""
|
|
264 |
"""Update a server's name"""
|
|
263 | 265 |
|
264 | 266 |
def main(self, server_id, new_name): |
265 | 267 |
self.client.update_server_name(int(server_id), new_name) |
... | ... | |
267 | 269 |
|
268 | 270 |
@command(api='compute') |
269 | 271 |
class server_delete(object): |
270 |
"""delete server"""
|
|
272 |
"""Delete a server"""
|
|
271 | 273 |
|
272 | 274 |
def main(self, server_id): |
273 | 275 |
self.client.delete_server(int(server_id)) |
... | ... | |
275 | 277 |
|
276 | 278 |
@command(api='compute') |
277 | 279 |
class server_reboot(object): |
278 |
"""reboot server"""
|
|
280 |
"""Reboot a server"""
|
|
279 | 281 |
|
280 | 282 |
def update_parser(cls, parser): |
281 | 283 |
parser.add_option('-f', dest='hard', action='store_true', |
... | ... | |
287 | 289 |
|
288 | 290 |
@command(api='cyclades') |
289 | 291 |
class server_start(object): |
290 |
"""start server"""
|
|
292 |
"""Start a server"""
|
|
291 | 293 |
|
292 | 294 |
def main(self, server_id): |
293 | 295 |
self.client.start_server(int(server_id)) |
... | ... | |
295 | 297 |
|
296 | 298 |
@command(api='cyclades') |
297 | 299 |
class server_shutdown(object): |
298 |
"""shutdown server"""
|
|
300 |
"""Shutdown a server"""
|
|
299 | 301 |
|
300 | 302 |
def main(self, server_id): |
301 | 303 |
self.client.shutdown_server(int(server_id)) |
... | ... | |
303 | 305 |
|
304 | 306 |
@command(api='cyclades') |
305 | 307 |
class server_console(object): |
306 |
"""get a VNC console"""
|
|
308 |
"""Get a VNC console"""
|
|
307 | 309 |
|
308 | 310 |
def main(self, server_id): |
309 | 311 |
reply = self.client.get_server_console(int(server_id)) |
... | ... | |
312 | 314 |
|
313 | 315 |
@command(api='cyclades') |
314 | 316 |
class server_firewall(object): |
315 |
"""set the firewall profile"""
|
|
317 |
"""Set the server's firewall profile"""
|
|
316 | 318 |
|
317 | 319 |
def main(self, server_id, profile): |
318 | 320 |
self.client.set_firewall_profile(int(server_id), profile) |
... | ... | |
320 | 322 |
|
321 | 323 |
@command(api='cyclades') |
322 | 324 |
class server_addr(object): |
323 |
"""list server addresses"""
|
|
325 |
"""List a server's addresses"""
|
|
324 | 326 |
|
325 | 327 |
def main(self, server_id, network=None): |
326 | 328 |
reply = self.client.list_server_addresses(int(server_id), network) |
... | ... | |
330 | 332 |
|
331 | 333 |
@command(api='compute') |
332 | 334 |
class server_meta(object): |
333 |
"""get server metadata"""
|
|
335 |
"""Get a server's metadata"""
|
|
334 | 336 |
|
335 | 337 |
def main(self, server_id, key=None): |
336 | 338 |
reply = self.client.get_server_metadata(int(server_id), key) |
... | ... | |
339 | 341 |
|
340 | 342 |
@command(api='compute') |
341 | 343 |
class server_addmeta(object): |
342 |
"""add server metadata"""
|
|
344 |
"""Add server metadata"""
|
|
343 | 345 |
|
344 | 346 |
def main(self, server_id, key, val): |
345 | 347 |
reply = self.client.create_server_metadata(int(server_id), key, val) |
... | ... | |
348 | 350 |
|
349 | 351 |
@command(api='compute') |
350 | 352 |
class server_setmeta(object): |
351 |
"""update server metadata"""
|
|
353 |
"""Update server's metadata"""
|
|
352 | 354 |
|
353 | 355 |
def main(self, server_id, key, val): |
354 | 356 |
metadata = {key: val} |
... | ... | |
358 | 360 |
|
359 | 361 |
@command(api='compute') |
360 | 362 |
class server_delmeta(object): |
361 |
"""delete server metadata"""
|
|
363 |
"""Delete server metadata"""
|
|
362 | 364 |
|
363 | 365 |
def main(self, server_id, key): |
364 | 366 |
self.client.delete_server_metadata(int(server_id), key) |
... | ... | |
366 | 368 |
|
367 | 369 |
@command(api='cyclades') |
368 | 370 |
class server_stats(object): |
369 |
"""get server statistics"""
|
|
371 |
"""Get server statistics"""
|
|
370 | 372 |
|
371 | 373 |
def main(self, server_id): |
372 | 374 |
reply = self.client.get_server_stats(int(server_id)) |
... | ... | |
375 | 377 |
|
376 | 378 |
@command(api='compute') |
377 | 379 |
class flavor_list(object): |
378 |
"""list flavors"""
|
|
380 |
"""List flavors"""
|
|
379 | 381 |
|
380 | 382 |
def update_parser(cls, parser): |
381 | 383 |
parser.add_option('-l', dest='detail', action='store_true', |
... | ... | |
388 | 390 |
|
389 | 391 |
@command(api='compute') |
390 | 392 |
class flavor_info(object): |
391 |
"""get flavor details"""
|
|
393 |
"""Get flavor details"""
|
|
392 | 394 |
|
393 | 395 |
def main(self, flavor_id): |
394 | 396 |
flavor = self.client.get_flavor_details(int(flavor_id)) |
... | ... | |
397 | 399 |
|
398 | 400 |
@command(api='compute') |
399 | 401 |
class image_list(object): |
400 |
"""list images"""
|
|
402 |
"""List images"""
|
|
401 | 403 |
|
402 | 404 |
def update_parser(cls, parser): |
403 | 405 |
parser.add_option('-l', dest='detail', action='store_true', |
... | ... | |
410 | 412 |
|
411 | 413 |
@command(api='compute') |
412 | 414 |
class image_info(object): |
413 |
"""get image details"""
|
|
415 |
"""Get image details"""
|
|
414 | 416 |
|
415 | 417 |
def main(self, image_id): |
416 | 418 |
image = self.client.get_image_details(image_id) |
... | ... | |
419 | 421 |
|
420 | 422 |
@command(api='compute') |
421 | 423 |
class image_delete(object): |
422 |
"""delete image"""
|
|
424 |
"""Delete image"""
|
|
423 | 425 |
|
424 | 426 |
def main(self, image_id): |
425 | 427 |
self.client.delete_image(image_id) |
... | ... | |
427 | 429 |
|
428 | 430 |
@command(api='compute') |
429 | 431 |
class image_meta(object): |
430 |
"""get image metadata"""
|
|
432 |
"""Get image metadata"""
|
|
431 | 433 |
|
432 | 434 |
def main(self, image_id, key=None): |
433 | 435 |
reply = self.client.get_image_metadata(image_id, key) |
... | ... | |
436 | 438 |
|
437 | 439 |
@command(api='compute') |
438 | 440 |
class image_addmeta(object): |
439 |
"""add image metadata"""
|
|
441 |
"""Add image metadata"""
|
|
440 | 442 |
|
441 | 443 |
def main(self, image_id, key, val): |
442 | 444 |
reply = self.client.create_image_metadata(image_id, key, val) |
... | ... | |
445 | 447 |
|
446 | 448 |
@command(api='compute') |
447 | 449 |
class image_setmeta(object): |
448 |
"""update image metadata"""
|
|
450 |
"""Update image metadata"""
|
|
449 | 451 |
|
450 | 452 |
def main(self, image_id, key, val): |
451 | 453 |
metadata = {key: val} |
... | ... | |
455 | 457 |
|
456 | 458 |
@command(api='compute') |
457 | 459 |
class image_delmeta(object): |
458 |
"""delete image metadata"""
|
|
460 |
"""Delete image metadata"""
|
|
459 | 461 |
|
460 | 462 |
def main(self, image_id, key): |
461 | 463 |
self.client.delete_image_metadata(image_id, key) |
... | ... | |
463 | 465 |
|
464 | 466 |
@command(api='cyclades') |
465 | 467 |
class network_list(object): |
466 |
"""list networks"""
|
|
468 |
"""List networks"""
|
|
467 | 469 |
|
468 | 470 |
def update_parser(cls, parser): |
469 | 471 |
parser.add_option('-l', dest='detail', action='store_true', |
... | ... | |
476 | 478 |
|
477 | 479 |
@command(api='cyclades') |
478 | 480 |
class network_create(object): |
479 |
"""create a network"""
|
|
481 |
"""Create a network"""
|
|
480 | 482 |
|
481 | 483 |
def main(self, name): |
482 | 484 |
reply = self.client.create_network(name) |
... | ... | |
485 | 487 |
|
486 | 488 |
@command(api='cyclades') |
487 | 489 |
class network_info(object): |
488 |
"""get network details"""
|
|
490 |
"""Get network details"""
|
|
489 | 491 |
|
490 | 492 |
def main(self, network_id): |
491 | 493 |
network = self.client.get_network_details(network_id) |
... | ... | |
494 | 496 |
|
495 | 497 |
@command(api='cyclades') |
496 | 498 |
class network_rename(object): |
497 |
"""update network name"""
|
|
499 |
"""Update network name"""
|
|
498 | 500 |
|
499 | 501 |
def main(self, network_id, new_name): |
500 | 502 |
self.client.update_network_name(network_id, new_name) |
... | ... | |
502 | 504 |
|
503 | 505 |
@command(api='cyclades') |
504 | 506 |
class network_delete(object): |
505 |
"""delete a network"""
|
|
507 |
"""Delete a network"""
|
|
506 | 508 |
|
507 | 509 |
def main(self, network_id): |
508 | 510 |
self.client.delete_network(network_id) |
... | ... | |
510 | 512 |
|
511 | 513 |
@command(api='cyclades') |
512 | 514 |
class network_connect(object): |
513 |
"""connect a server to a network"""
|
|
515 |
"""Connect a server to a network"""
|
|
514 | 516 |
|
515 | 517 |
def main(self, server_id, network_id): |
516 | 518 |
self.client.connect_server(server_id, network_id) |
... | ... | |
518 | 520 |
|
519 | 521 |
@command(api='cyclades') |
520 | 522 |
class network_disconnect(object): |
521 |
"""disconnect a server from a network"""
|
|
523 |
"""Disconnect a server from a network"""
|
|
522 | 524 |
|
523 | 525 |
def main(self, server_id, network_id): |
524 | 526 |
self.client.disconnect_server(server_id, network_id) |
... | ... | |
526 | 528 |
|
527 | 529 |
@command(api='image') |
528 | 530 |
class glance_list(object): |
529 |
"""list images"""
|
|
531 |
"""List images"""
|
|
530 | 532 |
|
531 | 533 |
def update_parser(cls, parser): |
532 | 534 |
parser.add_option('-l', dest='detail', action='store_true', |
... | ... | |
562 | 564 |
|
563 | 565 |
@command(api='image') |
564 | 566 |
class glance_meta(object): |
565 |
"""get image metadata"""
|
|
567 |
"""Get image metadata"""
|
|
566 | 568 |
|
567 | 569 |
def main(self, image_id): |
568 | 570 |
image = self.client.get_meta(image_id) |
... | ... | |
571 | 573 |
|
572 | 574 |
@command(api='image') |
573 | 575 |
class glance_register(object): |
574 |
"""register an image"""
|
|
576 |
"""Register an image"""
|
|
575 | 577 |
|
576 | 578 |
def update_parser(cls, parser): |
577 | 579 |
parser.add_option('--checksum', dest='checksum', metavar='CHECKSUM', |
... | ... | |
595 | 597 |
def main(self, name, location): |
596 | 598 |
params = {} |
597 | 599 |
for key in ('checksum', 'container_format', 'disk_format', 'id', |
598 |
'owner', 'is_public', 'size'):
|
|
600 |
'owner', 'size'): |
|
599 | 601 |
val = getattr(self.options, key) |
600 | 602 |
if val is not None: |
601 | 603 |
params[key] = val |
602 | 604 |
|
605 |
if self.options.is_public: |
|
606 |
params['is_public'] = 'true' |
|
607 |
|
|
603 | 608 |
properties = {} |
604 | 609 |
for property in self.options.properties or []: |
605 | 610 |
key, sep, val = property.partition('=') |
... | ... | |
613 | 618 |
|
614 | 619 |
@command(api='image') |
615 | 620 |
class glance_members(object): |
616 |
"""get image members"""
|
|
621 |
"""Get image members"""
|
|
617 | 622 |
|
618 | 623 |
def main(self, image_id): |
619 | 624 |
members = self.client.list_members(image_id) |
... | ... | |
623 | 628 |
|
624 | 629 |
@command(api='image') |
625 | 630 |
class glance_shared(object): |
626 |
"""list shared images"""
|
|
631 |
"""List shared images"""
|
|
627 | 632 |
|
628 | 633 |
def main(self, member): |
629 | 634 |
images = self.client.list_shared(member) |
... | ... | |
633 | 638 |
|
634 | 639 |
@command(api='image') |
635 | 640 |
class glance_addmember(object): |
636 |
"""add a member to an image"""
|
|
641 |
"""Add a member to an image"""
|
|
637 | 642 |
|
638 | 643 |
def main(self, image_id, member): |
639 | 644 |
self.client.add_member(image_id, member) |
... | ... | |
641 | 646 |
|
642 | 647 |
@command(api='image') |
643 | 648 |
class glance_delmember(object): |
644 |
"""remove a member from an image"""
|
|
649 |
"""Remove a member from an image"""
|
|
645 | 650 |
|
646 | 651 |
def main(self, image_id, member): |
647 | 652 |
self.client.remove_member(image_id, member) |
... | ... | |
649 | 654 |
|
650 | 655 |
@command(api='image') |
651 | 656 |
class glance_setmembers(object): |
652 |
"""set the members of an image"""
|
|
657 |
"""Set the members of an image"""
|
|
653 | 658 |
|
654 | 659 |
def main(self, image_id, *member): |
655 | 660 |
self.client.set_members(image_id, member) |
... | ... | |
660 | 665 |
|
661 | 666 |
def update_parser(cls, parser): |
662 | 667 |
parser.add_option('--account', dest='account', metavar='NAME', |
663 |
help='use account NAME')
|
|
668 |
help="Specify an account to use")
|
|
664 | 669 |
parser.add_option('--container', dest='container', metavar='NAME', |
665 |
help='use container NAME')
|
|
670 |
help="Specify a container to use")
|
|
666 | 671 |
|
667 |
def main(self): |
|
668 |
self.config.override('storage_account', self.options.account) |
|
669 |
self.config.override('storage_container', self.options.container) |
|
672 |
def progress(self, message): |
|
673 |
"""Return a generator function to be used for progress tracking""" |
|
674 |
|
|
675 |
MESSAGE_LENGTH = 25 |
|
676 |
MAX_PROGRESS_LENGTH = 32 |
|
677 |
|
|
678 |
def progress_gen(n): |
|
679 |
msg = message.ljust(MESSAGE_LENGTH) |
|
680 |
width = min(n, MAX_PROGRESS_LENGTH) |
|
681 |
hide = self.config.get('global', 'silent') or (n < 2) |
|
682 |
for i in progress.bar(range(n), msg, width, hide): |
|
683 |
yield |
|
684 |
yield |
|
670 | 685 |
|
671 |
# Use the more efficient Pithos client if available |
|
672 |
if 'pithos' in self.config.get('apis').split(): |
|
673 |
self.client = clients.PithosClient(self.config) |
|
686 |
return progress_gen |
|
687 |
|
|
688 |
def main(self): |
|
689 |
if self.options.account is not None: |
|
690 |
self.client.account = self.options.account |
|
691 |
if self.options.container is not None: |
|
692 |
self.client.container = self.options.container |
|
674 | 693 |
|
675 | 694 |
|
676 | 695 |
@command(api='storage') |
677 | 696 |
class store_create(object): |
678 |
"""create a container"""
|
|
697 |
"""Create a container"""
|
|
679 | 698 |
|
680 | 699 |
def update_parser(cls, parser): |
681 |
parser.add_option('--account', dest='account', metavar='ACCOUNT',
|
|
682 |
help='use account ACCOUNT')
|
|
700 |
parser.add_option('--account', dest='account', metavar='NAME',
|
|
701 |
help="Specify an account to use")
|
|
683 | 702 |
|
684 | 703 |
def main(self, container): |
685 |
self.config.override('storage_account', self.options.account) |
|
704 |
if self.options.account: |
|
705 |
self.client.account = self.options.account |
|
686 | 706 |
self.client.create_container(container) |
687 | 707 |
|
688 | 708 |
|
689 | 709 |
@command(api='storage') |
690 |
class store_container(store_command):
|
|
691 |
"""get container info"""
|
|
710 |
class store_container(object):
|
|
711 |
"""Get container info"""
|
|
692 | 712 |
|
693 |
def main(self): |
|
694 |
store_command.main(self) |
|
695 |
reply = self.client.get_container_meta() |
|
713 |
def update_parser(cls, parser): |
|
714 |
parser.add_option('--account', dest='account', metavar='NAME', |
|
715 |
help="Specify an account to use") |
|
716 |
|
|
717 |
def main(self, container): |
|
718 |
if self.options.account: |
|
719 |
self.client.account = self.options.account |
|
720 |
reply = self.client.get_container_meta(container) |
|
696 | 721 |
print_dict(reply) |
697 | 722 |
|
698 | 723 |
|
699 | 724 |
@command(api='storage') |
700 | 725 |
class store_upload(store_command): |
701 |
"""upload a file"""
|
|
726 |
"""Upload a file"""
|
|
702 | 727 |
|
703 | 728 |
def main(self, path, remote_path=None): |
704 |
store_command.main(self) |
|
729 |
super(store_upload, self).main() |
|
730 |
|
|
705 | 731 |
if remote_path is None: |
706 | 732 |
remote_path = basename(path) |
707 | 733 |
with open(path) as f: |
708 |
self.client.create_object(remote_path, f) |
|
734 |
hash_cb = self.progress('Calculating block hashes') |
|
735 |
upload_cb = self.progress('Uploading blocks') |
|
736 |
self.client.create_object(remote_path, f, hash_cb=hash_cb, |
|
737 |
upload_cb=upload_cb) |
|
709 | 738 |
|
710 | 739 |
|
711 | 740 |
@command(api='storage') |
712 | 741 |
class store_download(store_command): |
713 |
"""download a file""" |
|
714 |
|
|
715 |
def main(self, remote_path, local_path): |
|
716 |
store_command.main(self) |
|
717 |
f = self.client.get_object(remote_path) |
|
742 |
"""Download a file""" |
|
743 |
|
|
744 |
def main(self, remote_path, local_path='-'): |
|
745 |
super(store_download, self).main() |
|
746 |
|
|
747 |
f, size = self.client.get_object(remote_path) |
|
718 | 748 |
out = open(local_path, 'w') if local_path != '-' else stdout |
719 |
block = 4096 |
|
720 |
data = f.read(block) |
|
749 |
|
|
750 |
blocksize = 4 * 1024**2 |
|
751 |
nblocks = 1 + (size - 1) // blocksize |
|
752 |
|
|
753 |
cb = self.progress('Downloading blocks') if local_path != '-' else None |
|
754 |
if cb: |
|
755 |
gen = cb(nblocks) |
|
756 |
gen.next() |
|
757 |
|
|
758 |
data = f.read(blocksize) |
|
721 | 759 |
while data: |
722 | 760 |
out.write(data) |
723 |
data = f.read(block) |
|
761 |
data = f.read(blocksize) |
|
762 |
if cb: |
|
763 |
gen.next() |
|
724 | 764 |
|
725 | 765 |
|
726 | 766 |
@command(api='storage') |
727 | 767 |
class store_delete(store_command): |
728 |
"""delete a file"""
|
|
768 |
"""Delete a file"""
|
|
729 | 769 |
|
730 | 770 |
def main(self, path): |
731 | 771 |
store_command.main(self) |
... | ... | |
751 | 791 |
puts(columns([name, 12], [cls.description, 60])) |
752 | 792 |
|
753 | 793 |
|
794 |
def add_handler(name, level, prefix=''): |
|
795 |
h = logging.StreamHandler() |
|
796 |
fmt = logging.Formatter(prefix + '%(message)s') |
|
797 |
h.setFormatter(fmt) |
|
798 |
logger = logging.getLogger(name) |
|
799 |
logger.addHandler(h) |
|
800 |
logger.setLevel(level) |
|
801 |
|
|
802 |
|
|
754 | 803 |
def main(): |
755 | 804 |
parser = OptionParser(add_help_option=False) |
756 | 805 |
parser.usage = '%prog <group> <command> [options]' |
... | ... | |
759 | 808 |
help="Show this help message and exit") |
760 | 809 |
parser.add_option('--config', dest='config', metavar='PATH', |
761 | 810 |
help="Specify the path to the configuration file") |
811 |
parser.add_option('-d', '--debug', dest='debug', action='store_true', |
|
812 |
default=False, |
|
813 |
help="Include debug output") |
|
762 | 814 |
parser.add_option('-i', '--include', dest='include', action='store_true', |
763 | 815 |
default=False, |
764 | 816 |
help="Include protocol headers in the output") |
... | ... | |
780 | 832 |
print "kamaki %s" % kamaki.__version__ |
781 | 833 |
exit(0) |
782 | 834 |
|
783 |
if args.contains(['-s', '--silent']): |
|
784 |
level = logging.CRITICAL |
|
785 |
elif args.contains(['-v', '--verbose']): |
|
786 |
level = logging.INFO |
|
787 |
else: |
|
788 |
level = logging.WARNING |
|
789 |
|
|
790 |
logging.basicConfig(level=level, format='%(message)s') |
|
791 |
|
|
792 | 835 |
if '--config' in args: |
793 | 836 |
config_path = args.grouped['--config'].get(0) |
794 | 837 |
else: |
... | ... | |
859 | 902 |
if hasattr(cmd, 'update_parser'): |
860 | 903 |
cmd.update_parser(parser) |
861 | 904 |
|
862 |
if args.contains(['-h', '--help']): |
|
905 |
options, arguments = parser.parse_args(argv) |
|
906 |
|
|
907 |
if options.help: |
|
863 | 908 |
parser.print_help() |
864 | 909 |
exit(0) |
865 | 910 |
|
866 |
cmd.options, cmd.args = parser.parse_args(argv) |
|
911 |
if options.silent: |
|
912 |
add_handler('', logging.CRITICAL) |
|
913 |
elif options.debug: |
|
914 |
add_handler('requests', logging.INFO, prefix='* ') |
|
915 |
add_handler('clients.send', logging.DEBUG, prefix='> ') |
|
916 |
add_handler('clients.recv', logging.DEBUG, prefix='< ') |
|
917 |
elif options.verbose: |
|
918 |
add_handler('requests', logging.INFO, prefix='* ') |
|
919 |
add_handler('clients.send', logging.INFO, prefix='> ') |
|
920 |
add_handler('clients.recv', logging.INFO, prefix='< ') |
|
921 |
elif options.include: |
|
922 |
add_handler('clients.recv', logging.INFO) |
|
923 |
else: |
|
924 |
add_handler('', logging.WARNING) |
|
867 | 925 |
|
868 | 926 |
api = cmd.api |
869 |
if api == 'config': |
|
870 |
cmd.config = config |
|
871 |
elif api in ('compute', 'image', 'storage'): |
|
872 |
token = config.get(api, 'token') or config.get('gobal', 'token') |
|
873 |
url = config.get(api, 'url') |
|
874 |
client_cls = getattr(clients, api) |
|
875 |
kwargs = dict(base_url=url, token=token) |
|
876 |
|
|
877 |
# Special cases |
|
878 |
if api == 'compute' and config.getboolean(api, 'cyclades_extensions'): |
|
879 |
client_cls = clients.cyclades |
|
880 |
elif api == 'storage': |
|
881 |
kwargs['account'] = config.get(api, 'account') |
|
882 |
kwargs['container'] = config.get(api, 'container') |
|
883 |
if config.getboolean(api, 'pithos_extensions'): |
|
884 |
client_cls = clients.pithos |
|
885 |
|
|
886 |
cmd.client = client_cls(**kwargs) |
|
887 |
|
|
927 |
if api in ('compute', 'cyclades'): |
|
928 |
url = config.get('compute', 'url') |
|
929 |
token = config.get('compute', 'token') or config.get('global', 'token') |
|
930 |
if config.getboolean('compute', 'cyclades_extensions'): |
|
931 |
cmd.client = clients.cyclades(url, token) |
|
932 |
else: |
|
933 |
cmd.client = clients.compute(url, token) |
|
934 |
elif api in ('storage', 'pithos'): |
|
935 |
url = config.get('storage', 'url') |
|
936 |
token = config.get('storage', 'token') or config.get('global', 'token') |
|
937 |
account = config.get('storage', 'account') |
|
938 |
container = config.get('storage', 'container') |
|
939 |
if config.getboolean('storage', 'pithos_extensions'): |
|
940 |
cmd.client = clients.pithos(url, token, account, container) |
|
941 |
else: |
|
942 |
cmd.client = clients.storage(url, token, account, container) |
|
943 |
elif api == 'image': |
|
944 |
url = config.get('image', 'url') |
|
945 |
token = config.get('image', 'token') or config.get('global', 'token') |
|
946 |
cmd.client = clients.image(url, token) |
|
947 |
|
|
948 |
cmd.options = options |
|
949 |
cmd.config = config |
|
950 |
|
|
888 | 951 |
try: |
889 |
ret = cmd.main(*args.grouped['_'][2:])
|
|
952 |
ret = cmd.main(*arguments[3:])
|
|
890 | 953 |
exit(ret) |
891 | 954 |
except TypeError as e: |
892 | 955 |
if e.args and e.args[0].startswith('main()'): |
... | ... | |
894 | 957 |
exit(1) |
895 | 958 |
else: |
896 | 959 |
raise |
897 |
except clients.ClientError, err: |
|
898 |
log.error('%s', err.message) |
|
899 |
log.info('%s', err.details) |
|
960 |
except clients.ClientError as err: |
|
961 |
if err.status == 404: |
|
962 |
color = yellow |
|
963 |
elif 500 <= err.status < 600: |
|
964 |
color = magenta |
|
965 |
else: |
|
966 |
color = red |
|
967 |
|
|
968 |
puts_err(color(err.message)) |
|
969 |
if err.details and (options.verbose or options.debug): |
|
970 |
puts_err(err.details) |
|
900 | 971 |
exit(2) |
972 |
except ConnectionError as err: |
|
973 |
puts_err(red("Connection error")) |
|
974 |
exit(1) |
|
901 | 975 |
|
902 | 976 |
|
903 | 977 |
if __name__ == '__main__': |
Also available in: Unified diff