def main(gcloud_cli=None): metrics.Started(START_TIME) # TODO(b/36049857): Put a real version number here metrics.Executions( 'gcloud', local_state.InstallationState.VersionForInstalledComponent('core')) if gcloud_cli is None: gcloud_cli = CreateCLI([]) try: try: gcloud_cli.Execute() except IOError as err: # We want to ignore EPIPE IOErrors. # By default, Python ignores SIGPIPE (see # http://utcc.utoronto.ca/~cks/space/blog/python/SignalExceptionSurprise). # This means that attempting to write any output to a closed pipe (e.g. in # the case of output piped to `head` or `grep -q`) will result in an # IOError, which gets reported as a gcloud crash. We don't want this # behavior, so we ignore EPIPE (it's not a real error; it's a normal thing # to occur). # Before, we restore the SIGPIPE signal handler, but that caused issues # with scripts/programs that wrapped gcloud. if err.errno != errno.EPIPE: raise except Exception as err: # pylint:disable=broad-except crash_handling.HandleGcloudCrash(err) if properties.VALUES.core.print_unhandled_tracebacks.GetBool(): # We want to see the traceback as normally handled by Python raise else: # This is the case for most non-Cloud SDK developers. They shouldn't see # the full stack trace, but just the nice "gcloud crashed" message. sys.exit(1)
def testCraReportCrashWithCorrectException(self): properties.VALUES.core.disable_usage_reporting.Set(False) properties.VALUES.metrics.command_name.Set(COMMAND) self.StartObjectPatch(metrics, 'GetCIDIfMetricsEnabled', return_value=CID) crash_handling.HandleGcloudCrash(Exception()) self.assertTrue(self.report_event_mock.called) args, _ = self.report_event_mock.call_args_list[0] self.assertTrue(args[0].startswith( 'https://clouderrorreporting.googleapis.com/v1beta1/projects/cloud-sdk' '-crashes/events:report?')) self.assertEqual(args[1], 'POST') self.assertEqual( args[2], '{"context": {"httpRequest": {"url": "command"}, "user": '******'"randomly-generated-id-adsfad"}, "message": "%s", "serviceContext": {' '"service": "gcloud", "version": "%s"}}' % (EXAMPLE_TRACEBACK_SERIALIZED, config.CLOUD_SDK_VERSION)) content_length = str(447 + len(config.CLOUD_SDK_VERSION)) self.assertEqual( args[3], {'content-length': content_length, 'content-type': 'application/json', 'accept-encoding': 'gzip, deflate', 'accept': 'application/json', 'user-agent': 'google-cloud-sdk'}) self.AssertErrContains('gcloud crashed') self.AssertErrContains('If you would like to report this issue, please run ' 'the following command:') self.AssertErrContains('gcloud feedback') self.AssertErrContains('To check gcloud for common problems, please run ' 'the following command:') self.AssertErrContains('gcloud info --run-diagnostics')
def testExceptionImportErrorRunCommand(self): # We want to suggest reinstall here and skip error reporting msg = 'Example exception message text' exception = command_loading.CommandLoadFailure('gcloud version', ImportError(msg)) crash_handling.HandleGcloudCrash(exception) self.report_error_mock.assert_not_called() self.AssertErrContains('gcloud failed to load') self.AssertErrContains('gcloud components reinstall') self.AssertErrContains('https://cloud.google.com/sdk/') self.AssertErrNotContains(r'gcloud feedback')
def testDisableMetricsDontSendErrorReport(self): crash_handling.HandleGcloudCrash(Exception()) self.report_event_mock.assert_not_called() self.AssertErrContains('gcloud crashed') self.AssertErrContains('If you would like to report this issue, please run ' 'the following command:') self.AssertErrContains('gcloud feedback') self.AssertErrContains('To check gcloud for common problems, please run ' 'the following command:') self.AssertErrContains('gcloud info --run-diagnostics')
def testHandleGcloudCrashUsageTrueProperty(self): # disable_usage_reporting is set to True msg = 'Example exception message text' exception = Exception(msg) crash_handling.HandleGcloudCrash(exception) self.report_event_mock.assert_not_called() self.AssertErrContains('gcloud crashed') self.AssertErrContains('If you would like to report this issue, please run ' 'the following command:') self.AssertErrContains('gcloud feedback') self.AssertErrContains('To check gcloud for common problems, please run ' 'the following command:') self.AssertErrContains('gcloud info --run-diagnostics')
def main(gcloud_cli=None, credential_providers=None): if not platforms.PythonVersion().IsCompatible( allow_py3=properties.VALUES.core.allow_py3.GetBool()): sys.exit(1) metrics.Started(START_TIME) # TODO(b/36049857): Put a real version number here metrics.Executions( 'gcloud', local_state.InstallationState.VersionForInstalledComponent('core')) if gcloud_cli is None: gcloud_cli = CreateCLI([]) # Register some other sources for credentials and project. credential_providers = credential_providers or [ creds_store.DevShellCredentialProvider(), creds_store.GceCredentialProvider(), ] for provider in credential_providers: provider.Register() # Register support for service account impersonation. creds_store.IMPERSONATION_TOKEN_PROVIDER = ( iamcred_util.ImpersonationAccessTokenProvider()) try: try: gcloud_cli.Execute() except IOError as err: # We want to ignore EPIPE IOErrors. # By default, Python ignores SIGPIPE (see # http://utcc.utoronto.ca/~cks/space/blog/python/SignalExceptionSurprise). # This means that attempting to write any output to a closed pipe (e.g. in # the case of output piped to `head` or `grep -q`) will result in an # IOError, which gets reported as a gcloud crash. We don't want this # behavior, so we ignore EPIPE (it's not a real error; it's a normal thing # to occur). # Before, we restore the SIGPIPE signal handler, but that caused issues # with scripts/programs that wrapped gcloud. if err.errno != errno.EPIPE: raise except Exception as err: # pylint:disable=broad-except crash_handling.HandleGcloudCrash(err) if properties.VALUES.core.print_unhandled_tracebacks.GetBool(): # We want to see the traceback as normally handled by Python raise else: # This is the case for most non-Cloud SDK developers. They shouldn't see # the full stack trace, but just the nice "gcloud crashed" message. sys.exit(1) finally: for provider in credential_providers: provider.UnRegister()
def testHandleGcloudCrashUsageFalseProperty(self): # disable_usage_reporting is set to False msg = 'Example exception message text' exception = Exception(msg) properties.VALUES.core.disable_usage_reporting.Set(False) crash_handling.HandleGcloudCrash(exception) self.report_error_mock.assert_called_with(is_crash=True) self.AssertErrContains('gcloud crashed') self.AssertErrContains('If you would like to report this issue, please run ' 'the following command:') self.AssertErrContains('gcloud feedback') self.AssertErrContains('To check gcloud for common problems, please run ' 'the following command:') self.AssertErrContains('gcloud info --run-diagnostics')
def testMetricsError(self): self.report_event_mock.side_effect = apitools_exceptions.Error properties.VALUES.core.disable_usage_reporting.Set(False) properties.VALUES.metrics.command_name.Set(COMMAND) self.StartObjectPatch(metrics, 'GetCIDIfMetricsEnabled', return_value=CID) crash_handling.HandleGcloudCrash(Exception()) self.report_event_mock.assert_called_once() self.AssertErrContains('gcloud crashed') self.AssertErrContains('If you would like to report this issue, please run ' 'the following command:') self.AssertErrContains('gcloud feedback') self.AssertErrContains('To check gcloud for common problems, please run ' 'the following command:') self.AssertErrContains('gcloud info --run-diagnostics')
def testInvalidCaCerts(self): msg = 'certificate verify failed' crash_handling.HandleGcloudCrash(Exception(msg)) self.report_error_mock.assert_called_once() self.AssertErrContains('gcloud crashed') self.AssertErrContains('gcloud\'s default CA certificates failed to verify ' 'your connection, which can happen if you are behind' ' a proxy or firewall.') self.AssertErrContains('To use a custom CA certificates file, please run ' 'the following command:') self.AssertErrContains(' gcloud config set core/custom_ca_certs_file ' '/path/to/ca_certs') self.AssertErrContains('If you would like to report this issue, please run ' 'the following command:') self.AssertErrContains('gcloud feedback') self.AssertErrContains('To check gcloud for common problems, please run ' 'the following command:') self.AssertErrContains('gcloud info --run-diagnostics')
def main(gcloud_cli=None, credential_providers=None): if not platforms.PythonVersion().IsCompatible( allow_py3=properties.VALUES.core.allow_py3.GetBool()): sys.exit(1) metrics.Started(START_TIME) # TODO(b/36049857): Put a real version number here metrics.Executions( 'gcloud', local_state.InstallationState.VersionForInstalledComponent('core')) if gcloud_cli is None: gcloud_cli = CreateCLI([]) # Register some other sources for credentials and project. credential_providers = credential_providers or [ creds_store.DevShellCredentialProvider(), creds_store.GceCredentialProvider(), ] for provider in credential_providers: provider.Register() # Register support for service account impersonation. creds_store.IMPERSONATION_TOKEN_PROVIDER = ( iamcred_util.ImpersonationAccessTokenProvider()) try: try: gcloud_cli.Execute() # Flush stdout so that if we've received a SIGPIPE we handle the broken # pipe within this try block, instead of potentially during interpreter # shutdown. sys.stdout.flush() except IOError as err: # We want to ignore EPIPE IOErrors (as of Python 3.3 these can be caught # specifically with BrokenPipeError, but we do it this way for Python 2 # compatibility). # # By default, Python ignores SIGPIPE (see # http://utcc.utoronto.ca/~cks/space/blog/python/SignalExceptionSurprise). # This means that attempting to write any output to a closed pipe (e.g. in # the case of output piped to `head` or `grep -q`) will result in an # IOError, which gets reported as a gcloud crash. We don't want this # behavior, so we ignore EPIPE (it's not a real error; it's a normal thing # to occur). # # Before, we restored the SIGPIPE signal handler, but that caused issues # with scripts/programs that wrapped gcloud. if err.errno == errno.EPIPE: # At this point we've caught the broken pipe, but since Python flushes # standard streams on exit, it's still possible for a broken pipe error # to happen during interpreter shutdown. The interpreter will catch this # but in Python 3 it still prints a warning to stderr saying that the # exception was ignored (see https://bugs.python.org/issue11380): # # Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' # encoding='UTF-8'> # BrokenPipeError: [Errno 32] Broken pipe # # To prevent this from happening, we redirect any remaining output to # devnull as recommended here: # https://docs.python.org/3/library/signal.html#note-on-sigpipe. devnull = os.open(os.devnull, os.O_WRONLY) os.dup2(devnull, sys.stdout.fileno()) else: raise except Exception as err: # pylint:disable=broad-except crash_handling.HandleGcloudCrash(err) if properties.VALUES.core.print_unhandled_tracebacks.GetBool(): # We want to see the traceback as normally handled by Python raise else: # This is the case for most non-Cloud SDK developers. They shouldn't see # the full stack trace, but just the nice "gcloud crashed" message. sys.exit(1) finally: for provider in credential_providers: provider.UnRegister()