| OLD | NEW |
| 1 # -*- coding: utf-8 -*- |
| 1 # Copyright 2011 Google Inc. All Rights Reserved. | 2 # Copyright 2011 Google Inc. All Rights Reserved. |
| 2 # | 3 # |
| 3 # Licensed under the Apache License, Version 2.0 (the "License"); | 4 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 # you may not use this file except in compliance with the License. | 5 # you may not use this file except in compliance with the License. |
| 5 # You may obtain a copy of the License at | 6 # You may obtain a copy of the License at |
| 6 # | 7 # |
| 7 # http://www.apache.org/licenses/LICENSE-2.0 | 8 # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 # | 9 # |
| 9 # Unless required by applicable law or agreed to in writing, software | 10 # Unless required by applicable law or agreed to in writing, software |
| 10 # distributed under the License is distributed on an "AS IS" BASIS, | 11 # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 # See the License for the specific language governing permissions and | 13 # See the License for the specific language governing permissions and |
| 13 # limitations under the License. | 14 # limitations under the License. |
| 15 """Implementation of config command for creating a gsutil configuration file.""" |
| 14 | 16 |
| 15 from __future__ import absolute_import | 17 from __future__ import absolute_import |
| 16 | 18 |
| 17 import datetime | 19 import datetime |
| 20 from httplib import ResponseNotReady |
| 18 import multiprocessing | 21 import multiprocessing |
| 19 import os | 22 import os |
| 20 import platform | 23 import platform |
| 21 import signal | 24 import signal |
| 25 import socket |
| 22 import stat | 26 import stat |
| 23 import sys | 27 import sys |
| 28 import textwrap |
| 24 import time | 29 import time |
| 25 import webbrowser | 30 import webbrowser |
| 26 | 31 |
| 27 import boto | 32 import boto |
| 28 from boto.provider import Provider | 33 from boto.provider import Provider |
| 34 from httplib2 import ServerNotFoundError |
| 35 from oauth2client.client import HAS_CRYPTO |
| 36 |
| 29 import gslib | 37 import gslib |
| 30 from gslib.command import Command | 38 from gslib.command import Command |
| 31 from gslib.command import COMMAND_NAME | |
| 32 from gslib.command import COMMAND_NAME_ALIASES | |
| 33 from gslib.command import FILE_URIS_OK | |
| 34 from gslib.command import MAX_ARGS | |
| 35 from gslib.command import MIN_ARGS | |
| 36 from gslib.command import PROVIDER_URIS_OK | |
| 37 from gslib.command import SUPPORTED_SUB_ARGS | |
| 38 from gslib.command import URIS_START_ARG | |
| 39 from gslib.commands.compose import MAX_COMPONENT_COUNT | 39 from gslib.commands.compose import MAX_COMPONENT_COUNT |
| 40 from gslib.cred_types import CredTypes | 40 from gslib.cred_types import CredTypes |
| 41 from gslib.exception import AbortException | 41 from gslib.exception import AbortException |
| 42 from gslib.exception import CommandException | 42 from gslib.exception import CommandException |
| 43 from gslib.help_provider import HELP_NAME | |
| 44 from gslib.help_provider import HELP_NAME_ALIASES | |
| 45 from gslib.help_provider import HELP_ONE_LINE_SUMMARY | |
| 46 from gslib.help_provider import HELP_TEXT | |
| 47 from gslib.help_provider import HELP_TYPE | |
| 48 from gslib.help_provider import HelpType | |
| 49 from gslib.util import IS_WINDOWS | 43 from gslib.util import IS_WINDOWS |
| 50 from gslib.util import TWO_MB | 44 from gslib.util import TWO_MB |
| 51 from httplib import ResponseNotReady | |
| 52 from httplib2 import ServerNotFoundError | |
| 53 from oauth2client.client import HAS_CRYPTO | |
| 54 import textwrap | |
| 55 from textwrap import TextWrapper | |
| 56 | 45 |
| 57 _detailed_help_text = (""" | 46 |
| 47 _DETAILED_HELP_TEXT = (""" |
| 58 <B>SYNOPSIS</B> | 48 <B>SYNOPSIS</B> |
| 59 gsutil [-D] config [-a] [-b] [-e] [-f] [-o <file>] [-r] [-s <scope>] [-w] | 49 gsutil [-D] config [-a] [-b] [-e] [-f] [-o <file>] [-r] [-s <scope>] [-w] |
| 60 | 50 |
| 61 | 51 |
| 62 <B>DESCRIPTION</B> | 52 <B>DESCRIPTION</B> |
| 63 The gsutil config command obtains access credentials for Google Cloud | 53 The gsutil config command obtains access credentials for Google Cloud |
| 64 Storage and writes a boto/gsutil configuration file containing the obtained | 54 Storage and writes a boto/gsutil configuration file containing the obtained |
| 65 credentials along with a number of other configuration-controllable values. | 55 credentials along with a number of other configuration-controllable values. |
| 66 | 56 |
| 67 Unless specified otherwise (see OPTIONS), the configuration file is written | 57 Unless specified otherwise (see OPTIONS), the configuration file is written |
| (...skipping 19 matching lines...) Expand all Loading... |
| 87 | 77 |
| 88 If you want to use credentials based on access key and secret (the older | 78 If you want to use credentials based on access key and secret (the older |
| 89 authentication method before OAuth2 was supported) instead of OAuth2, | 79 authentication method before OAuth2 was supported) instead of OAuth2, |
| 90 see help about the -a option in the OPTIONS section. | 80 see help about the -a option in the OPTIONS section. |
| 91 | 81 |
| 92 If you wish to use gsutil with other providers (or to copy data back and | 82 If you wish to use gsutil with other providers (or to copy data back and |
| 93 forth between multiple providers) you can edit their credentials into the | 83 forth between multiple providers) you can edit their credentials into the |
| 94 [Credentials] section after creating the initial configuration file. | 84 [Credentials] section after creating the initial configuration file. |
| 95 | 85 |
| 96 | 86 |
| 97 | |
| 98 <B>CONFIGURING SERVICE ACCOUNT CREDENTIALS</B> | 87 <B>CONFIGURING SERVICE ACCOUNT CREDENTIALS</B> |
| 99 You can configure credentials for service accounts using the gsutil config -e | 88 You can configure credentials for service accounts using the gsutil config -e |
| 100 option. Service accounts are useful for authenticating on behalf of a service | 89 option. Service accounts are useful for authenticating on behalf of a service |
| 101 or application (as opposed to a user). | 90 or application (as opposed to a user). |
| 102 | 91 |
| 103 When you run gsutil config -e, you will be prompted for your service account | 92 When you run gsutil config -e, you will be prompted for your service account |
| 104 email address and the path to your private key file. To get these data, visit | 93 email address and the path to your private key file. To get these data, visit |
| 105 the `Google Cloud Console <https://cloud.google.com/console#/project>`_, click | 94 the `Google Developers Console <https://cloud.google.com/console#/project>`_, |
| 106 on the project you are using, then click "APIs & auth", then click "Registered | 95 click on the project you are using, then click "APIs & auth", then click |
| 107 apps", then click on the name of the registered app. (Note: for service | 96 "Credentials", then click "CREATE NEW CLIENT ID"; on the pop-up dialog box |
| 108 accounts created via the older API Developer's Console, the name will be | 97 select "Service account" and click "Create Client ID". This will download |
| 109 something like "Service Account-<service account id>".) This page lists | 98 a private key file, which you should move to somewhere |
| 110 the email address of your service account. From this page you can also click | 99 accessible from the machine where you run gsutil. Make sure to set its |
| 111 Generate New Key, to generate and download the private key file. Save this | 100 protection so only the users you want to be able to authenticate have |
| 112 file somewhere accessible from the machine where you run gsutil. Make sure | 101 access. |
| 113 to set its protection so only the users you want to be able to authenticate | |
| 114 as have access. | |
| 115 | 102 |
| 116 Note that your service account will NOT be considered an Owner for the | 103 Note that your service account will NOT be considered an Owner for the |
| 117 purposes of API access (see "gsutil help creds" for more information about | 104 purposes of API access (see "gsutil help creds" for more information about |
| 118 this). See https://developers.google.com/accounts/docs/OAuth2ServiceAccount | 105 this). See https://developers.google.com/accounts/docs/OAuth2ServiceAccount |
| 119 for further information on service account authentication. | 106 for further information on service account authentication. |
| 120 | 107 |
| 121 | 108 |
| 122 <B>CONFIGURATION FILE SELECTION PROCEDURE</B> | 109 <B>CONFIGURATION FILE SELECTION PROCEDURE</B> |
| 123 By default, gsutil will look for the configuration file in /etc/boto.cfg and | 110 By default, gsutil will look for the configuration file in /etc/boto.cfg and |
| 124 ~/.boto. You can override this choice by setting the BOTO_CONFIG environment | 111 ~/.boto. You can override this choice by setting the BOTO_CONFIG environment |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 157 option-controllable features. | 144 option-controllable features. |
| 158 | 145 |
| 159 The following are the currently defined configuration settings, broken | 146 The following are the currently defined configuration settings, broken |
| 160 down by section. Their use is documented in comments preceding each, in | 147 down by section. Their use is documented in comments preceding each, in |
| 161 the configuration file. If you see a setting you want to change that's not | 148 the configuration file. If you see a setting you want to change that's not |
| 162 listed in your current file, see the section below on Updating to the Latest | 149 listed in your current file, see the section below on Updating to the Latest |
| 163 Configuration File. | 150 Configuration File. |
| 164 | 151 |
| 165 The currently supported settings, are, by section: | 152 The currently supported settings, are, by section: |
| 166 | 153 |
| 154 [Credentials] |
| 155 aws_access_key_id |
| 156 aws_secret_access_key |
| 157 gs_access_key_id |
| 158 gs_host |
| 159 gs_json_host |
| 160 gs_json_port |
| 161 gs_oauth2_refresh_token |
| 162 gs_port |
| 163 gs_secret_access_key |
| 164 s3_host |
| 165 s3_port |
| 166 |
| 167 [Boto] | 167 [Boto] |
| 168 proxy | 168 proxy |
| 169 proxy_port | 169 proxy_port |
| 170 proxy_user | 170 proxy_user |
| 171 proxy_pass | 171 proxy_pass |
| 172 proxy_rdns |
| 172 http_socket_timeout | 173 http_socket_timeout |
| 173 is_secure | |
| 174 https_validate_certificates | 174 https_validate_certificates |
| 175 debug | 175 debug |
| 176 max_retry_delay |
| 176 num_retries | 177 num_retries |
| 177 | 178 |
| 178 [GSUtil] | 179 [GSUtil] |
| 179 resumable_threshold | 180 check_hashes |
| 180 resumable_tracker_dir | 181 content_language |
| 181 software_update_check_period | 182 default_api_version |
| 183 default_project_id |
| 184 json_api_version |
| 185 parallel_composite_upload_component_size |
| 186 parallel_composite_upload_threshold |
| 182 parallel_process_count | 187 parallel_process_count |
| 183 parallel_thread_count | 188 parallel_thread_count |
| 184 parallel_composite_upload_threshold | 189 prefer_api |
| 185 parallel_composite_upload_component_size | 190 resumable_threshold |
| 191 resumable_tracker_dir (deprecated in 4.6, use state_dir) |
| 192 rsync_buffer_lines |
| 193 software_update_check_period |
| 194 state_dir |
| 186 use_magicfile | 195 use_magicfile |
| 187 content_language | |
| 188 check_hashes | |
| 189 default_api_version | |
| 190 default_project_id | |
| 191 discovery_service_url | |
| 192 json_api_version | |
| 193 | 196 |
| 194 [OAuth2] | 197 [OAuth2] |
| 195 token_cache | |
| 196 token_cache | |
| 197 client_id | 198 client_id |
| 198 client_secret | 199 client_secret |
| 200 oauth2_refresh_retries |
| 201 provider_authorization_uri |
| 199 provider_label | 202 provider_label |
| 200 provider_authorization_uri | |
| 201 provider_token_uri | 203 provider_token_uri |
| 202 oauth2_refresh_retries | 204 token_cache |
| 203 | 205 |
| 204 | 206 |
| 205 <B>UPDATING TO THE LATEST CONFIGURATION FILE</B> | 207 <B>UPDATING TO THE LATEST CONFIGURATION FILE</B> |
| 206 We add new configuration controllable features to the boto configuration file | 208 We add new configuration controllable features to the boto configuration file |
| 207 over time, but most gsutil users create a configuration file once and then | 209 over time, but most gsutil users create a configuration file once and then |
| 208 keep it for a long time, so new features aren't apparent when you update | 210 keep it for a long time, so new features aren't apparent when you update |
| 209 to a newer version of gsutil. If you want to get the latest configuration | 211 to a newer version of gsutil. If you want to get the latest configuration |
| 210 file (which includes all the latest settings and documentation about each) | 212 file (which includes all the latest settings and documentation about each) |
| 211 you can rename your current file (e.g., to '.boto_old'), run gsutil config, | 213 you can rename your current file (e.g., to '.boto_old'), run gsutil config, |
| 212 and then edit any configuration settings you wanted from your old file | 214 and then edit any configuration settings you wanted from your old file |
| (...skipping 25 matching lines...) Expand all Loading... |
| 238 | 240 |
| 239 -r Request token restricted to read-only access. | 241 -r Request token restricted to read-only access. |
| 240 | 242 |
| 241 -s <scope> Request additional OAuth2 <scope>. | 243 -s <scope> Request additional OAuth2 <scope>. |
| 242 | 244 |
| 243 -w Request token restricted to read-write access. | 245 -w Request token restricted to read-write access. |
| 244 """) | 246 """) |
| 245 | 247 |
| 246 | 248 |
| 247 try: | 249 try: |
| 248 from gslib.third_party.oauth2_plugin import oauth2_helper | 250 from gcs_oauth2_boto_plugin import oauth2_helper # pylint: disable=g-import-n
ot-at-top |
| 249 except ImportError: | 251 except ImportError: |
| 250 pass | 252 pass |
| 251 | 253 |
| 252 GOOG_CLOUD_CONSOLE_URI = 'https://cloud.google.com/console#/project' | 254 GOOG_CLOUD_CONSOLE_URI = 'https://cloud.google.com/console#/project' |
| 253 | 255 |
| 254 SCOPE_FULL_CONTROL = 'https://www.googleapis.com/auth/devstorage.full_control' | 256 SCOPE_FULL_CONTROL = 'https://www.googleapis.com/auth/devstorage.full_control' |
| 255 SCOPE_READ_WRITE = 'https://www.googleapis.com/auth/devstorage.read_write' | 257 SCOPE_READ_WRITE = 'https://www.googleapis.com/auth/devstorage.read_write' |
| 256 SCOPE_READ_ONLY = 'https://www.googleapis.com/auth/devstorage.read_only' | 258 SCOPE_READ_ONLY = 'https://www.googleapis.com/auth/devstorage.read_only' |
| 257 | 259 |
| 258 CONFIG_PRELUDE_CONTENT = """ | 260 CONFIG_PRELUDE_CONTENT = """ |
| (...skipping 14 matching lines...) Expand all Loading... |
| 273 # On Windows and Mac systems parallel multi-processing and multi-threading | 275 # On Windows and Mac systems parallel multi-processing and multi-threading |
| 274 # in Python presents various challenges so we retain compatibility with | 276 # in Python presents various challenges so we retain compatibility with |
| 275 # the established parallel mode operation, i.e. one process and 24 threads. | 277 # the established parallel mode operation, i.e. one process and 24 threads. |
| 276 if platform.system() == 'Linux': | 278 if platform.system() == 'Linux': |
| 277 DEFAULT_PARALLEL_PROCESS_COUNT = multiprocessing.cpu_count() | 279 DEFAULT_PARALLEL_PROCESS_COUNT = multiprocessing.cpu_count() |
| 278 DEFAULT_PARALLEL_THREAD_COUNT = 10 | 280 DEFAULT_PARALLEL_THREAD_COUNT = 10 |
| 279 else: | 281 else: |
| 280 DEFAULT_PARALLEL_PROCESS_COUNT = 1 | 282 DEFAULT_PARALLEL_PROCESS_COUNT = 1 |
| 281 DEFAULT_PARALLEL_THREAD_COUNT = 24 | 283 DEFAULT_PARALLEL_THREAD_COUNT = 24 |
| 282 | 284 |
| 283 DEFAULT_PARALLEL_COMPOSITE_UPLOAD_THRESHOLD = '150M' | 285 # TODO: Once compiled crcmod is being distributed by major Linux distributions |
| 286 # revert DEFAULT_PARALLEL_COMPOSITE_UPLOAD_THRESHOLD value to '150M'. |
| 287 DEFAULT_PARALLEL_COMPOSITE_UPLOAD_THRESHOLD = '0' |
| 284 DEFAULT_PARALLEL_COMPOSITE_UPLOAD_COMPONENT_SIZE = '50M' | 288 DEFAULT_PARALLEL_COMPOSITE_UPLOAD_COMPONENT_SIZE = '50M' |
| 285 | 289 |
| 290 CHECK_HASH_IF_FAST_ELSE_FAIL = 'if_fast_else_fail' |
| 291 CHECK_HASH_IF_FAST_ELSE_SKIP = 'if_fast_else_skip' |
| 292 CHECK_HASH_ALWAYS = 'always' |
| 293 CHECK_HASH_NEVER = 'never' |
| 294 |
| 286 CONFIG_BOTO_SECTION_CONTENT = """ | 295 CONFIG_BOTO_SECTION_CONTENT = """ |
| 287 [Boto] | 296 [Boto] |
| 288 | 297 |
| 289 # http_socket_timeout specifies the timeout (in seconds) used to tell httplib | 298 # http_socket_timeout specifies the timeout (in seconds) used to tell httplib |
| 290 # how long to wait for socket timeouts. The default is 70 seconds. Note that | 299 # how long to wait for socket timeouts. The default is 70 seconds. Note that |
| 291 # this timeout only applies to httplib, not to httplib2 (which is used for | 300 # this timeout only applies to httplib, not to httplib2 (which is used for |
| 292 # OAuth2 refresh/access token exchanges). | 301 # OAuth2 refresh/access token exchanges). |
| 293 #http_socket_timeout = 70 | 302 #http_socket_timeout = 70 |
| 294 | 303 |
| 295 # The following two options control the use of a secure transport for requests | 304 # The following two options control the use of a secure transport for requests |
| 296 # to S3 and Google Cloud Storage. It is highly recommended to set both options | 305 # to S3 and Google Cloud Storage. It is highly recommended to set both options |
| 297 # to True in production environments, especially when using OAuth2 bearer token | 306 # to True in production environments, especially when using OAuth2 bearer token |
| 298 # authentication with Google Cloud Storage. | 307 # authentication with Google Cloud Storage. |
| 299 | 308 |
| 300 # Set 'is_secure' to False to cause boto to connect using HTTP instead of the | |
| 301 # default HTTPS. This is useful if you want to capture/analyze traffic | |
| 302 # (e.g., with tcpdump). | |
| 303 # WARNING: This option should always be set to True (the default value) in | |
| 304 # production environments, for several reasons: | |
| 305 # 1. OAuth2 refresh and access tokens are bearer tokens, so must be | |
| 306 # protected from exposure on the wire. | |
| 307 # 2. Resumable upload IDs are bearer tokens, so similarly must be protected. | |
| 308 # 3. The gsutil update command needs to run over HTTPS to guard against | |
| 309 # man-in-the-middle attacks on code updates. | |
| 310 # 4. User data shouldn't be sent in the clear. | |
| 311 #is_secure = True | |
| 312 | |
| 313 # Set 'https_validate_certificates' to False to disable server certificate | 309 # Set 'https_validate_certificates' to False to disable server certificate |
| 314 # checking. The default for this option in the boto library is currently | 310 # checking. The default for this option in the boto library is currently |
| 315 # 'False' (to avoid breaking apps that depend on invalid certificates); it is | 311 # 'False' (to avoid breaking apps that depend on invalid certificates); it is |
| 316 # therefore strongly recommended to always set this option explicitly to True | 312 # therefore strongly recommended to always set this option explicitly to True |
| 317 # in configuration files, to protect against "man-in-the-middle" attacks. | 313 # in configuration files, to protect against "man-in-the-middle" attacks. |
| 318 https_validate_certificates = True | 314 https_validate_certificates = True |
| 319 | 315 |
| 320 # 'debug' controls the level of debug messages printed: 0 for none, 1 | 316 # 'debug' controls the level of debug messages printed: 0 for none, 1 |
| 321 # for basic boto debug, 2 for all boto debug plus HTTP requests/responses. | 317 # for basic boto debug, 2 for all boto debug plus HTTP requests/responses. |
| 322 # Note: 'gsutil -d' sets debug to 2 for that one command run. | 318 # Note: 'gsutil -d' sets debug to 2 for that one command run. |
| 323 #debug = <0, 1, or 2> | 319 #debug = <0, 1, or 2> |
| 324 | 320 |
| 325 # 'num_retries' controls the number of retry attempts made when errors occur | 321 # 'num_retries' controls the number of retry attempts made when errors occur |
| 326 # during data transfers. The default is 6. Note: don't set this value to 0, as | 322 # during data transfers. The default is 6. |
| 327 # it will cause boto to fail when reusing HTTP connections. | 323 # Note 1: You can cause gsutil to retry failures effectively infinitely by |
| 324 # setting this value to a large number (like 10000). Doing that could be useful |
| 325 # in cases where your network connection occasionally fails and is down for an |
| 326 # extended period of time, because when it comes back up gsutil will continue |
| 327 # retrying. However, in general we recommend not setting the value above 10, |
| 328 # because otherwise gsutil could appear to "hang" due to excessive retries |
| 329 # (since unless you run gsutil -D you won't see any logged evidence that gsutil |
| 330 # is retrying). |
| 331 # Note 2: Don't set this value to 0, as it will cause boto to fail when reusing |
| 332 # HTTP connections. |
| 328 #num_retries = <integer value> | 333 #num_retries = <integer value> |
| 334 |
| 335 # 'max_retry_delay' controls the max delay (in seconds) between retries. The |
| 336 # default value is 60, so the backoff sequence will be 1 seconds, 2 seconds, 4, |
| 337 # 8, 16, 32, and then 60 for all subsequent retries for a given HTTP request. |
| 338 # Note: At present this value only impacts the XML API and the JSON API uses a |
| 339 # fixed value of 60. |
| 340 #max_retry_delay = <integer value> |
| 329 """ | 341 """ |
| 330 | 342 |
| 331 CONFIG_INPUTLESS_GSUTIL_SECTION_CONTENT = """ | 343 CONFIG_INPUTLESS_GSUTIL_SECTION_CONTENT = """ |
| 332 [GSUtil] | 344 [GSUtil] |
| 333 | 345 |
| 334 # 'resumable_threshold' specifies the smallest file size [bytes] for which | 346 # 'resumable_threshold' specifies the smallest file size [bytes] for which |
| 335 # resumable Google Cloud Storage transfers are attempted. The default is 2097152 | 347 # resumable Google Cloud Storage transfers are attempted. The default is 2097152 |
| 336 # (2 MiB). | 348 # (2 MiB). |
| 337 #resumable_threshold = %(resumable_threshold)d | 349 #resumable_threshold = %(resumable_threshold)d |
| 338 | 350 |
| 339 # 'resumable_tracker_dir' specifies the base location where resumable | 351 # 'rsync_buffer_lines' specifies the number of lines of bucket or directory |
| 340 # transfer tracker files are saved. By default they're in ~/.gsutil | 352 # listings saved in each temp file during sorting. (The complete set is |
| 341 #resumable_tracker_dir = <file path> | 353 # split across temp files and separately sorted/merged, to avoid needing to |
| 342 # gsutil also saves a file called .last_software_update_check in this directory, | 354 # fit everything in memory at once.) If you are trying to synchronize very |
| 343 # that tracks the last time a check was made whether a new version of the gsutil | 355 # large directories/buckets (e.g., containing millions or more objects), |
| 344 # software is available. 'software_update_check_period' specifies the number of | 356 # having too small a value here can cause gsutil to run out of open file |
| 345 # days between such checks. The default is 30. Setting the value to 0 disables | 357 # handles. If that happens, you can try to increase the number of open file |
| 358 # handles your system allows (e.g., see 'man ulimit' on Linux; see also |
| 359 # http://docs.python.org/2/library/resource.html). If you can't do that (or |
| 360 # if you're already at the upper limit), increasing rsync_buffer_lines will |
| 361 # cause gsutil to use fewer file handles, but at the cost of more memory. With |
| 362 # rsync_buffer_lines set to 32000 and assuming a typical URL is 100 bytes |
| 363 # long, gsutil will require approximately 10MB of memory while building |
| 364 # the synchronization state, and will require approximately 60 open file |
| 365 # descriptors to build the synchronization state over all 1M source and 1M |
| 366 # destination URLs. Memory and file descriptors are only consumed while |
| 367 # building the state; once the state is built, it resides in two temp files that |
| 368 # are read and processed incrementally during the actual copy/delete |
| 369 # operations. |
| 370 #rsync_buffer_lines = 32000 |
| 371 |
| 372 # 'state_dir' specifies the base location where files that |
| 373 # need a static location are stored, such as pointers to credentials, |
| 374 # resumable transfer tracker files, and the last software update check. |
| 375 # By default these files are stored in ~/.gsutil |
| 376 #state_dir = <file_path> |
| 377 # gsutil periodically checks whether a new version of the gsutil software is |
| 378 # available. 'software_update_check_period' specifies the number of days |
| 379 # between such checks. The default is 30. Setting the value to 0 disables |
| 346 # periodic software update checks. | 380 # periodic software update checks. |
| 347 #software_update_check_period = 30 | 381 #software_update_check_period = 30 |
| 348 | 382 |
| 349 # 'parallel_process_count' and 'parallel_thread_count' specify the number | 383 # 'parallel_process_count' and 'parallel_thread_count' specify the number |
| 350 # of OS processes and Python threads, respectively, to use when executing | 384 # of OS processes and Python threads, respectively, to use when executing |
| 351 # operations in parallel. The default settings should work well as configured, | 385 # operations in parallel. The default settings should work well as configured, |
| 352 # however, to enhance performance for transfers involving large numbers of | 386 # however, to enhance performance for transfers involving large numbers of |
| 353 # files, you may experiment with hand tuning these values to optimize | 387 # files, you may experiment with hand tuning these values to optimize |
| 354 # performance for your particular system configuration. | 388 # performance for your particular system configuration. |
| 355 # MacOS and Windows users should see | 389 # MacOS and Windows users should see |
| 356 # https://github.com/GoogleCloudPlatform/gsutil/issues/77 before attempting | 390 # https://github.com/GoogleCloudPlatform/gsutil/issues/77 before attempting |
| 357 # to experiment with these values. | 391 # to experiment with these values. |
| 358 #parallel_process_count = %(parallel_process_count)d | 392 #parallel_process_count = %(parallel_process_count)d |
| 359 #parallel_thread_count = %(parallel_thread_count)d | 393 #parallel_thread_count = %(parallel_thread_count)d |
| 360 | 394 |
| 361 # 'parallel_composite_upload_threshold' specifies the maximum size of a file to | 395 # 'parallel_composite_upload_threshold' specifies the maximum size of a file to |
| 362 # upload in a single stream. Files larger than this threshold will be | 396 # upload in a single stream. Files larger than this threshold will be |
| 363 # partitioned into component parts and uploaded in parallel and then composed | 397 # partitioned into component parts and uploaded in parallel and then composed |
| 364 # into a single object. | 398 # into a single object. |
| 365 # The number of components will be the smaller of | 399 # The number of components will be the smaller of |
| 366 # ceil(file_size / parallel_composite_upload_component_size) and | 400 # ceil(file_size / parallel_composite_upload_component_size) and |
| 367 # MAX_COMPONENT_COUNT. The current value of MAX_COMPONENT_COUNT is | 401 # MAX_COMPONENT_COUNT. The current value of MAX_COMPONENT_COUNT is |
| 368 # %(max_component_count)d. | 402 # %(max_component_count)d. |
| 369 # If 'parallel_composite_upload_threshold' is set to 0, then automatic parallel | 403 # If 'parallel_composite_upload_threshold' is set to 0, then automatic parallel |
| 370 # uploads will never occur. | 404 # uploads will never occur. |
| 405 # Setting an extremely low threshold is unadvisable. The vast majority of |
| 406 # environments will see degraded performance for thresholds below 80M, and it |
| 407 # is almost never advantageous to have a threshold below 20M. |
| 371 # 'parallel_composite_upload_component_size' specifies the ideal size of a | 408 # 'parallel_composite_upload_component_size' specifies the ideal size of a |
| 372 # component in bytes, which will act as an upper bound to the size of the | 409 # component in bytes, which will act as an upper bound to the size of the |
| 373 # components if ceil(file_size / parallel_composite_upload_component_size) is | 410 # components if ceil(file_size / parallel_composite_upload_component_size) is |
| 374 # less than MAX_COMPONENT_COUNT. | 411 # less than MAX_COMPONENT_COUNT. |
| 375 # Values can be provided either in bytes or as human-readable values | 412 # Values can be provided either in bytes or as human-readable values |
| 376 # (e.g., "150M" to represent 150 megabytes) | 413 # (e.g., "150M" to represent 150 megabytes) |
| 414 # |
| 415 # Note: At present parallel composite uploads are disabled by default, because |
| 416 # using composite objects requires a compiled crcmod (see "gsutil help crcmod"), |
| 417 # and for operating systems that don't already have this package installed this |
| 418 # makes gsutil harder to use. Google is actively working with a number of the |
| 419 # Linux distributions to get crcmod included with the stock distribution. Once |
| 420 # that is done we will re-enable parallel composite uploads by default in |
| 421 # gsutil. |
| 377 #parallel_composite_upload_threshold = %(parallel_composite_upload_threshold)s | 422 #parallel_composite_upload_threshold = %(parallel_composite_upload_threshold)s |
| 378 #parallel_composite_upload_component_size = %(parallel_composite_upload_componen
t_size)s | 423 #parallel_composite_upload_component_size = %(parallel_composite_upload_componen
t_size)s |
| 379 | 424 |
| 380 # 'use_magicfile' specifies if the 'file --mime-type <filename>' command should | 425 # 'use_magicfile' specifies if the 'file --mime-type <filename>' command should |
| 381 # be used to guess content types instead of the default filename extension-based | 426 # be used to guess content types instead of the default filename extension-based |
| 382 # mechanism. Available on UNIX and MacOS (and possibly on Windows, if you're | 427 # mechanism. Available on UNIX and MacOS (and possibly on Windows, if you're |
| 383 # running Cygwin or some other package that provides implementations of | 428 # running Cygwin or some other package that provides implementations of |
| 384 # UNIX-like commands). When available and enabled use_magicfile should be more | 429 # UNIX-like commands). When available and enabled use_magicfile should be more |
| 385 # robust because it analyzes file contents in addition to extensions. | 430 # robust because it analyzes file contents in addition to extensions. |
| 386 #use_magicfile = False | 431 #use_magicfile = False |
| 387 | 432 |
| 388 # 'content_language' specifies the ISO 639-1 language code of the content, to be | 433 # 'content_language' specifies the ISO 639-1 language code of the content, to be |
| 389 # passed in the Content-Language header. By default no Content-Language is sent. | 434 # passed in the Content-Language header. By default no Content-Language is sent. |
| 390 # See the ISO 639-1 column of | 435 # See the ISO 639-1 column of |
| 391 # http://www.loc.gov/standards/iso639-2/php/code_list.php for a list of | 436 # http://www.loc.gov/standards/iso639-2/php/code_list.php for a list of |
| 392 # language codes. | 437 # language codes. |
| 393 content_language = en | 438 content_language = en |
| 394 | 439 |
| 395 # 'check_hashes' specifies how strictly to require integrity checking for | 440 # 'check_hashes' specifies how strictly to require integrity checking for |
| 396 # downloaded data. Legal values are: | 441 # downloaded data. Legal values are: |
| 397 # 'if_fast_else_fail' - (default) Only integrity check if the digest will run | 442 # '%(hash_fast_else_fail)s' - (default) Only integrity check if the digest |
| 398 # efficiently (using compiled code), else fail the download. | 443 # will run efficiently (using compiled code), else fail the download. |
| 399 # 'if_fast_else_skip' - Only integrity check if the server supplies a hash and | 444 # '%(hash_fast_else_skip)s' - Only integrity check if the server supplies a |
| 400 # the local digest computation will run quickly, else skip the check. | 445 # hash and the local digest computation will run quickly, else skip the |
| 401 # 'always' - Always check download integrity regardless of possible | 446 # check. |
| 447 # '%(hash_always)s' - Always check download integrity regardless of possible |
| 402 # performance costs. | 448 # performance costs. |
| 403 # 'never' - Don't perform download integrity checks. This settings is not | 449 # '%(hash_never)s' - Don't perform download integrity checks. This setting is |
| 404 # recommended except for special cases such as measuring download | 450 # not recommended except for special cases such as measuring download |
| 405 # performance excluding time for integrity checking. | 451 # performance excluding time for integrity checking. |
| 406 # This option exists to assist users who wish to download a GCS composite object | 452 # This option exists to assist users who wish to download a GCS composite object |
| 407 # and are unable to install crcmod with the C-extension. CRC32c is the only | 453 # and are unable to install crcmod with the C-extension. CRC32c is the only |
| 408 # available integrity check for composite objects, and without the C-extension, | 454 # available integrity check for composite objects, and without the C-extension, |
| 409 # download performance can be significantly degraded by the digest computation. | 455 # download performance can be significantly degraded by the digest computation. |
| 410 #check_hashes = if_fast_else_fail | 456 #check_hashes = if_fast_else_fail |
| 411 | 457 |
| 412 # The ability to specify an alternative discovery service URL is primarily for | |
| 413 # cloud storage service developers. | |
| 414 #discovery_service_url = https://www.googleapis.com/discovery/v1/apis/{api}/{api
Version}/rest | |
| 415 # The ability to specify an alternative JSON API version is primarily for cloud | 458 # The ability to specify an alternative JSON API version is primarily for cloud |
| 416 # storage service developers. | 459 # storage service developers. |
| 417 #json_api_version = v1beta2 | 460 #json_api_version = v1 |
| 418 | 461 |
| 419 """ % {'resumable_threshold': TWO_MB, | 462 # Specifies the API to use when interacting with cloud storage providers. If |
| 463 # the gsutil command supports this API for the provider, it will be used |
| 464 # instead of the default. |
| 465 # Commands typically default to XML for S3 and JSON for GCS. |
| 466 #prefer_api = json |
| 467 #prefer_api = xml |
| 468 |
| 469 """ % {'hash_fast_else_fail': CHECK_HASH_IF_FAST_ELSE_FAIL, |
| 470 'hash_fast_else_skip': CHECK_HASH_IF_FAST_ELSE_SKIP, |
| 471 'hash_always': CHECK_HASH_ALWAYS, |
| 472 'hash_never': CHECK_HASH_NEVER, |
| 473 'resumable_threshold': TWO_MB, |
| 420 'parallel_process_count': DEFAULT_PARALLEL_PROCESS_COUNT, | 474 'parallel_process_count': DEFAULT_PARALLEL_PROCESS_COUNT, |
| 421 'parallel_thread_count': DEFAULT_PARALLEL_THREAD_COUNT, | 475 'parallel_thread_count': DEFAULT_PARALLEL_THREAD_COUNT, |
| 422 'parallel_composite_upload_threshold': ( | 476 'parallel_composite_upload_threshold': ( |
| 423 DEFAULT_PARALLEL_COMPOSITE_UPLOAD_THRESHOLD), | 477 DEFAULT_PARALLEL_COMPOSITE_UPLOAD_THRESHOLD), |
| 424 'parallel_composite_upload_component_size': ( | 478 'parallel_composite_upload_component_size': ( |
| 425 DEFAULT_PARALLEL_COMPOSITE_UPLOAD_COMPONENT_SIZE), | 479 DEFAULT_PARALLEL_COMPOSITE_UPLOAD_COMPONENT_SIZE), |
| 426 'max_component_count': MAX_COMPONENT_COUNT} | 480 'max_component_count': MAX_COMPONENT_COUNT} |
| 427 | 481 |
| 428 CONFIG_OAUTH2_CONFIG_CONTENT = """ | 482 CONFIG_OAUTH2_CONFIG_CONTENT = """ |
| 429 [OAuth2] | 483 [OAuth2] |
| 430 # This section specifies options used with OAuth2 authentication. | 484 # This section specifies options used with OAuth2 authentication. |
| 431 | 485 |
| 432 # 'token_cache' specifies how the OAuth2 client should cache access tokens. | 486 # 'token_cache' specifies how the OAuth2 client should cache access tokens. |
| 433 # Valid values are: | 487 # Valid values are: |
| 434 # 'in_memory': an in-memory cache is used. This is only useful if the boto | 488 # 'in_memory': an in-memory cache is used. This is only useful if the boto |
| 435 # client instance (and with it the OAuth2 plugin instance) persists | 489 # client instance (and with it the OAuth2 plugin instance) persists |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 471 # 'oauth2_refresh_retries' controls the number of retry attempts made when | 525 # 'oauth2_refresh_retries' controls the number of retry attempts made when |
| 472 # rate limiting errors occur for OAuth2 requests to retrieve an access token. | 526 # rate limiting errors occur for OAuth2 requests to retrieve an access token. |
| 473 # The default value is 6. | 527 # The default value is 6. |
| 474 #oauth2_refresh_retries = <integer value> | 528 #oauth2_refresh_retries = <integer value> |
| 475 """ | 529 """ |
| 476 | 530 |
| 477 | 531 |
| 478 class ConfigCommand(Command): | 532 class ConfigCommand(Command): |
| 479 """Implementation of gsutil config command.""" | 533 """Implementation of gsutil config command.""" |
| 480 | 534 |
| 481 # Command specification (processed by parent class). | 535 # Command specification. See base class for documentation. |
| 482 command_spec = { | 536 command_spec = Command.CreateCommandSpec( |
| 483 # Name of command. | 537 'config', |
| 484 COMMAND_NAME: 'config', | 538 command_name_aliases=['cfg', 'conf', 'configure'], |
| 485 # List of command name aliases. | 539 min_args=0, |
| 486 COMMAND_NAME_ALIASES: ['cfg', 'conf', 'configure'], | 540 max_args=0, |
| 487 # Min number of args required by this command. | 541 supported_sub_args='habefwrs:o:', |
| 488 MIN_ARGS: 0, | 542 file_url_ok=False, |
| 489 # Max number of args required by this command, or NO_MAX. | 543 provider_url_ok=False, |
| 490 MAX_ARGS: 0, | 544 urls_start_arg=0, |
| 491 # Getopt-style string specifying acceptable sub args. | 545 ) |
| 492 SUPPORTED_SUB_ARGS: 'habefwrs:o:', | 546 # Help specification. See help_provider.py for documentation. |
| 493 # True if file URIs acceptable for this command. | 547 help_spec = Command.HelpSpec( |
| 494 FILE_URIS_OK: False, | 548 help_name='config', |
| 495 # True if provider-only URIs acceptable for this command. | 549 help_name_aliases=['cfg', 'conf', 'configure', 'proxy', 'aws', 's3'], |
| 496 PROVIDER_URIS_OK: False, | 550 help_type='command_help', |
| 497 # Index in args of first URI arg. | 551 help_one_line_summary=( |
| 498 URIS_START_ARG: 0, | 552 'Obtain credentials and create configuration file'), |
| 499 } | 553 help_text=_DETAILED_HELP_TEXT, |
| 500 help_spec = { | 554 subcommand_help_text={}, |
| 501 # Name of command or auxiliary help info for which this help applies. | 555 ) |
| 502 HELP_NAME: 'config', | |
| 503 # List of help name aliases. | |
| 504 HELP_NAME_ALIASES: ['cfg', 'conf', 'configure', 'proxy', 'aws', 's3'], | |
| 505 # Type of help: | |
| 506 HELP_TYPE: HelpType.COMMAND_HELP, | |
| 507 # One line summary of this help. | |
| 508 HELP_ONE_LINE_SUMMARY: 'Obtain credentials and create configuration file', | |
| 509 # The full help text. | |
| 510 HELP_TEXT: _detailed_help_text, | |
| 511 } | |
| 512 | 556 |
| 513 def _OpenConfigFile(self, file_path): | 557 def _OpenConfigFile(self, file_path): |
| 514 """Creates and opens a configuration file for writing. | 558 """Creates and opens a configuration file for writing. |
| 515 | 559 |
| 516 The file is created with mode 0600, and attempts to open existing files will | 560 The file is created with mode 0600, and attempts to open existing files will |
| 517 fail (the latter is important to prevent symlink attacks). | 561 fail (the latter is important to prevent symlink attacks). |
| 518 | 562 |
| 519 It is the caller's responsibility to close the file. | 563 It is the caller's responsibility to close the file. |
| 520 | 564 |
| 521 Args: | 565 Args: |
| 522 file_path: Path of the file to be created. | 566 file_path: Path of the file to be created. |
| 523 | 567 |
| 524 Returns: | 568 Returns: |
| 525 A writable file object for the opened file. | 569 A writable file object for the opened file. |
| 526 | 570 |
| 527 Raises: | 571 Raises: |
| 528 CommandException: if an error occurred when opening the file (including | 572 CommandException: if an error occurred when opening the file (including |
| 529 when the file already exists). | 573 when the file already exists). |
| 530 """ | 574 """ |
| 531 flags = os.O_RDWR | os.O_CREAT | os.O_EXCL | 575 flags = os.O_RDWR | os.O_CREAT | os.O_EXCL |
| 532 # Accommodate Windows; stolen from python2.6/tempfile.py. | 576 # Accommodate Windows; copied from python2.6/tempfile.py. |
| 533 if hasattr(os, 'O_NOINHERIT'): | 577 if hasattr(os, 'O_NOINHERIT'): |
| 534 flags |= os.O_NOINHERIT | 578 flags |= os.O_NOINHERIT |
| 535 try: | 579 try: |
| 536 fd = os.open(file_path, flags, 0600) | 580 fd = os.open(file_path, flags, 0600) |
| 537 except (OSError, IOError), e: | 581 except (OSError, IOError), e: |
| 538 raise CommandException('Failed to open %s for writing: %s' % | 582 raise CommandException('Failed to open %s for writing: %s' % |
| 539 (file_path, e)) | 583 (file_path, e)) |
| 540 return os.fdopen(fd, 'w') | 584 return os.fdopen(fd, 'w') |
| 541 | 585 |
| 542 def _CheckPrivateKeyFilePermissions(self, file_path): | 586 def _CheckPrivateKeyFilePermissions(self, file_path): |
| 543 """Checks that the file has reasonable permissions for a private key. | 587 """Checks that the file has reasonable permissions for a private key. |
| 544 | 588 |
| 545 In particular, check that the filename provided by the user is not | 589 In particular, check that the filename provided by the user is not |
| 546 world- or group-readable. If either of these are true, we issue a warning | 590 world- or group-readable. If either of these are true, we issue a warning |
| 547 and offer to fix the permissions. | 591 and offer to fix the permissions. |
| 548 | 592 |
| 549 Args: | 593 Args: |
| 550 filename: The name of the private key file. | 594 file_path: The name of the private key file. |
| 551 """ | 595 """ |
| 552 if IS_WINDOWS: | 596 if IS_WINDOWS: |
| 553 # For Windows, this check doesn't work (it actually just checks whether | 597 # For Windows, this check doesn't work (it actually just checks whether |
| 554 # the file is read-only). Since Windows files have a complicated ACL | 598 # the file is read-only). Since Windows files have a complicated ACL |
| 555 # system, this check doesn't make much sense on Windows anyway, so we | 599 # system, this check doesn't make much sense on Windows anyway, so we |
| 556 # just don't do it. | 600 # just don't do it. |
| 557 return | 601 return |
| 558 | 602 |
| 559 st = os.stat(file_path) | 603 st = os.stat(file_path) |
| 560 if bool((stat.S_IRGRP | stat.S_IROTH) & st.st_mode): | 604 if bool((stat.S_IRGRP | stat.S_IROTH) & st.st_mode): |
| 561 self.logger.warn( | 605 self.logger.warn( |
| 562 '\nYour private key file is readable by people other than yourself.\n' | 606 '\nYour private key file is readable by people other than yourself.\n' |
| 563 'This is a security risk, since anyone with this information can use ' | 607 'This is a security risk, since anyone with this information can use ' |
| 564 'your service account.\n') | 608 'your service account.\n') |
| 565 fix_it = raw_input('Would you like gsutil to change the file ' | 609 fix_it = raw_input('Would you like gsutil to change the file ' |
| 566 'permissions for you? (y/N) ') | 610 'permissions for you? (y/N) ') |
| 567 if fix_it in ('y', 'Y'): | 611 if fix_it in ('y', 'Y'): |
| 568 try: | 612 try: |
| 569 os.chmod(file_path, 0400) | 613 os.chmod(file_path, 0400) |
| 570 self.logger.info( | 614 self.logger.info( |
| 571 '\nThe permissions on your file have been successfully ' | 615 '\nThe permissions on your file have been successfully ' |
| 572 'modified.' | 616 'modified.' |
| 573 '\nThe only access allowed is readability by the user ' | 617 '\nThe only access allowed is readability by the user ' |
| 574 '(permissions 0400 in chmod).') | 618 '(permissions 0400 in chmod).') |
| 575 except Exception as e: | 619 except Exception, _: # pylint: disable=broad-except |
| 576 self.logger.warn( | 620 self.logger.warn( |
| 577 '\nWe were unable to modify the permissions on your file.\n' | 621 '\nWe were unable to modify the permissions on your file.\n' |
| 578 'If you would like to fix this yourself, consider running:\n' | 622 'If you would like to fix this yourself, consider running:\n' |
| 579 '"sudo chmod 400 </path/to/key>" for improved security.') | 623 '"sudo chmod 400 </path/to/key>" for improved security.') |
| 580 else: | 624 else: |
| 581 self.logger.info( | 625 self.logger.info( |
| 582 '\nYou have chosen to allow this file to be readable by others.\n' | 626 '\nYou have chosen to allow this file to be readable by others.\n' |
| 583 'If you would like to fix this yourself, consider running:\n' | 627 'If you would like to fix this yourself, consider running:\n' |
| 584 '"sudo chmod 400 </path/to/key>" for improved security.') | 628 '"sudo chmod 400 </path/to/key>" for improved security.') |
| 585 | 629 |
| 586 def _PromptForProxyConfigVarAndMaybeSaveToBotoConfig(self, varname, prompt): | 630 def _PromptForProxyConfigVarAndMaybeSaveToBotoConfig(self, varname, prompt, |
| 587 """Prompts user for one proxy configuration line, and saves to boto.config | 631 convert_to_bool=False): |
| 588 if not empty. | 632 """Prompts for one proxy config line, saves to boto.config if not empty. |
| 589 | 633 |
| 590 Args: | 634 Args: |
| 591 varname: The config variable name. | 635 varname: The config variable name. |
| 592 prompt: The prompt to output to the user. | 636 prompt: The prompt to output to the user. |
| 637 convert_to_bool: Whether to convert "y/n" to True/False. |
| 593 """ | 638 """ |
| 594 value = raw_input(prompt) | 639 value = raw_input(prompt) |
| 595 if value: | 640 if value: |
| 641 if convert_to_bool: |
| 642 if value == 'y' or value == 'Y': |
| 643 value = 'True' |
| 644 else: |
| 645 value = 'False' |
| 596 boto.config.set('Boto', varname, value) | 646 boto.config.set('Boto', varname, value) |
| 597 | 647 |
| 598 def _PromptForProxyConfig(self): | 648 def _PromptForProxyConfig(self): |
| 599 """ | 649 """Prompts for proxy config data, loads non-empty values into boto.config. |
| 600 Prompts user for proxy configuration data, and loads non-empty values into | |
| 601 boto.config. | |
| 602 """ | 650 """ |
| 603 self._PromptForProxyConfigVarAndMaybeSaveToBotoConfig( | 651 self._PromptForProxyConfigVarAndMaybeSaveToBotoConfig( |
| 604 'proxy', 'What is your proxy host? ') | 652 'proxy', 'What is your proxy host? ') |
| 605 self._PromptForProxyConfigVarAndMaybeSaveToBotoConfig( | 653 self._PromptForProxyConfigVarAndMaybeSaveToBotoConfig( |
| 606 'proxy_port', 'What is your proxy port? ') | 654 'proxy_port', 'What is your proxy port? ') |
| 607 self._PromptForProxyConfigVarAndMaybeSaveToBotoConfig( | 655 self._PromptForProxyConfigVarAndMaybeSaveToBotoConfig( |
| 608 'proxy_user', 'What is your proxy user (leave blank if not used)? ') | 656 'proxy_user', 'What is your proxy user (leave blank if not used)? ') |
| 609 self._PromptForProxyConfigVarAndMaybeSaveToBotoConfig( | 657 self._PromptForProxyConfigVarAndMaybeSaveToBotoConfig( |
| 610 'proxy_pass', 'What is your proxy pass (leave blank if not used)? ') | 658 'proxy_pass', 'What is your proxy pass (leave blank if not used)? ') |
| 659 self._PromptForProxyConfigVarAndMaybeSaveToBotoConfig( |
| 660 'proxy_rdns', |
| 661 'Should DNS lookups be resolved by your proxy? (Y if your site ' |
| 662 'disallows client DNS lookups)? ', |
| 663 convert_to_bool=True) |
| 611 | 664 |
| 612 def _WriteConfigLineMaybeCommented(self, config_file, name, value, desc): | 665 def _WriteConfigLineMaybeCommented(self, config_file, name, value, desc): |
| 613 """Writes proxy name/value pair to config file if value is not None, else | 666 """Writes proxy name/value pair or comment line to config file. |
| 614 writes comment line. | 667 |
| 668 Writes proxy name/value pair if value is not None. Otherwise writes |
| 669 comment line. |
| 615 | 670 |
| 616 Args: | 671 Args: |
| 672 config_file: File object to which the resulting config file will be |
| 673 written. |
| 617 name: The config variable name. | 674 name: The config variable name. |
| 618 value: The value, or None. | 675 value: The value, or None. |
| 619 desc: Human readable description (for comment). | 676 desc: Human readable description (for comment). |
| 620 config_file: File object to which the resulting config file will be | |
| 621 written. | |
| 622 """ | 677 """ |
| 623 if not value: | 678 if not value: |
| 624 name = '#%s' % name | 679 name = '#%s' % name |
| 625 value = '<%s>' % desc | 680 value = '<%s>' % desc |
| 626 config_file.write('%s = %s\n' % (name, value)) | 681 config_file.write('%s = %s\n' % (name, value)) |
| 627 | 682 |
| 628 def _WriteProxyConfigFileSection(self, config_file): | 683 def _WriteProxyConfigFileSection(self, config_file): |
| 629 """Writes proxy section of configuration file. | 684 """Writes proxy section of configuration file. |
| 630 | 685 |
| 631 Args: | 686 Args: |
| 632 config_file: File object to which the resulting config file will be | 687 config_file: File object to which the resulting config file will be |
| 633 written. | 688 written. |
| 634 """ | 689 """ |
| 635 config = boto.config | 690 config = boto.config |
| 636 config_file.write( | 691 config_file.write( |
| 637 """# To use a proxy, edit and uncomment the proxy and proxy_port lines. If you | 692 '# To use a proxy, edit and uncomment the proxy and proxy_port lines.\n' |
| 638 # need a user/password with this proxy, edit and uncomment those lines as well. | 693 '# If you need a user/password with this proxy, edit and uncomment\n' |
| 639 """) | 694 '# those lines as well. If your organization also disallows DNS\n' |
| 695 '# lookups by client machines set proxy_rdns = True\n') |
| 640 self._WriteConfigLineMaybeCommented( | 696 self._WriteConfigLineMaybeCommented( |
| 641 config_file, 'proxy', config.get_value('Boto', 'proxy', None), | 697 config_file, 'proxy', config.get_value('Boto', 'proxy', None), |
| 642 'proxy host') | 698 'proxy host') |
| 643 self._WriteConfigLineMaybeCommented( | 699 self._WriteConfigLineMaybeCommented( |
| 644 config_file, 'proxy_port', config.get_value('Boto', 'proxy_port', None), | 700 config_file, 'proxy_port', config.get_value('Boto', 'proxy_port', None), |
| 645 'proxy port') | 701 'proxy port') |
| 646 self._WriteConfigLineMaybeCommented( | 702 self._WriteConfigLineMaybeCommented( |
| 647 config_file, 'proxy_user', config.get_value('Boto', 'proxy_user', None), | 703 config_file, 'proxy_user', config.get_value('Boto', 'proxy_user', None), |
| 648 'proxy user') | 704 'proxy user') |
| 649 self._WriteConfigLineMaybeCommented( | 705 self._WriteConfigLineMaybeCommented( |
| 650 config_file, 'proxy_pass', config.get_value('Boto', 'proxy_pass', None), | 706 config_file, 'proxy_pass', config.get_value('Boto', 'proxy_pass', None), |
| 651 'proxy password') | 707 'proxy password') |
| 708 self._WriteConfigLineMaybeCommented( |
| 709 config_file, 'proxy_rdns', |
| 710 config.get_value('Boto', 'proxy_rdns', False), |
| 711 'let proxy server perform DNS lookups') |
| 652 | 712 |
| 713 # pylint: disable=dangerous-default-value,too-many-statements |
| 653 def _WriteBotoConfigFile(self, config_file, launch_browser=True, | 714 def _WriteBotoConfigFile(self, config_file, launch_browser=True, |
| 654 oauth2_scopes=[SCOPE_FULL_CONTROL], | 715 oauth2_scopes=[SCOPE_FULL_CONTROL], |
| 655 cred_type=CredTypes.OAUTH2_USER_ACCOUNT): | 716 cred_type=CredTypes.OAUTH2_USER_ACCOUNT): |
| 656 """Creates a boto config file interactively. | 717 """Creates a boto config file interactively. |
| 657 | 718 |
| 658 Needed credentials are obtained interactively, either by asking the user for | 719 Needed credentials are obtained interactively, either by asking the user for |
| 659 access key and secret, or by walking the user through the OAuth2 approval | 720 access key and secret, or by walking the user through the OAuth2 approval |
| 660 flow. | 721 flow. |
| 661 | 722 |
| 662 Args: | 723 Args: |
| 663 config_file: File object to which the resulting config file will be | 724 config_file: File object to which the resulting config file will be |
| 664 written. | 725 written. |
| 726 launch_browser: In the OAuth2 approval flow, attempt to open a browser |
| 727 window and navigate to the approval URL. |
| 728 oauth2_scopes: A list of OAuth2 scopes to request authorization for, when |
| 729 using OAuth2. |
| 665 cred_type: There are three options: | 730 cred_type: There are three options: |
| 666 - for HMAC, ask the user for access key and secret | 731 - for HMAC, ask the user for access key and secret |
| 667 - for OAUTH2_USER_ACCOUNT, walk the user through OAuth2 approval flow | 732 - for OAUTH2_USER_ACCOUNT, walk the user through OAuth2 approval flow |
| 668 and produce a config with an oauth2_refresh_token credential. | 733 and produce a config with an oauth2_refresh_token credential. |
| 669 - for OAUTH2_SERVICE_ACCOUNT, prompt the user for OAuth2 for client ID, | 734 - for OAUTH2_SERVICE_ACCOUNT, prompt the user for OAuth2 for service |
| 670 and private key file (and password for the file) | 735 account email address and private key file (and password for that |
| 671 launch_browser: In the OAuth2 approval flow, attempt to open a browser | 736 file). |
| 672 window and navigate to the approval URL. | |
| 673 oauth2_scopes: A list of OAuth2 scopes to request authorization for, when | |
| 674 using OAuth2. | |
| 675 """ | 737 """ |
| 676 # Collect credentials | 738 # Collect credentials |
| 677 provider_map = {'aws': 'aws', 'google': 'gs'} | 739 provider_map = {'aws': 'aws', 'google': 'gs'} |
| 678 uri_map = {'aws': 's3', 'google': 'gs'} | 740 uri_map = {'aws': 's3', 'google': 'gs'} |
| 679 key_ids = {} | 741 key_ids = {} |
| 680 sec_keys = {} | 742 sec_keys = {} |
| 681 if cred_type == CredTypes.OAUTH2_SERVICE_ACCOUNT: | 743 if cred_type == CredTypes.OAUTH2_SERVICE_ACCOUNT: |
| 682 gs_service_client_id = raw_input('What is your service account email ' | 744 gs_service_client_id = raw_input('What is your service account email ' |
| 683 'address? ') | 745 'address? ') |
| 684 gs_service_key_file = raw_input('What is the full path to your private ' | 746 gs_service_key_file = raw_input('What is the full path to your private ' |
| 685 'key file? ') | 747 'key file? ') |
| 686 gs_service_key_file_password = raw_input( | 748 gs_service_key_file_password = raw_input( |
| 687 '\n'.join(textwrap.wrap( | 749 '\n'.join(textwrap.wrap( |
| 688 "What is the password for your service key file? If you haven't " | 750 'What is the password for your service key file [if you haven\'t ' |
| 689 " set one explicitly, leave this line blank. "))) | 751 'set one explicitly, leave this line blank]?')) + ' ') |
| 690 self._CheckPrivateKeyFilePermissions(gs_service_key_file) | 752 self._CheckPrivateKeyFilePermissions(gs_service_key_file) |
| 691 elif cred_type == CredTypes.OAUTH2_USER_ACCOUNT: | 753 elif cred_type == CredTypes.OAUTH2_USER_ACCOUNT: |
| 692 oauth2_client = oauth2_helper.OAuth2ClientFromBotoConfig(boto.config, | 754 oauth2_client = oauth2_helper.OAuth2ClientFromBotoConfig(boto.config, |
| 693 cred_type) | 755 cred_type) |
| 694 try: | 756 try: |
| 695 oauth2_refresh_token = oauth2_helper.OAuth2ApprovalFlow( | 757 oauth2_refresh_token = oauth2_helper.OAuth2ApprovalFlow( |
| 696 oauth2_client, oauth2_scopes, launch_browser) | 758 oauth2_client, oauth2_scopes, launch_browser) |
| 697 except (ResponseNotReady, ServerNotFoundError) as e: | 759 except (ResponseNotReady, ServerNotFoundError, socket.error): |
| 698 # TODO: Determine condition to check for in the ResponseNotReady | 760 # TODO: Determine condition to check for in the ResponseNotReady |
| 699 # exception so we only run proxy config flow if failure was caused by | 761 # exception so we only run proxy config flow if failure was caused by |
| 700 # request being blocked because it wasn't sent through proxy. (This | 762 # request being blocked because it wasn't sent through proxy. (This |
| 701 # error could also happen if gsutil or the oauth2 client had a bug that | 763 # error could also happen if gsutil or the oauth2 client had a bug that |
| 702 # attempted to incorrectly reuse an HTTP connection, for example.) | 764 # attempted to incorrectly reuse an HTTP connection, for example.) |
| 703 sys.stdout.write('\n'.join(textwrap.wrap( | 765 sys.stdout.write('\n'.join(textwrap.wrap( |
| 704 "Unable to connect to accounts.google.com during OAuth2 flow. This " | 766 "Unable to connect to accounts.google.com during OAuth2 flow. This " |
| 705 "can happen if your site uses a proxy. If you are using gsutil " | 767 "can happen if your site uses a proxy. If you are using gsutil " |
| 706 "through a proxy, please enter the proxy's information; otherwise " | 768 "through a proxy, please enter the proxy's information; otherwise " |
| 707 "leave the following fields blank.")) + '\n') | 769 "leave the following fields blank.")) + '\n') |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 786 '# To add %s credentials ("%s://" URIs), edit and ' | 848 '# To add %s credentials ("%s://" URIs), edit and ' |
| 787 'uncomment the\n# following two lines:\n' | 849 'uncomment the\n# following two lines:\n' |
| 788 '#%s_access_key_id = <your %s access key ID>\n' | 850 '#%s_access_key_id = <your %s access key ID>\n' |
| 789 '#%s_secret_access_key = <your %s secret access key>\n' % | 851 '#%s_secret_access_key = <your %s secret access key>\n' % |
| 790 (provider, uri_scheme, key_prefix, provider, key_prefix, | 852 (provider, uri_scheme, key_prefix, provider, key_prefix, |
| 791 provider)) | 853 provider)) |
| 792 host_key = Provider.HostKeyMap[provider] | 854 host_key = Provider.HostKeyMap[provider] |
| 793 config_file.write( | 855 config_file.write( |
| 794 '# The ability to specify an alternate storage host and port\n' | 856 '# The ability to specify an alternate storage host and port\n' |
| 795 '# is primarily for cloud storage service developers.\n' | 857 '# is primarily for cloud storage service developers.\n' |
| 858 '# Setting a non-default gs_host only works if prefer_api=xml.\n' |
| 796 '#%s_host = <alternate storage host address>\n' | 859 '#%s_host = <alternate storage host address>\n' |
| 797 '#%s_port = <alternate storage host port>\n\n' | 860 '#%s_port = <alternate storage host port>\n' |
| 798 % (host_key, host_key)) | 861 % (host_key, host_key)) |
| 862 if host_key == 'gs': |
| 863 config_file.write( |
| 864 '#%s_json_host = <alternate JSON API storage host address>\n' |
| 865 '#%s_json_port = <alternate JSON API storage host port>\n\n' |
| 866 % (host_key, host_key)) |
| 867 config_file.write('\n') |
| 799 | 868 |
| 800 # Write the config file Boto section. | 869 # Write the config file Boto section. |
| 801 config_file.write('%s\n' % CONFIG_BOTO_SECTION_CONTENT) | 870 config_file.write('%s\n' % CONFIG_BOTO_SECTION_CONTENT) |
| 802 self._WriteProxyConfigFileSection(config_file) | 871 self._WriteProxyConfigFileSection(config_file) |
| 803 | 872 |
| 804 # Write the config file GSUtil section that doesn't depend on user input. | 873 # Write the config file GSUtil section that doesn't depend on user input. |
| 805 config_file.write(CONFIG_INPUTLESS_GSUTIL_SECTION_CONTENT) | 874 config_file.write(CONFIG_INPUTLESS_GSUTIL_SECTION_CONTENT) |
| 806 | 875 |
| 807 # Write the default API version. | 876 # Write the default API version. |
| 808 config_file.write(""" | 877 config_file.write(""" |
| 809 # 'default_api_version' specifies the default Google Cloud Storage API | 878 # 'default_api_version' specifies the default Google Cloud Storage XML API |
| 810 # version to use. If not set below gsutil defaults to API version 1. | 879 # version to use. If not set below gsutil defaults to API version 1. |
| 811 """) | 880 """) |
| 812 api_version = 2 | 881 api_version = 2 |
| 813 if cred_type == CredTypes.HMAC: api_version = 1 | 882 if cred_type == CredTypes.HMAC: api_version = 1 |
| 814 | 883 |
| 815 config_file.write('default_api_version = %d\n' % api_version) | 884 config_file.write('default_api_version = %d\n' % api_version) |
| 816 | 885 |
| 817 # Write the config file GSUtil section that includes the default | 886 # Write the config file GSUtil section that includes the default |
| 818 # project ID input from the user. | 887 # project ID input from the user. |
| 819 if launch_browser: | 888 if launch_browser: |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 852 if not default_project_id: | 921 if not default_project_id: |
| 853 raise CommandException( | 922 raise CommandException( |
| 854 'No default project ID entered. The default project ID is needed by ' | 923 'No default project ID entered. The default project ID is needed by ' |
| 855 'the\nls and mb commands; please try again.') | 924 'the\nls and mb commands; please try again.') |
| 856 config_file.write('%sdefault_project_id = %s\n\n\n' % | 925 config_file.write('%sdefault_project_id = %s\n\n\n' % |
| 857 (project_id_section_prelude, default_project_id)) | 926 (project_id_section_prelude, default_project_id)) |
| 858 | 927 |
| 859 # Write the config file OAuth2 section. | 928 # Write the config file OAuth2 section. |
| 860 config_file.write(CONFIG_OAUTH2_CONFIG_CONTENT) | 929 config_file.write(CONFIG_OAUTH2_CONFIG_CONTENT) |
| 861 | 930 |
| 862 # Command entry point. | |
| 863 def RunCommand(self): | 931 def RunCommand(self): |
| 932 """Command entry point for the config command.""" |
| 864 scopes = [] | 933 scopes = [] |
| 865 cred_type = CredTypes.OAUTH2_USER_ACCOUNT | 934 cred_type = CredTypes.OAUTH2_USER_ACCOUNT |
| 866 launch_browser = False | 935 launch_browser = False |
| 867 output_file_name = None | 936 output_file_name = None |
| 868 has_a = False | 937 has_a = False |
| 869 has_e = False | 938 has_e = False |
| 870 for opt, opt_arg in self.sub_opts: | 939 for opt, opt_arg in self.sub_opts: |
| 871 if opt == '-a': | 940 if opt == '-a': |
| 872 cred_type = CredTypes.HMAC | 941 cred_type = CredTypes.HMAC |
| 873 has_a = True | 942 has_a = True |
| (...skipping 20 matching lines...) Expand all Loading... |
| 894 if not HAS_CRYPTO: | 963 if not HAS_CRYPTO: |
| 895 raise CommandException( | 964 raise CommandException( |
| 896 'Service account authentication requires either\nPyOpenSSL or ' | 965 'Service account authentication requires either\nPyOpenSSL or ' |
| 897 'PyCrypto 2.6 or later. Please install either of these\nto proceed,' | 966 'PyCrypto 2.6 or later. Please install either of these\nto proceed,' |
| 898 ' or configure a different type of credentials.') | 967 ' or configure a different type of credentials.') |
| 899 | 968 |
| 900 if not scopes: | 969 if not scopes: |
| 901 scopes.append(SCOPE_FULL_CONTROL) | 970 scopes.append(SCOPE_FULL_CONTROL) |
| 902 | 971 |
| 903 default_config_path_bak = None | 972 default_config_path_bak = None |
| 904 if output_file_name is None: | 973 if not output_file_name: |
| 905 # Check to see if a default config file name is requested via | 974 # Check to see if a default config file name is requested via |
| 906 # environment variable. If so, use it, otherwise use the hard-coded | 975 # environment variable. If so, use it, otherwise use the hard-coded |
| 907 # default file. Then use the default config file name, if it doesn't | 976 # default file. Then use the default config file name, if it doesn't |
| 908 # exist or can be moved out of the way without clobbering an existing | 977 # exist or can be moved out of the way without clobbering an existing |
| 909 # backup file. | 978 # backup file. |
| 910 boto_config_from_env = os.environ.get('BOTO_CONFIG', None) | 979 boto_config_from_env = os.environ.get('BOTO_CONFIG', None) |
| 911 if boto_config_from_env: | 980 if boto_config_from_env: |
| 912 default_config_path = boto_config_from_env | 981 default_config_path = boto_config_from_env |
| 913 else: | 982 else: |
| 914 default_config_path = os.path.expanduser(os.path.join('~', '.boto')) | 983 default_config_path = os.path.expanduser(os.path.join('~', '.boto')) |
| 915 if not os.path.exists(default_config_path): | 984 if not os.path.exists(default_config_path): |
| 916 output_file_name = default_config_path | 985 output_file_name = default_config_path |
| 917 else: | 986 else: |
| 918 default_config_path_bak = default_config_path + '.bak' | 987 default_config_path_bak = default_config_path + '.bak' |
| 919 if os.path.exists(default_config_path_bak): | 988 if os.path.exists(default_config_path_bak): |
| 920 raise CommandException( | 989 raise CommandException( |
| 921 'Cannot back up existing config ' | 990 'Cannot back up existing config ' |
| 922 'file "%s": backup file exists ("%s").' | 991 'file "%s": backup file exists ("%s").' |
| 923 % (default_config_path, default_config_path_bak)) | 992 % (default_config_path, default_config_path_bak)) |
| 924 else: | 993 else: |
| 925 try: | 994 try: |
| 926 sys.stderr.write( | 995 sys.stderr.write( |
| 927 'Backing up existing config file "%s" to "%s"...\n' | 996 'Backing up existing config file "%s" to "%s"...\n' |
| 928 % (default_config_path, default_config_path_bak)) | 997 % (default_config_path, default_config_path_bak)) |
| 929 os.rename(default_config_path, default_config_path_bak) | 998 os.rename(default_config_path, default_config_path_bak) |
| 930 except e: | 999 except Exception, e: |
| 931 raise CommandException( | 1000 raise CommandException( |
| 932 'Failed to back up existing config ' | 1001 'Failed to back up existing config ' |
| 933 'file ("%s" -> "%s"): %s.' | 1002 'file ("%s" -> "%s"): %s.' |
| 934 % (default_config_path, default_config_path_bak, e)) | 1003 % (default_config_path, default_config_path_bak, e)) |
| 935 output_file_name = default_config_path | 1004 output_file_name = default_config_path |
| 936 | 1005 |
| 937 if output_file_name == '-': | 1006 if output_file_name == '-': |
| 938 output_file = sys.stdout | 1007 output_file = sys.stdout |
| 939 else: | 1008 else: |
| 940 output_file = self._OpenConfigFile(output_file_name) | 1009 output_file = self._OpenConfigFile(output_file_name) |
| 941 sys.stderr.write( | 1010 sys.stderr.write('\n'.join(textwrap.wrap( |
| 942 'This script will create a boto config file at\n%s\ncontaining your ' | 1011 'This command will create a boto config file at %s containing your ' |
| 943 'credentials, based on your responses to the following questions.\n\n' | 1012 'credentials, based on your responses to the following questions.' |
| 944 % output_file_name) | 1013 % output_file_name)) + '\n') |
| 945 | 1014 |
| 946 # Catch ^C so we can restore the backup. | 1015 # Catch ^C so we can restore the backup. |
| 947 signal.signal(signal.SIGINT, cleanup_handler) | 1016 signal.signal(signal.SIGINT, CleanupHandler) |
| 948 try: | 1017 try: |
| 949 self._WriteBotoConfigFile(output_file, launch_browser=launch_browser, | 1018 self._WriteBotoConfigFile(output_file, launch_browser=launch_browser, |
| 950 oauth2_scopes=scopes, cred_type=cred_type) | 1019 oauth2_scopes=scopes, cred_type=cred_type) |
| 951 except Exception as e: | 1020 except Exception as e: |
| 952 user_aborted = isinstance(e, AbortException) | 1021 user_aborted = isinstance(e, AbortException) |
| 953 if user_aborted: | 1022 if user_aborted: |
| 954 sys.stderr.write('\nCaught ^C; cleaning up\n') | 1023 sys.stderr.write('\nCaught ^C; cleaning up\n') |
| 955 # If an error occurred during config file creation, remove the invalid | 1024 # If an error occurred during config file creation, remove the invalid |
| 956 # config file and restore the backup file. | 1025 # config file and restore the backup file. |
| 957 if output_file_name != '-': | 1026 if output_file_name != '-': |
| (...skipping 15 matching lines...) Expand all Loading... |
| 973 output_file.close() | 1042 output_file.close() |
| 974 if not boto.config.has_option('Boto', 'proxy'): | 1043 if not boto.config.has_option('Boto', 'proxy'): |
| 975 sys.stderr.write('\n' + '\n'.join(textwrap.wrap( | 1044 sys.stderr.write('\n' + '\n'.join(textwrap.wrap( |
| 976 'Boto config file "%s" created.\nIf you need to use a proxy to ' | 1045 'Boto config file "%s" created.\nIf you need to use a proxy to ' |
| 977 'access the Internet please see the instructions in that file.' | 1046 'access the Internet please see the instructions in that file.' |
| 978 % output_file_name)) + '\n') | 1047 % output_file_name)) + '\n') |
| 979 | 1048 |
| 980 return 0 | 1049 return 0 |
| 981 | 1050 |
| 982 | 1051 |
| 983 def cleanup_handler(signalnum, handler): | 1052 def CleanupHandler(unused_signalnum, unused_handler): |
| 984 raise AbortException('User interrupted config command') | 1053 raise AbortException('User interrupted config command') |
| OLD | NEW |