OLD | NEW |
---|---|
1 # Copyright 2011 Google Inc. All Rights Reserved. | 1 # Copyright 2011 Google Inc. All Rights Reserved. |
2 # | 2 # |
3 # Licensed under the Apache License, Version 2.0 (the "License"); | 3 # Licensed under the Apache License, Version 2.0 (the "License"); |
4 # you may not use this file except in compliance with the License. | 4 # you may not use this file except in compliance with the License. |
5 # You may obtain a copy of the License at | 5 # You may obtain a copy of the License at |
6 # | 6 # |
7 # http://www.apache.org/licenses/LICENSE-2.0 | 7 # http://www.apache.org/licenses/LICENSE-2.0 |
8 # | 8 # |
9 # Unless required by applicable law or agreed to in writing, software | 9 # Unless required by applicable law or agreed to in writing, software |
10 # distributed under the License is distributed on an "AS IS" BASIS, | 10 # distributed under the License is distributed on an "AS IS" BASIS, |
(...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
428 if hasattr(os, 'O_NOINHERIT'): | 428 if hasattr(os, 'O_NOINHERIT'): |
429 flags |= os.O_NOINHERIT | 429 flags |= os.O_NOINHERIT |
430 try: | 430 try: |
431 fd = os.open(file_path, flags, 0600) | 431 fd = os.open(file_path, flags, 0600) |
432 except (OSError, IOError), e: | 432 except (OSError, IOError), e: |
433 raise CommandException('Failed to open %s for writing: %s' % | 433 raise CommandException('Failed to open %s for writing: %s' % |
434 (file_path, e)) | 434 (file_path, e)) |
435 return os.fdopen(fd, 'w') | 435 return os.fdopen(fd, 'w') |
436 | 436 |
437 def _WriteBotoConfigFile(self, config_file, use_oauth2=True, | 437 def _WriteBotoConfigFile(self, config_file, use_oauth2=True, |
438 launch_browser=True, oauth2_scopes=[SCOPE_FULL_CONTROL]): | 438 oauth2_scopes=[SCOPE_FULL_CONTROL]): |
439 """Creates a boto config file interactively. | 439 """Creates a boto config file interactively. |
440 | 440 |
441 Needed credentials are obtained interactively, either by asking the user for | 441 Needed credentials are obtained interactively, either by asking the user for |
442 access key and secret, or by walking the user through the OAuth2 approval | 442 access key and secret, or by walking the user through the OAuth2 approval |
443 flow. | 443 flow. |
444 | 444 |
445 Args: | 445 Args: |
446 config_file: File object to which the resulting config file will be | 446 config_file: File object to which the resulting config file will be |
447 written. | 447 written. |
448 use_oauth2: If True, walk user through OAuth2 approval flow and produce a | 448 use_oauth2: If True, walk user through OAuth2 approval flow and produce a |
449 config with an oauth2_refresh_token credential. If false, ask the | 449 config with an oauth2_refresh_token credential. If false, ask the |
450 user for access key and secret. | 450 user for access key and secret. |
451 launch_browser: In the OAuth2 approval flow, attempt to open a browser | 451 launch_browser: In the OAuth2 approval flow, attempt to open a browser |
452 window and navigate to the approval URL. | 452 window and navigate to the approval URL. |
453 oauth2_scopes: A list of OAuth2 scopes to request authorization for, when | 453 oauth2_scopes: A list of OAuth2 scopes to request authorization for, when |
454 using OAuth2. | 454 using OAuth2. |
455 """ | 455 """ |
456 | 456 |
457 # Collect credentials | 457 # Collect credentials |
458 provider_map = {'aws': 'aws', 'google': 'gs'} | 458 provider_map = {'aws': 'aws', 'google': 'gs'} |
459 uri_map = {'aws': 's3', 'google': 'gs'} | 459 uri_map = {'aws': 's3', 'google': 'gs'} |
460 key_ids = {} | 460 key_ids = {} |
461 sec_keys = {} | 461 sec_keys = {} |
462 if use_oauth2: | 462 if use_oauth2: |
463 oauth2_refresh_token = oauth2_helper.OAuth2ApprovalFlow( | 463 oauth2_refresh_token = oauth2_helper.OAuth2ApprovalFlow( |
464 oauth2_helper.OAuth2ClientFromBotoConfig(boto.config), | 464 oauth2_helper.OAuth2ClientFromBotoConfig(boto.config), |
465 oauth2_scopes, launch_browser) | 465 oauth2_scopes) |
466 else: | 466 else: |
467 got_creds = False | 467 got_creds = False |
468 for provider in provider_map: | 468 for provider in provider_map: |
469 if provider == 'google': | 469 if provider == 'google': |
470 key_ids[provider] = raw_input('What is your %s access key ID? ' % | 470 key_ids[provider] = raw_input('What is your %s access key ID? ' % |
471 provider) | 471 provider) |
472 sec_keys[provider] = raw_input('What is your %s secret access key? ' % | 472 sec_keys[provider] = raw_input('What is your %s secret access key? ' % |
473 provider) | 473 provider) |
474 got_creds = True | 474 got_creds = True |
475 if not key_ids[provider] or not sec_keys[provider]: | 475 if not key_ids[provider] or not sec_keys[provider]: |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
533 # Write the default API version. | 533 # Write the default API version. |
534 config_file.write(""" | 534 config_file.write(""" |
535 # 'default_api_version' specifies the default Google Cloud Storage API | 535 # 'default_api_version' specifies the default Google Cloud Storage API |
536 # version to use. If not set below gsutil defaults to API version 1. | 536 # version to use. If not set below gsutil defaults to API version 1. |
537 """) | 537 """) |
538 api_version = 2 | 538 api_version = 2 |
539 if not use_oauth2: api_version = 1 | 539 if not use_oauth2: api_version = 1 |
540 | 540 |
541 config_file.write('default_api_version = %d\n' % api_version) | 541 config_file.write('default_api_version = %d\n' % api_version) |
542 | 542 |
543 # Write the config file GSUtil section that includes the default | 543 default_project_id = '0' |
544 # project ID input from the user. | |
545 if launch_browser: | |
546 sys.stdout.write( | |
547 'Attempting to launch a browser to open the Google API console at ' | |
548 'URL: %s\n\n' | |
549 '[Note: due to a Python bug, you may see a spurious error message ' | |
550 '"object is not\n callable [...] in [...] Popen.__del__" which can ' | |
551 'be ignored.]\n\n' % GOOG_API_CONSOLE_URI) | |
552 sys.stdout.write( | |
553 'In your browser you should see the API Console. Click "Storage" and ' | |
554 'look for the value under "Identifying your project\n\n') | |
555 if not webbrowser.open(GOOG_API_CONSOLE_URI, new=1, autoraise=True): | |
556 sys.stdout.write( | |
557 'Launching browser appears to have failed; please navigate a ' | |
558 'browser to the following URL:\n%s\n' % GOOG_API_CONSOLE_URI) | |
559 # Short delay; webbrowser.open on linux insists on printing out a message | |
560 # which we don't want to run into the prompt for the auth code. | |
561 time.sleep(2) | |
562 else: | |
563 sys.stdout.write( | |
564 '\nPlease navigate your browser to %s,\nthen click "Services" on the ' | |
565 'left side panel and ensure you have Google Cloud\nStorage' | |
566 'activated, then click "Google Cloud Storage" on the left side ' | |
567 'panel and\nfind the "x-goog-project-id" on that page.\n' % | |
568 GOOG_API_CONSOLE_URI) | |
569 default_project_id = raw_input('What is your project-id? ') | |
570 project_id_section_prelude = """ | 544 project_id_section_prelude = """ |
571 # 'default_project_id' specifies the default Google Cloud Storage project ID to | 545 # 'default_project_id' specifies the default Google Cloud Storage project ID to |
572 # use with the 'mb' and 'ls' commands. If defined it overrides the default value | 546 # use with the 'mb' and 'ls' commands. If defined it overrides the default value |
573 # you set in the API Console. Either of these defaults can be overridden | 547 # you set in the API Console. Either of these defaults can be overridden |
574 # by specifying the -p option to the 'mb' and 'ls' commands. | 548 # by specifying the -p option to the 'mb' and 'ls' commands. |
575 """ | 549 """ |
576 if default_project_id: | 550 config_file.write('%sdefault_project_id = %s\n\n\n' % |
M-A Ruel
2014/04/02 21:29:43
this change is not necessary.
Ryan Tseng
2014/04/02 22:07:03
I could leave it in but it will be unreachable cod
| |
577 config_file.write('%sdefault_project_id = %s\n\n\n' % | 551 (project_id_section_prelude, default_project_id)) |
578 (project_id_section_prelude, default_project_id)) | |
579 else: | |
580 sys.stderr.write('No default project ID entered. You will need to edit ' | |
581 'the default_project_id value\nin your boto config file ' | |
582 'before using "gsutil ls gs://" or "mb" commands' | |
583 'with the\ndefault API version (2).\n') | |
584 config_file.write('%s#default_project_id = <value>\n\n\n' % | |
585 project_id_section_prelude) | |
586 | 552 |
587 # Write the config file OAuth2 section. | 553 # Write the config file OAuth2 section. |
588 config_file.write(CONFIG_OAUTH2_CONFIG_CONTENT) | 554 config_file.write(CONFIG_OAUTH2_CONFIG_CONTENT) |
589 | 555 |
590 # Command entry point. | 556 # Command entry point. |
591 def RunCommand(self): | 557 def RunCommand(self): |
592 scopes = [] | 558 scopes = [] |
593 use_oauth2 = True | 559 use_oauth2 = True |
594 launch_browser = False | 560 launch_browser = False |
595 output_file_name = None | 561 output_file_name = None |
(...skipping 20 matching lines...) Expand all Loading... | |
616 'see README for details);\n' | 582 'see README for details);\n' |
617 'you are running Python %s.\nUse "gsutil config -a" to create a ' | 583 'you are running Python %s.\nUse "gsutil config -a" to create a ' |
618 'config with Developer Key authentication credentials.' % sys.version) | 584 'config with Developer Key authentication credentials.' % sys.version) |
619 | 585 |
620 if not scopes: | 586 if not scopes: |
621 scopes.append(SCOPE_FULL_CONTROL) | 587 scopes.append(SCOPE_FULL_CONTROL) |
622 | 588 |
623 if output_file_name is None: | 589 if output_file_name is None: |
624 # Check to see if a default config file name is requested via | 590 # Check to see if a default config file name is requested via |
625 # environment variable. If so, use it, otherwise use the hard-coded | 591 # environment variable. If so, use it, otherwise use the hard-coded |
626 # default file. Then use the default config file name, if it doesn't | 592 # default file. Then use the default config file name, if it doesn't |
M-A Ruel
2014/04/02 21:29:43
I'd recommend to not change third party whitespace
Ryan Tseng
2014/04/02 22:07:03
Done.
| |
627 # exist or can be moved out of the way without clobbering an existing | 593 # exist or can be moved out of the way without clobbering an existing |
628 # backup file. | 594 # backup file. |
629 boto_config_from_env = os.environ.get('BOTO_CONFIG', None) | 595 boto_config_from_env = os.environ.get('BOTO_CONFIG', None) |
630 if boto_config_from_env: | 596 if boto_config_from_env: |
631 default_config_path = boto_config_from_env | 597 default_config_path = boto_config_from_env |
632 else: | 598 else: |
633 default_config_path = os.path.expanduser(os.path.join('~', '.boto')) | 599 default_config_path = os.path.expanduser(os.path.join('~', '.boto')) |
634 if not os.path.exists(default_config_path): | 600 if not os.path.exists(default_config_path): |
635 output_file_name = default_config_path | 601 output_file_name = default_config_path |
636 default_config_path_bak = None | 602 default_config_path_bak = None |
637 else: | 603 else: |
(...skipping 11 matching lines...) Expand all Loading... | |
649 except e: | 615 except e: |
650 raise CommandException('Failed to back up existing config ' | 616 raise CommandException('Failed to back up existing config ' |
651 'file ("%s" -> "%s"): %s.' | 617 'file ("%s" -> "%s"): %s.' |
652 % (default_config_path, default_config_path_bak, e)) | 618 % (default_config_path, default_config_path_bak, e)) |
653 output_file_name = default_config_path | 619 output_file_name = default_config_path |
654 | 620 |
655 if output_file_name == '-': | 621 if output_file_name == '-': |
656 output_file = sys.stdout | 622 output_file = sys.stdout |
657 else: | 623 else: |
658 output_file = self._OpenConfigFile(output_file_name) | 624 output_file = self._OpenConfigFile(output_file_name) |
659 sys.stderr.write( | |
660 'This script will create a boto config file at\n%s\ncontaining your ' | |
661 'credentials, based on your responses to the following questions.\n\n' | |
662 % output_file_name) | |
663 | 625 |
664 # Catch ^C so we can restore the backup. | 626 # Catch ^C so we can restore the backup. |
665 signal.signal(signal.SIGINT, cleanup_handler) | 627 signal.signal(signal.SIGINT, cleanup_handler) |
666 try: | 628 try: |
667 self._WriteBotoConfigFile(output_file, use_oauth2=use_oauth2, | 629 self._WriteBotoConfigFile(output_file, use_oauth2=use_oauth2, |
668 launch_browser=launch_browser, oauth2_scopes=scopes) | 630 oauth2_scopes=scopes) |
669 except Exception, e: | 631 except Exception, e: |
670 user_aborted = isinstance(e, AbortException) | 632 user_aborted = isinstance(e, AbortException) |
671 if user_aborted: | 633 if user_aborted: |
672 sys.stderr.write('\nCaught ^C; cleaning up\n') | 634 sys.stderr.write('\nCaught ^C; cleaning up\n') |
673 # If an error occurred during config file creation, remove the invalid | 635 # If an error occurred during config file creation, remove the invalid |
674 # config file and restore the backup file. | 636 # config file and restore the backup file. |
675 if output_file_name != '-': | 637 if output_file_name != '-': |
676 output_file.close() | 638 output_file.close() |
677 os.unlink(output_file_name) | 639 os.unlink(output_file_name) |
678 if default_config_path_bak: | 640 if default_config_path_bak: |
679 sys.stderr.write('Restoring previous backed up file (%s)\n' % | 641 sys.stderr.write('Restoring previous backed up file (%s)\n' % |
680 default_config_path_bak) | 642 default_config_path_bak) |
681 os.rename(default_config_path_bak, output_file_name) | 643 os.rename(default_config_path_bak, output_file_name) |
682 raise | 644 raise |
683 | 645 |
684 if output_file_name != '-': | 646 if output_file_name != '-': |
685 output_file.close() | 647 output_file.close() |
686 sys.stderr.write( | 648 sys.stderr.write( |
687 '\nBoto config file "%s" created.\nIf you need to use a proxy to ' | 649 '\nBoto config file "%s" created.\n' % output_file_name) |
688 'use a proxy to access the Internet please see the instructions in ' | |
689 'that file.\n' % output_file_name) | |
690 | 650 |
691 return 0 | 651 return 0 |
692 | 652 |
693 def cleanup_handler(signalnum, handler): | 653 def cleanup_handler(signalnum, handler): |
694 raise AbortException('User interrupted config command') | 654 raise AbortException('User interrupted config command') |
OLD | NEW |