Chromium Code Reviews| 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 |