def _CheckAndHandleCredentialException(e, args): # Provide detail to users who have no boto config file (who might previously # have been using gsutil only for accessing publicly readable buckets and # objects). # pylint: disable=g-import-not-at-top from gslib.util import HasConfiguredCredentials if (not HasConfiguredCredentials() and not boto.config.get_value('Tests', 'bypass_anonymous_access_warning', False)): # The check above allows tests to assert that we get a particular, # expected failure, rather than always encountering this error message # when there are no configured credentials. This allows tests to # simulate a second user without permissions, without actually requiring # two separate configured users. if os.environ.get('CLOUDSDK_WRAPPER') == '1': _OutputAndExit('\n'.join(textwrap.wrap( 'You are attempting to access protected data with no configured ' 'credentials. Please visit ' 'https://cloud.google.com/console#/project and sign up for an ' 'account, and then run the "gcloud auth login" command to ' 'configure gsutil to use these credentials.'))) else: _OutputAndExit('\n'.join(textwrap.wrap( 'You are attempting to access protected data with no configured ' 'credentials. Please visit ' 'https://cloud.google.com/console#/project and sign up for an ' 'account, and then run the "gsutil config" command to configure ' 'gsutil to use these credentials.'))) elif (e.reason and (e.reason == 'AccountProblem' or e.reason == 'Account disabled.' or 'account for the specified project has been disabled' in e.reason) and ','.join(args).find('gs://') != -1): _OutputAndExit('\n'.join(textwrap.wrap( _ConstructAccountProblemHelp(e.reason))))
def _RunNamedCommandAndHandleExceptions(command_runner, command_name, args=None, headers=None, debug=0, parallel_operations=False): try: # Catch ^C so we can print a brief message instead of the normal Python # stack trace. signal.signal(signal.SIGINT, _HandleControlC) # Catch ^\ so we can force a breakpoint in a running gsutil. if not util.IS_WINDOWS: signal.signal(signal.SIGQUIT, _HandleSigQuit) return command_runner.RunNamedCommand(command_name, args, headers, debug, parallel_operations) except AttributeError as e: if str(e).find('secret_access_key') != -1: _OutputAndExit( 'Missing credentials for the given URI(s). Does your ' 'boto config file contain all needed credentials?') else: _OutputAndExit(str(e)) except boto.exception.StorageDataError as e: _OutputAndExit('StorageDataError: %s.' % e.reason) except boto.exception.BotoClientError as e: _OutputAndExit('BotoClientError: %s.' % e.reason) except gslib.exception.CommandException as e: _HandleCommandException(e) except getopt.GetoptError as e: _HandleCommandException(gslib.exception.CommandException(e.msg)) except boto.exception.InvalidAclError as e: _OutputAndExit('InvalidAclError: %s.' % str(e)) except boto.exception.InvalidUriError as e: _OutputAndExit('InvalidUriError: %s.' % e.message) except gslib.exception.ProjectIdException as e: _OutputAndExit('ProjectIdException: %s.' % e.reason) except boto.auth_handler.NotReadyToAuthenticate: _OutputAndExit('NotReadyToAuthenticate') except OSError as e: _OutputAndExit('OSError: %s.' % e.strerror) except IOError as e: if e.errno == errno.EPIPE and not IsRunningInteractively(): # If we get a pipe error, this just means that the pipe to stdout or # stderr is broken. This can happen if the user pipes gsutil to a command # that doesn't use the entire output stream. Instead of raising an error, # just swallow it up and exit cleanly. sys.exit(0) else: raise except wildcard_iterator.WildcardException as e: _OutputAndExit(e.reason) except boto.exception.StorageResponseError as e: # Check for access denied, and provide detail to users who have no boto # config file (who might previously have been using gsutil only for # accessing publicly readable buckets and objects). if (e.status == 403 or (e.status == 400 and e.code == 'MissingSecurityHeader')): _, _, detail = util.ParseErrorDetail(e) if detail and detail.find( 'x-goog-project-id header is required') != -1: _OutputAndExit('\n'.join( textwrap.wrap( 'You are attempting to perform an operation that requires an ' 'x-goog-project-id header, with none configured. Please re-run ' 'gsutil config and make sure to follow the instructions for ' 'finding and entering your default project id.'))) if (not HasConfiguredCredentials() and not boto.config.get_value( 'Tests', 'bypass_anonymous_access_warning', False)): # The check above allows tests to assert that we get a particular, # expected failure, rather than always encountering this error message # when there are no configured credentials. This allows tests to # simulate a second user without permissions, without actually requiring # two separate configured users. _OutputAndExit('\n'.join( textwrap.wrap( 'You are attempting to access protected data with no configured ' 'credentials. Please visit ' 'https://cloud.google.com/console#/project and sign up for an ' 'account, and then run the "gsutil config" command to configure ' 'gsutil to use these credentials.'))) elif (e.error_code == 'AccountProblem' and ','.join(args).find('gs://') != -1): default_project_id = boto.config.get_value( 'GSUtil', 'default_project_id') (acct_help_part_1, acct_help_part_2, acct_help_part_3) = (_ConstructAclHelp(default_project_id)) if default_project_id: _OutputAndExit(acct_help_part_1 + acct_help_part_2 + '3. ' + acct_help_part_3) else: _OutputAndExit(acct_help_part_1 + '2. ' + acct_help_part_3) exc_name, message, detail = util.ParseErrorDetail(e) _OutputAndExit( util.FormatErrorMessage(exc_name, e.status, e.code, e.reason, message, detail)) except boto.exception.ResumableUploadException as e: _OutputAndExit('ResumableUploadException: %s.' % e.message) except socket.error as e: if e.args[0] == errno.EPIPE: # Retrying with a smaller file (per suggestion below) works because # the library code send loop (in boto/s3/key.py) can get through the # entire file and then request the HTTP response before the socket # gets closed and the response lost. message = (""" Got a "Broken pipe" error. This can happen to clients using Python 2.x, when the server sends an error response and then closes the socket (see http://bugs.python.org/issue5542). If you are trying to upload a large object you might retry with a small (say 200k) object, and see if you get a more specific error code. """) _OutputAndExit(message) else: _HandleUnknownFailure(e) except Exception as e: # Check for two types of errors related to service accounts. These errors # appear to be the same except for their messages, but they are caused by # different problems and both have unhelpful error messages. Moreover, # the error type belongs to PyOpenSSL, which is not necessarily installed. if 'mac verify failure' in str(e): _OutputAndExit( "Encountered an error while refreshing access token." + " If you are using a service account,\nplease verify that the " + "gs_service_key_file_password field in your config file," + "\n%s, is correct." % GetConfigFilePath()) elif 'asn1 encoding routines' in str(e): _OutputAndExit( "Encountered an error while refreshing access token." + " If you are using a service account,\nplease verify that the " + "gs_service_key_file field in your config file,\n%s, is correct." % GetConfigFilePath()) _HandleUnknownFailure(e)
def _MaybeCheckForAndOfferSoftwareUpdate(self, command_name, debug): """Checks the last time we checked for an update, and if it's been longer than the configured threshold offers the user to update gsutil. Args: command_name: The name of the command being run. debug: Debug level to pass in to boto connection (range 0..3). Returns: True if the user decides to update. """ # Don't try to interact with user if: # - gsutil is not connected to a tty (e.g., if being run from cron); # - user is running gsutil -q # - user is running the update command (which could otherwise cause an # additional note that an update is available when user is already trying # to perform an update); # - user doesn't have credentials configured; or, # - user specified gs_host (which could be a non-production different # service instance, in which case credentials won't work for checking # gsutil tarball). gs_host = boto.config.get('Credentials', 'gs_host', None) if (not sys.stdout.isatty() or not sys.stderr.isatty() or not sys.stdin.isatty() or command_name == 'update' or not logging.getLogger().isEnabledFor(logging.INFO) or not HasConfiguredCredentials() or gs_host): return False software_update_check_period = boto.config.get( 'GSUtil', 'software_update_check_period', 30) # Setting software_update_check_period to 0 means periodic software # update checking is disabled. if software_update_check_period == 0: return False cur_ts = int(time.time()) if not os.path.isfile(LAST_CHECKED_FOR_GSUTIL_UPDATE_TIMESTAMP_FILE): # Set last_checked_ts from date of VERSION file, so if the user installed # an old copy of gsutil it will get noticed (and an update offered) the # first time they try to run it. last_checked_ts = int(os.path.getmtime(gslib.VERSION_FILE)) with open(LAST_CHECKED_FOR_GSUTIL_UPDATE_TIMESTAMP_FILE, 'w') as f: f.write(str(last_checked_ts)) else: with open(LAST_CHECKED_FOR_GSUTIL_UPDATE_TIMESTAMP_FILE, 'r') as f: last_checked_ts = int(f.readline()) if (cur_ts - last_checked_ts > software_update_check_period * SECONDS_PER_DAY): suri_builder = StorageUriBuilder(debug, self.bucket_storage_uri_class) cur_ver = LookUpGsutilVersion( suri_builder.StorageUri(GSUTIL_PUB_TARBALL)) with open(LAST_CHECKED_FOR_GSUTIL_UPDATE_TIMESTAMP_FILE, 'w') as f: f.write(str(cur_ts)) if gslib.VERSION != cur_ver: print '\n'.join( textwrap.wrap( 'A newer version of gsutil (%s) is available than the version you ' 'are running (%s). A detailed log of gsutil release changes is ' 'available at gs://pub/gsutil_ReleaseNotes.txt if you would like ' 'to read them before updating.' % (cur_ver, gslib.VERSION), width=78)) if gslib.IS_PACKAGE_INSTALL: return False print answer = raw_input('Would you like to update [Y/n]? ') return not answer or answer.lower()[0] != 'n' return False