def _PrintSuggestedAction(err, err_string): """Print the best action for the user to take, given the error.""" if (isinstance(err, backend.CommandLoadFailure) and type(err.root_exception) is ImportError): # This usually indicates installation corruption. # We do want to suggest `gcloud components reinstall` here (ex. as opposed # to the similar message in gcloud.py), because there's a good chance it'll # work (rather than a manual reinstall). # Don't suggest `gcloud feedback`, because this is probably an # installation problem. log.error( ('gcloud failed to load ({0}): {1}\n\n' 'This usually indicates corruption in your gcloud installation or ' 'problems with your Python interpreter.\n\n' 'Please verify that the following is the path to a working Python 2.7 ' 'executable:\n' ' {2}\n' 'If it is not, please set the CLOUDSDK_PYTHON environment variable to ' 'point to a working Python 2.7 executable.\n\n' 'If you are still experiencing problems, please run the following ' 'command to reinstall:\n' ' $ gcloud components reinstall\n\n' 'If that command fails, please reinstall the Cloud SDK using the ' 'instructions here:\n' ' https://cloud.google.com/sdk/' ).format(err.command, err_string, sys.executable)) else: log.error('gcloud crashed ({0}): {1}'.format( getattr(err, 'error_name', type(err).__name__), err_string)) log.err.Print('\nIf you would like to report this issue, please run the ' 'following command:') log.err.Print(' gcloud feedback')
def DeleteModule(self, module, version): """Deletes the given version of the module. Args: module: str, The module to delete. version: str, The version of the module to delete. Returns: bool, whether the deletion was successful """ rpcserver = self._GetRpcServer() response = rpcserver.Send('/api/versions/delete', app_id=self.project, module=module, version_match=version) # These strings have been seen in production, and verified against the code # of the AppEngine API endpoint being hit. if response == 'Module deleted.' or response.endswith('Success.\n'): # This is the normal case: deletion succeeded return True elif response == 'Cannot delete default version.\n': # This is a known error case. log.error('Cannot delete default version [{0}] of module [{1}].'.format( version, module)) return False else: # This is the unknown case. The safest behavior is to pass the message # through to the user as a warning, but assume the deletion succeeded. log.warning('Version [{0}] of module [{1}]: '.format(version, module) + response) return True
def HandleError(exc, command_path, known_error_handler=None): """Handles an error that occurs during command execution. It calls ConvertKnownError to convert exceptions to known types before processing. If it is a known type, it is printed nicely as as error. If not, it is raised as a crash. Args: exc: Exception, The original exception that occurred. command_path: str, The name of the command that failed (for error reporting). known_error_handler: f(exc): A function to process known errors. """ known_exc, print_error = ConvertKnownError(exc) if known_exc: msg = u'({0}) {1}'.format( console_attr.SafeText(command_path), console_attr.SafeText(known_exc)) log.debug(msg, exc_info=sys.exc_info()) if print_error: log.error(msg) # Uncaught errors will be handled in gcloud_main. if known_error_handler: known_error_handler(exc) if properties.VALUES.core.print_handled_tracebacks.GetBool(): raise _Exit(known_exc) else: # Make sure any uncaught exceptions still make it into the log file. log.debug(console_attr.SafeText(exc), exc_info=sys.exc_info()) raise
def Run(self, args): """Run 'deployments create'. Args: args: argparse.Namespace, The arguments that this command was invoked with. Returns: If --async=true, returns Operation to poll. Else, returns a struct containing the list of resources and list of outputs in the deployment. Raises: HttpException: An http error response was received while executing api request. ToolException: Config file could not be read or parsed, or the deployment creation operation encountered an error. """ client = self.context['deploymentmanager-client'] messages = self.context['deploymentmanager-messages'] project = properties.VALUES.core.project.Get(required=True) deployment = messages.Deployment( name=args.deployment_name, target=importer.BuildTargetConfig( messages, args.config, args.properties), ) if args.description: deployment.description = args.description try: operation = client.deployments.Insert( messages.DeploymentmanagerDeploymentsInsertRequest( project=project, deployment=deployment, preview=args.preview, ) ) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(dm_v2_util.GetError(error)) if args.async: return operation else: op_name = operation.name try: dm_v2_util.WaitForOperation(op_name, project, self.context, 'create', OPERATION_TIMEOUT) log.status.Print('Create operation ' + op_name + ' completed successfully.') except exceptions.ToolException: # Operation timed out or had errors. Print this warning, then still # show whatever operation can be gotten. log.error('Create operation ' + op_name + ' has errors or failed to complete within ' + str(OPERATION_TIMEOUT) + ' seconds.') except apitools_exceptions.HttpError as error: raise exceptions.HttpException(dm_v2_util.GetError(error)) return dm_v2_util.FetchResourcesAndOutputs(client, messages, project, args.deployment_name)
def DoWebFlow(self, launch_browser): """Launches a browser to get credentials.""" # pylint:disable=g-import-not-at-top, Import when needed for performance. import webbrowser try: # Sometimes it's not possible to launch the web browser. This often # happens when people ssh into other machines. if launch_browser: if c_gce.Metadata().connected: launch_browser = False try: browser = webbrowser.get() if (hasattr(browser, 'name') and browser.name in _WEBBROWSER_NAMES_BLACKLIST): launch_browser = False except webbrowser.Error: launch_browser = False return c_store.AcquireFromWebFlow(launch_browser=launch_browser) except c_store.FlowError: msg = 'There was a problem with web authentication.' if launch_browser: msg += ' Try running again with --no-launch-browser.' log.error(msg) raise
def FromURL(url): """Loads a snapshot from a URL. Args: url: str, The URL to the file to load. Returns: A ComponentSnapshot object. Raises: URLFetchError: If the URL cannot be fetched. """ req = urllib2.Request(url, data=None, headers={'Cache-Control': 'no-cache'}) try: response = urllib2.urlopen(req, timeout=TIMEOUT_IN_SEC) except (urllib2.HTTPError, urllib2.URLError, ssl.SSLError) as e: log.error('Could not fetch [{url}]: {error}.'.format( url=url, error=e)) response = None if not response: raise URLFetchError( ('Unable to fetch component listing from server. Check your network' ' settings and try again.')) code = response.getcode() if code and code != 200: raise URLFetchError('Received response code %s while fetching %s.', code, url) data = json.loads(response.read()) # TODO(user) Handle a json parse error here. return ComponentSnapshot.FromDictionary(data, url=url)
def main(gcloud_cli=None): metrics.Started(START_TIME) # TODO(markpell): Put a real version number here metrics.Executions( 'gcloud', local_state.InstallationState.VersionForInstalledComponent('core')) if gcloud_cli is None: gcloud_cli = CreateCLI([]) try: gcloud_cli.Execute() except Exception as e: # pylint:disable=broad-except log.error('gcloud crashed ({0}): {1}'.format( getattr(e, 'error_name', type(e).__name__), gcloud_cli.SafeExceptionToString(e))) log.err.Print('\nIf you would like to report this issue, please run the ' 'following command:') log.err.Print(' gcloud feedback') 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 Run(self, args): """This is what gets called when the user runs this command. Args: args: an argparse namespace. All the arguments that were provided to this command invocation. Raises: util.Error: if the cluster is unreachable or not running. """ util.CheckKubectlInstalled() adapter = self.context['api_adapter'] cluster_ref = adapter.ParseCluster(args.name) log.status.Print('Fetching cluster endpoint and auth data.') # Call DescribeCluster to get auth info and cache for next time cluster = adapter.GetCluster(cluster_ref) auth = cluster.masterAuth has_creds = (auth and ((auth.clientCertificate and auth.clientKey) or (auth.username and auth.password))) if not has_creds and not util.ClusterConfig.UseGCPAuthProvider(cluster): raise util.Error( 'get-credentials requires edit permission on {0}'.format( cluster_ref.projectId)) if not adapter.IsRunning(cluster): log.error( 'cluster %s is not running. The kubernetes API will probably be ' 'unreachable.' % cluster_ref.clusterId) util.ClusterConfig.Persist(cluster, cluster_ref.projectId)
def DockerLogin(server, email, username, access_token): """Register the username / token for the given server on Docker's keyring.""" # Sanitize and normalize the server input. parsed_url = client_lib.GetNormalizedURL(server) server = parsed_url.geturl() # 'docker login' must be used due to the change introduced in # https://github.com/docker/docker/pull/20107 . docker_args = ['login'] if not _EmailFlagDeprecatedForDockerVersion(): docker_args.append('--email=' + email) docker_args.append('--username='******'--password='******'Docker CLI operation failed:') log.out.Print(stdoutdata) log.status.Print(stderrdata) raise client_lib.DockerError('Docker login failed.')
def Run(self, args): if args.config: # If the user has specified an config file, use that. config_filename = args.config else: # Otherwise, check for an app.yaml in the source directory. config_filename = os.path.join(args.source_dir, 'app.yaml') if not os.path.exists(config_filename): config_filename = None # If there was an config file either specified by the user or in the source # directory, load it. if config_filename: try: myi = yaml_parsing.ModuleYamlInfo.FromFile(config_filename) config = myi.parsed except IOError as ex: log.error('Unable to open %s: %s', config_filename, ex) return else: config = None fingerprinter.GenerateConfigs( args.source_dir, fingerprinting.Params(appinfo=config, custom=args.custom)) # If the user has a config file, make sure that they're using a custom # runtime. if config and args.custom and config.GetEffectiveRuntime() != 'custom': log.status.Print(RUNTIME_MISMATCH_MSG % config_filename)
def _PrintInstallationAction(err, err_string): """Prompts installation error action. Args: err: Exception err. err_string: Exception err string. """ # This usually indicates installation corruption. # We do want to suggest `gcloud components reinstall` here (ex. as opposed # to the similar message in gcloud.py), because there's a good chance it'll # work (rather than a manual reinstall). # Don't suggest `gcloud feedback`, because this is probably an # installation problem. log.error( ('gcloud failed to load ({0}): {1}\n\n' 'This usually indicates corruption in your gcloud installation or ' 'problems with your Python interpreter.\n\n' 'Please verify that the following is the path to a working Python 2.7 ' 'executable:\n' ' {2}\n' 'If it is not, please set the CLOUDSDK_PYTHON environment variable to ' 'point to a working Python 2.7 executable.\n\n' 'If you are still experiencing problems, please run the following ' 'command to reinstall:\n' ' $ gcloud components reinstall\n\n' 'If that command fails, please reinstall the Cloud SDK using the ' 'instructions here:\n' ' https://cloud.google.com/sdk/' ).format(err.command, err_string, sys.executable))
def _ProcessStreamingOutput(line): """Handles the streaming output of the docker client. Args: line: a single line of streamed output. Raises: Error: if a problem occured during the operation with an explanation string if possible. """ line = line.strip() if not line: return log_record = json.loads(line) if 'status' in log_record: feedback = log_record['status'].strip() if 'progress' in log_record: feedback += ': ' + log_record['progress'] + '\r' else: feedback += '\n' log.info(feedback) elif 'error' in log_record: error = log_record['error'].strip() log.error(error) raise Error('Unable to push the image to the registry: "%s"' % error) elif 'errorDetail' in log_record: error_detail = log_record['errorDetail'] or 'Unknown Error' raise Error('Unable to push the image to the registry: "%s"' % error_detail)
def ProgressHandler(action, func_with_output_lines): """Handles the streaming output of the docker client. Args: action: str, action verb for logging purposes, for example "push" or "pull". func_with_output_lines: a function streaming output from the docker client. Raises: Error: if a problem occured during the operation with an explanation string if possible. """ for line in func_with_output_lines(): line = line.strip() if not line: continue log_record = json.loads(line) if 'status' in log_record: feedback = log_record['status'].strip() if 'progress' in log_record: feedback += ': ' + log_record['progress'] + '\r' else: feedback += '\n' log.info(feedback) elif 'error' in log_record: error = log_record['error'].strip() log.error(error) raise Error('Unable to %s the image to/from the registry: "%s"' % (action, error)) elif 'errorDetail' in log_record: error_detail = log_record['errorDetail'] or 'Unknown Error' raise Error('Unable to push the image to the registry: "%s"' % error_detail)
def DoInstalledAppBrowserFlow(client_id_file, scopes, launch_browser): """Launches a browser to get credentials.""" try: if client_id_file is not None: client_type = GetClientSecretsType(client_id_file) if client_type != clientsecrets.TYPE_INSTALLED: raise c_exc.ToolException( 'Only client IDs of type \'%s\' are allowed, but encountered ' 'type \'%s\'' % (clientsecrets.TYPE_INSTALLED, client_type)) return c_store.AcquireFromWebFlowAndClientIdFile( client_id_file=client_id_file, scopes=scopes, launch_browser=launch_browser) else: return c_store.AcquireFromWebFlow( launch_browser=launch_browser, scopes=scopes, client_id=DEFAULT_CREDENTIALS_DEFAULT_CLIENT_ID, client_secret=DEFAULT_CREDENTIALS_DEFAULT_CLIENT_SECRET) except c_store.FlowError: msg = 'There was a problem with web authentication.' if launch_browser: msg += ' Try running again with --no-launch-browser.' log.error(msg) raise
def Display(self, args, result): """Display prints information about what just happened to stdout. Args: args: The same as the args in Run. result: A dict object representing the response if the api request was successful. """ printer = util.PrettyPrinter(0) if args.cert_file is not None: cert_file = args.cert_file private_key = result.get('clientCert').get('certPrivateKey') while True: try: with files.OpenForWritingPrivate(cert_file) as cf: cf.write(private_key) cf.write('\n') printer.Print('Wrote the private key for ssl-cert "{name}" to {file}.' .format(name=args.common_name, file=cert_file)) return except OSError as e: log.error(e) cert_file = console_io.PromptResponse( 'Enter a destination for the cert:') else: printer.PrintSslCertInsertResponse(result) printer.Print('Note: Save the private key. This is the only time you ' 'will be able to see the private key. If you lose this ' 'private key, you will have to create a new certificate.')
def _GetCatalog(client, messages, environment_type): """Gets a test environment catalog from the TestEnvironmentDiscoveryService. Args: client: The Testing API client object. messages: The Testing API messages object. environment_type: {enum} which EnvironmentType catalog to get. Returns: The test environment catalog. Raises: calliope_exceptions.HttpException: If it could not connect to the service. """ request = messages.TestingTestEnvironmentCatalogGetRequest( environmentType=environment_type, projectId=properties.VALUES.core.project.Get()) try: return client.testEnvironmentCatalog.Get(request) except apitools_exceptions.HttpError as error: raise calliope_exceptions.HttpException( 'Unable to access the test environment catalog: ' + GetError(error)) except: # Give the user some explanation in case we get a vague/unexpected error, # such as a socket.error from httplib2. log.error('Unable to access the Firebase Test Lab environment catalog.') raise # Re-raise the error in case Calliope can do something with it.
def _GetCatalog(context, environment_type): """Gets a test environment catalog from the TestEnvironmentDiscoveryService. Args: context: {str:object}, The current context, which is a set of key-value pairs that can be used for common initialization among commands. environment_type: Value from the EnvironmentType enum. Returns: The test environment catalog. Raises: exceptions.HttpException: If it could not connect to the service. """ client = context['testing_client'] messages = context['testing_messages'] request = messages.TestingTestEnvironmentCatalogGetRequest() request.environmentType = environment_type try: return client.testEnvironmentCatalog.Get(request) except apitools_exceptions.HttpError as error: raise exceptions.HttpException( 'Unable to access the test environment catalog: ' + GetError(error)) except: # Give the user some explanation in case we get a vague/unexpected error, # such as a socket.error from httplib2. log.error('Unable to access the test environment catalog.') raise # Re-raise the error in case Calliope can do something with it.
def HandleEndpointsError(self, user_error): """Handle an error state returned by IsEndpointsConfigUpdated. Args: user_error: Either None or a string with a message from the server that indicates what the error was and how the user should resolve it. Raises: Error: The update state is fatal and the user hasn't chosen to ignore Endpoints errors. """ detailed_error = user_error or ( "Check the app's AppEngine logs for errors: %s" % self.GetLogUrl()) error_message = ('Failed to update Endpoints configuration. %s' % detailed_error) log.error(error_message) # Also display a link to the Python troubleshooting documentation. doc_link = ('https://developers.google.com/appengine/docs/python/' 'endpoints/test_deploy#troubleshooting_a_deployment_failure') log.error('See the deployment troubleshooting documentation for more ' 'information: %s' % doc_link) if self.ignore_endpoints_failures: log.debug('Ignoring Endpoints failure and proceeding with update.') else: raise Error(error_message)
def Build(self): """Calls "docker build". Raises: ImageBuildError: if the image could not be built. """ log.info('Building docker image %s from %s/Dockerfile:', self.tag, self._image_opts.dockerfile_dir) width, _ = console_attr_os.GetTermSize() log.status.Print(DOCKER_OUTPUT_BEGIN.center(width, DOCKER_OUTPUT_LINE_CHAR)) build_res = self._docker_client.build( path=self._image_opts.dockerfile_dir, tag=self.tag, quiet=False, fileobj=None, nocache=self._image_opts.nocache, rm=self._image_opts.rm) info = None error = None error_detail = None log_records = [] try: for line in build_res: line = line.strip() if not line: continue log_record = json.loads(line) log_records.append(log_record) if 'stream' in log_record: info = log_record['stream'].strip() log.status.Print(info) if 'error' in log_record: error = log_record['error'].strip() # will be logged to log.error in the thrown exception log.status.Print(error) if 'errorDetail' in log_record: error_detail = log_record['errorDetail']['message'].strip() log.status.Print(error_detail) except docker.errors.APIError as e: log.error(e.explanation) error = e.explanation error_detail = '' finally: log.status.Print(DOCKER_OUTPUT_LINE_CHAR * width + '\n') if not log_records: raise ImageBuildError( 'Error building docker image {0} [with no output]'.format(self.tag)) success_message = log_records[-1].get(_STREAM) if success_message: m = _SUCCESSFUL_BUILD_PATTERN.match(success_message) if m: # The build was successful. self._id = m.group(1) log.info('Image %s built, id = %s', self.tag, self.id) return raise ImageBuildError('Docker build aborted: ' + error)
def TryYaml(): try: return yaml.load(input_string) except yaml.YAMLError as e: if hasattr(e, 'problem_mark'): mark = e.problem_mark log.error('Service config YAML had an error at position (%s:%s)' % (mark.line+1, mark.column+1))
def _DoFreshInstall(self, e): """Do a reinstall of what we have based on a fresh download of the SDK. Args: e: snapshots.IncompatibleSchemaVersionError, The exception we got with information about the new schema version. """ self._EnsureNotDisabled() if os.environ.get('CLOUDSDK_REINSTALL_COMPONENTS'): # We are already reinstalling but got here somehow. Something is very # wrong and we want to avoid the infinite loop. self._RaiseReinstallationFailedError() # Print out an arbitrary message that we wanted to show users for this # udpate. message = e.schema_version.message if message: self.__Write(msg=message, word_wrap=True) # We can decide that for some reason we just never want to update past this # version of the schema. if e.schema_version.no_update: return answer = console_io.PromptContinue( message='\nThe component manager must perform a self update before you ' 'can continue. It and all components will be updated to their ' 'latest versions.') if not answer: return self._CheckCWD() install_state = self._GetInstallState() self.__Write('Downloading and extracting updated components...\n') download_url = e.schema_version.url try: staging_state = install_state.CreateStagingFromDownload(download_url) except local_state.Error: log.error('An updated Cloud SDK failed to download') log.debug('Handling re-installation error', exc_info=True) self._RaiseReinstallationFailedError() # shell out to install script installed_component_ids = sorted(install_state.InstalledComponents().keys()) env = dict(os.environ) env['CLOUDSDK_REINSTALL_COMPONENTS'] = ','.join( installed_component_ids) installer_path = os.path.join(staging_state.sdk_root, 'bin', 'bootstrapping', 'install.py') p = subprocess.Popen([sys.executable, '-S', installer_path], env=env) ret_val = p.wait() if ret_val: self._RaiseReinstallationFailedError() self.__Write('Creating backup and activating new installation...') install_state.ReplaceWith(staging_state) self.__Write('\nDone!\n')
def error(self, message=None, context=None): """Overrides argparse.ArgumentParser's .error(message) method. Specifically, it avoids reprinting the program name and the string "error:". Args: message: str, The error message to print. context: _ErrorContext, A previous intercepted error context to reproduce. """ if context: # Reproduce a previous call to this method from the info in context. message = context.message parser = context.parser error = context.error if error: # argparse calls this method as the result of an exception that can be # checked in sys.exc_info()[1]. A side effect of this try-except is to # set sys.exc_info()[1] to context.error from the original call that was # saved below in self._error_context. This value might be checked later # in the execution (the test harness in particular checks it). try: raise error # pylint: disable=raising-bad-type except type(error): pass else: error = sys.exc_info()[1] else: error = sys.exc_info()[1] parser = self if '_ARGCOMPLETE' not in os.environ and ( self._probe_error or 'too few arguments' in message or 'Invalid choice' in message): # Save this context for later. We may be able to decuce a better error # message. For instance, argparse might complain about an invalid # command choice 'flag-value' for '--unknown-flag flag-value', but # with a little finagling in parse_known_args() we can verify that # '--unknown-flag' is in fact an unknown flag and error out on that. self._error_context = _ErrorContext(message, parser, error) return parser.ReportErrorMetrics(error, message) # No need to output help/usage text if we are in completion mode. However, # we do need to populate group/command level choices. These choices are not # loaded when there is a parser error since we do lazy loading. if '_ARGCOMPLETE' in os.environ: # pylint:disable=protected-access if self._calliope_command._sub_parser: self._calliope_command.LoadAllSubElements() else: message = console_attr.EncodeForConsole(message) log.error(u'({prog}) {message}'.format(prog=self.prog, message=message)) # multi-line message means hints already added, no need for usage. # pylint:disable=protected-access if '\n' not in message: argparse._sys.stderr.write(self._calliope_command.GetUsage()) self.exit(2)
def RunPlugin(self, section_name, plugin_spec, params, args=None, valid_exit_codes=(0,), runtime_data=None): """Run a plugin. Args: section_name: (str) Name of the config section that the plugin spec is from. plugin_spec: ({str: str, ...}) A dictionary mapping plugin locales to script names params: (fingerprinting.Params or None) Parameters for the plugin. args: ([str, ...] or None) Command line arguments for the plugin. valid_exit_codes: (int, ...) Exit codes that will be accepted without raising an exception. runtime_data: ({str: object, ...}) A dictionary of runtime data passed back from detect. Returns: (PluginResult) A bundle of the exit code and data produced by the plugin. Raises: PluginInvocationFailed: The plugin terminated with a non-zero exit code. """ # TODO(user): Support other script types. if plugin_spec.has_key('python'): normalized_path = _NormalizePath(self.root, plugin_spec['python']) # We're sharing 'result' with the output collection thread, we can get # away with this without locking because we pass it into the thread at # creation and do not use it again until after we've joined the thread. result = PluginResult() p = subprocess.Popen([execution_utils.GetPythonExecutable(), normalized_path] + (args if args else []), stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) stderr_thread = threading.Thread(target=self._ProcessPluginStderr, args=(section_name, p.stderr,)) stderr_thread.start() stdout_thread = threading.Thread(target=self._ProcessPluginPipes, args=(section_name, p, result, params, runtime_data)) stdout_thread.start() stderr_thread.join() stdout_thread.join() exit_code = p.wait() result.exit_code = exit_code if exit_code not in valid_exit_codes: raise PluginInvocationFailed('Failed during execution of plugin %s ' 'for section %s of runtime %s. rc = %s' % (normalized_path, section_name, self.config.get('name', 'unknown'), exit_code)) return result else: log.error('No usable plugin type found for %s' % section_name)
def _LogKnownError(known_exc, command_path, print_error): msg = '({0}) {1}'.format(console_attr.SafeText(command_path), console_attr.SafeText(known_exc)) help_message = _MessageWhenMissingServiceUsePermission(known_exc) if help_message: msg = '{0}\n\n{1}'.format(msg, console_attr.SafeText(help_message)) log.debug(msg, exc_info=sys.exc_info()) if print_error: log.error(msg)
def Run(self, args): ve_dir = config.Paths().virtualenv_dir if util.VirtualEnvExists(ve_dir): if util.EnableFileExists(ve_dir): util.RmEnableFile(ve_dir) log.status.Print('Virtual env disabled.') else: log.error('Virtual env does not exist at {}.'.format(ve_dir)) raise exceptions.ExitCodeNoError(exit_code=1)
def OperationResponseHandler(self, response, args): if response.failed: log.error(response.stderr) return None if response.stderr: log.status.Print(response.stderr) return response.stdout
def ConnectToInstance(cmd_args, sql_user): """Connects to the instance using the relevant CLI.""" try: log.status.write( 'Connecting to database with SQL user [{0}].'.format(sql_user)) execution_utils.Exec(cmd_args) except OSError: log.error('Failed to execute command "{0}"'.format(' '.join(cmd_args))) log.Print(info_holder.InfoHolder())
def TryYaml(): try: return yaml.load(input_string) except yaml.YAMLError as e: if hasattr(e, 'problem_mark'): mark = e.problem_mark log.error( 'Service config YAML had an error at position (%s:%s)' % (mark.line + 1, mark.column + 1))
def _FetchAccessToken(self, workstation): try: self.access_token = self.client.projects_locations_workstationClusters_workstations.GenerateAccessToken( self.messages. WorkstationsProjectsLocationsWorkstationClustersWorkstationsGenerateAccessTokenRequest( workstation=workstation.RelativeName(), )).accessToken except Error as e: log.error('Error fetching access token: {0}'.format(e)) sys.exit(1)
def DoInstalledAppBrowserFlow(self, launch_browser): """Launches a browser to get credentials.""" try: return c_store.AcquireFromWebFlow(launch_browser=launch_browser) except c_store.FlowError: msg = 'There was a problem with web authentication.' if launch_browser: msg += ' Try running again with --no-launch-browser.' log.error(msg) raise
def OperationResponseHandler(self, response, args): if response.failed: log.error(response.stderr) return None if response.stderr: log.status.Print(response.stderr) log.status.Print('Service is successfully deleted.') return None
def CleanUp(self): """Cleanup any files or resource provisioned during config init.""" if (self.encrypted_client_cert_path is not None and os.path.exists(self.encrypted_client_cert_path)): try: os.remove(self.encrypted_client_cert_path) log.debug('unprovisioned client cert - %s', self.encrypted_client_cert_path) except files.Error as e: log.error('failed to remove client certificate - %s', e)
def TearDown(self): for img in self.images_to_delete: try: self.Run('container images delete -q --force-delete-tags {0}'. format(img)) # Don't fail the test if deletion fails for any reason. # The cleanup script will remove undeleted images. except Exception as e: # pylint: disable=broad-except log.error('Error deleting image: {0}. Error: {1}'.format( img, e))
def CreateCluster(dataproc, cluster, is_async, timeout): """Create a cluster. Args: dataproc: Dataproc object that contains client, messages, and resources cluster: Cluster to create is_async: Whether to wait for the operation to complete timeout: Timeout used when waiting for the operation to complete Returns: Created cluster, or None if async """ # Get project id and region. cluster_ref = util.ParseCluster(cluster.clusterName, dataproc) request_id = util.GetUniqueId() request = dataproc.messages.DataprocProjectsRegionsClustersCreateRequest( cluster=cluster, projectId=cluster_ref.projectId, region=cluster_ref.region, requestId=request_id) operation = dataproc.client.projects_regions_clusters.Create(request) if is_async: log.status.write('Creating [{0}] with operation [{1}].'.format( cluster_ref, operation.name)) return operation = util.WaitForOperation( dataproc, operation, message='Waiting for cluster creation operation', timeout_s=timeout) get_request = dataproc.messages.DataprocProjectsRegionsClustersGetRequest( projectId=cluster_ref.projectId, region=cluster_ref.region, clusterName=cluster_ref.clusterName) cluster = dataproc.client.projects_regions_clusters.Get(get_request) if cluster.status.state == ( dataproc.messages.ClusterStatus.StateValueValuesEnum.RUNNING): zone_uri = cluster.config.gceClusterConfig.zoneUri zone_short_name = zone_uri.split('/')[-1] # Log the URL of the cluster log.CreatedResource( cluster_ref, # Also indicate which zone the cluster was placed in. This is helpful # if the server picked a zone (auto zone) details='Cluster placed in zone [{0}]'.format(zone_short_name)) else: log.error('Create cluster failed!') if operation.details: log.error('Details:\n' + operation.details) return cluster
def NewDockerClient(local=False, **kwargs): """Factory method for building a docker.Client from environment variables. Args: local: bool, whether this is a local docker build **kwargs: Any kwargs will be passed to the docker.Client constructor and override any determined from the environment. Returns: A docker.Client instance. Raises: DockerDaemonConnectionError: If the Docker daemon isn't responding. """ client = NewDockerClientNoCheck(**kwargs) try: client.ping() except requests.exceptions.SSLError as e: log.error('Failed to connect to Docker daemon due to an SSL problem: %s', e) msg = '' # There is a common problem with TLS and docker-py on OS X Python # installations, especially the one in Homebrew. if platforms.Platform.Current() == platforms.OperatingSystem.MACOSX: msg += ('\n\nThis may be due to the issue described at the following ' 'URL, especially if you\'re using a Python installation from ' 'Homebrew: ' 'https://github.com/docker/docker-py/issues/465\n\n' 'One possible workaround is to set the environment variable ' 'CLOUDSDK_PYTHON to another Python executable (that is, not the ' 'one from Homebrew).') try: # This is a part of requests[security], which is a set of optional # dependencies for the requests library. If installed, it can work # around the SSL issue. # pylint: disable=g-import-not-at-top import ndg # pylint: disable=import-error,unused-variable # pylint: enable=g-import-not-at-top except ImportError: msg += ('\n\nYou do not appear to have requests[security] installed. ' 'Consider installing this package (which bundles security ' 'libraries that may fix this problem) to the current Python ' 'installation as another possible workaround:\n' ' pip install requests[security]\n' 'If you do this, you must set the environment variable ' 'CLOUDSDK_PYTHON_SITEPACKAGES before running the Cloud SDK ' 'again:\n' ' export CLOUDSDK_PYTHON_SITEPACKAGES=1') raise DockerDaemonConnectionError( 'Couldn\'t connect to the Docker daemon due to an SSL problem.' + msg) except requests.exceptions.ConnectionError, e: log.error('Failed to connect to Docker Daemon due to: %s', e) msg = DOCKER_CONNECTION_ERROR if local: msg += '\n' + DOCKER_CONNECTION_ERROR_LOCAL raise DockerDaemonConnectionError(msg)
def Persist(cls, cluster, project_id, cli): """Save config data for the given cluster. Persists config file and kubernetes auth file for the given cluster to cloud-sdk config directory and returns ClusterConfig object encapsulating the same data. Args: cluster: valid Cluster message to persist config data for. project_id: project that owns this cluster. cli: calliope.cli.CLI, The top-level CLI object. Returns: ClusterConfig of the persisted data. """ kwargs = { 'cluster_name': cluster.name, 'zone_id': cluster.zone, 'project_id': project_id, 'server': 'https://' + cluster.endpoint, } auth = cluster.masterAuth version = cls._ClusterVersion(cluster) if auth.clientCertificate and auth.clientKey and auth.clusterCaCertificate: kwargs['ca_data'] = auth.clusterCaCertificate kwargs['client_key_data'] = auth.clientKey kwargs['client_cert_data'] = auth.clientCertificate elif IsVersionOlderThan(version, '0.18'): # Manually copy cert files for legacy clusters. config_dir = cls.GetConfigDir(cluster.name, cluster.zone, project_id) file_utils.MakeDir(config_dir) certs = cls._FetchCertFiles(cluster, project_id, cli) kwargs['has_cert_files'] = bool(certs) else: # This should not happen unless the cluster is in an unusual error # state. log.error('Cluster is missing certificate data.') # TODO(user): these are not needed if cluster has certs, though they # are useful for testing, e.g. with curl. Consider removing if/when the # apiserver no longer supports insecure (no certs) requests. # TODO(user): use api_adapter instead of getattr, or remove bearerToken # support if getattr(auth, 'bearerToken', None): kwargs['token'] = auth.bearerToken else: username = getattr(auth, 'user', None) or getattr( auth, 'username', None) kwargs['username'] = username kwargs['password'] = auth.password c_config = cls(**kwargs) c_config.GenKubeconfig() return c_config
def Run(self, args): """Returns the results for one completion.""" presentation_kwargs = args.resource_presentation_kwargs or {} with cache_util.GetCache(args.cache, create=True) as cache: log.info('cache name {}'.format(cache.name)) if not args.kwargs: args.kwargs = {} # Create the ResourceInfo object that is used to hook up the parameter # info to the argparse namespace for resource argument completers. if args.resource_spec_path: spec = _GetPresentationSpec(args.resource_spec_path, **presentation_kwargs) spec.required = False resource_info = concept_parsers.ConceptParser([spec]).GetInfo( spec.name) # Since the argument being completed doesn't have the correct # dest, make sure the handler always gives the same ResourceInfo # object. def ResourceInfoMonkeyPatch(*args, **kwargs): del args, kwargs return resource_info args.CONCEPTS.ArgNameToConceptInfo = ResourceInfoMonkeyPatch completer = _GetCompleter(args.module_path, cache=cache, qualify=args.qualify, resource_spec=args.resource_spec_path, presentation_kwargs=presentation_kwargs, attribute=args.attribute, **args.kwargs) parameter_info = completer.ParameterInfo( args, args.GetPositionalArgument('resource_to_complete')) if args.resource_to_complete is not None: matches = completer.Complete(args.resource_to_complete, parameter_info) return [matches] while True: name = console_io.PromptResponse('COMPLETE> ') if name is None: break try: completions = completer.Complete(name, parameter_info) except (Exception, SystemExit) as e: # pylint: disable=broad-except if args.stack_trace: exceptions.reraise(Exception(e)) else: log.error(six.text_type(e)) continue if completions: print('\n'.join(completions)) sys.stderr.write('\n') return None
def _check_if_docker_installed(): """Checks for 'docker' in system PATH.""" if not shutil.which('docker'): log.error('[2/3] Docker not found') if platforms.OperatingSystem.Current( ) == platforms.OperatingSystem.LINUX: error_format = DOCKER_NOT_FOUND_HELP_TEXT_LINUX_FORMAT else: error_format = DOCKER_NOT_FOUND_HELP_TEXT_NON_LINUX_FORMAT raise OSError(error_format.format(gcloud_args=' '.join(sys.argv[1:])))
def GetApplicationCodeBucket(self): """Retrieves the default code bucket associated with the application.""" request = self.messages.AppengineAppsGetRequest( name=self._FormatApp(app_id=self.project), ensureResourcesExist=True) try: application = requests.MakeRequest(self.client.apps.Get, request) except exceptions.HttpException, e: log.error(e) return ''
def _DefaultOperationResponseHandler(response): """Process results of BinaryOperation Execution.""" if response.stdout: log.status.Print(response.stdout) if response.failed: log.error(response.stderr) return None log.status.Print(response.stderr) return response.stdout
def _LoginResponseHandler(self, response): if response.stdout: log.status.Print(response.stdout) if response.stderr: log.status.Print(response.stderr) if response.failed: log.error(self._LOGIN_CONFIG_FAILED_MESSAGE.format(response.stderr)) return None log.status.Print(self._LOGIN_CONFIG_SUCCESS_MESSAGE) return response.stdout
def ExecuteCleanup(self, scenario_context): # TODO(b/112041463): Make cleanup more robust. if not self.cleanup_for: return if (self.cleanup_for in scenario_context.resource_ref_resolver.UncleanedReferences()): try: self.Execute(scenario_context) except Exception as e: # pylint: disable=broad-except, Best effort if isinstance(e, (KeyboardInterrupt, SystemExit)): raise log.error('Cleanup step failed: {}'.format(e))
def Run(self, args): """Run the authentication command.""" # Run the auth flow. Even if the user already is authenticated, the flow # will allow him or her to choose a different account. try: launch_browser = args.launch_browser and not c_gce.Metadata().connected # Sometimes it's not possible to launch the web browser. This often # happens when people ssh into other machines. if launch_browser: try: browser = webbrowser.get() if (hasattr(browser, 'name') and browser.name in _WEBBROWSER_NAMES_BLACKLIST): launch_browser = False except webbrowser.Error: launch_browser = False creds = c_store.AcquireFromWebFlow( launch_browser=launch_browser) except c_store.FlowError: log.error( ('There was a problem with the web flow. Try running with ' '--no-launch-browser')) raise account = args.account if not account: account = creds.token_response['id_token']['email'] c_store.Store(creds, account) if not args.do_not_activate: properties.PersistProperty(properties.VALUES.core.account, account) project = args.project if not project and sys.stdout.isatty(): project = console_io.PromptResponse( ('\nYou can view your existing projects and create new ones in the ' 'Google Developers Console at: ' 'https://console.developers.google.com. ' 'If you have a project ready, you can enter it now.\n\n' 'Enter your Google Cloud project ID (or leave blank to not set): ')) if project: properties.PersistProperty(properties.VALUES.core.project, project) else: log.err.write( '\nYou can set your active project at any time by running:\n' ' $ gcloud config set project <project id>\n') return creds
def Persist(cls, cluster, project_id, cli): """Save config data for the given cluster. Persists config file and kubernetes auth file for the given cluster to cloud-sdk config directory and returns ClusterConfig object encapsulating the same data. Args: cluster: valid Cluster message to persist config data for. project_id: project that owns this cluster. cli: calliope.cli.CLI, The top-level CLI object. Returns: ClusterConfig of the persisted data. """ kwargs = { 'cluster_name': cluster.name, 'zone_id': cluster.zone, 'project_id': project_id, 'server': 'https://' + cluster.endpoint, } auth = cluster.masterAuth version = cls._ClusterVersion(cluster) if auth.clientCertificate and auth.clientKey and auth.clusterCaCertificate: kwargs['ca_data'] = auth.clusterCaCertificate kwargs['client_key_data'] = auth.clientKey kwargs['client_cert_data'] = auth.clientCertificate elif IsVersionOlderThan(version, '0.18'): # Manually copy cert files for legacy clusters. config_dir = cls.GetConfigDir(cluster.name, cluster.zone, project_id) file_utils.MakeDir(config_dir) certs = cls._FetchCertFiles(cluster, project_id, cli) kwargs['has_cert_files'] = bool(certs) else: # This should not happen unless the cluster is in an unusual error # state. log.error('Cluster is missing certificate data.') # TODO(user): these are not needed if cluster has certs, though they # are useful for testing, e.g. with curl. Consider removing if/when the # apiserver no longer supports insecure (no certs) requests. # TODO(user): use api_adapter instead of getattr, or remove bearerToken # support if getattr(auth, 'bearerToken', None): kwargs['token'] = auth.bearerToken else: username = getattr(auth, 'user', None) or getattr(auth, 'username', None) kwargs['username'] = username kwargs['password'] = auth.password c_config = cls(**kwargs) c_config.GenKubeconfig() return c_config
def PrintError(message): """Override's argparse.ArgumentParser's .error(message) method. Specifically, it avoids reprinting the program name and the string "error:". Args: message: str, The error message to print. """ # pylint:disable=protected-access shorthelp = ShortHelpText(command, command._ai) argparse._sys.stderr.write(shorthelp + '\n') log.error('({prog}) {message}'.format(prog=parser.prog, message=message)) parser.exit(2)
def PrintError(message): """Override's argparse.ArgumentParser's .error(message) method. Specifically, it avoids reprinting the program name and the string "error:". Args: message: str, The error message to print. """ # pylint:disable=protected-access, Trying to mimic exactly what happens # in the argparse code, except for the desired change. parser.print_usage(argparse._sys.stderr) log.error('({prog}) {message}'.format(prog=parser.prog, message=message)) parser.exit(2)
def Epilog(self, resources_were_displayed): del resources_were_displayed if self._errors: log.error(self._errors[0][1]) elif self._log_async: log.status.Print('Bulk instance creation in progress: {}'.format( self._operation_selflink)) else: if self._errors: log.warning(self._errors[0][1]) log.status.Print( 'Bulk create request finished with status message: [{}]'. format(self._status_message))
def _CreateFlow(self): try: return c_flow.NoBrowserHelperFlow.from_client_config( self._client_config, self._scopes, autogenerate_code_verifier=not properties.VALUES.auth. disable_code_verifier.GetBool()) except c_flow.LocalServerCreationError: log.error( 'Cannot start a local server to handle authorization ' 'redirection. Please run this command on a machine where ' 'gcloud can start a local server.') raise
def _LogKnownError(known_exc, command_path, print_error): """Logs the error message of the known exception.""" msg = '({0}) {1}'.format(console_attr.SafeText(command_path), console_attr.SafeText(known_exc)) if isinstance(known_exc, api_exceptions.HttpException): service_use_help = _BuildMissingServiceUsePermissionAdditionalHelp( known_exc) auth_scopes_help = _BuildMissingAuthScopesAdditionalHelp(known_exc) msg = service_use_help.Extend(msg) msg = auth_scopes_help.Extend(msg) log.debug(msg, exc_info=sys.exc_info()) if print_error: log.error(msg)
def _OnWebsocketError(self, client, error): if isinstance(error, websocket_exceptions.WebSocketBadStatusException ) and error.status_code == 503: log.error( 'The workstation does not have a server running on port {0}.'. format(self.port)) client.close() elif isinstance( error, websocket_exceptions.WebSocketConnectionClosedException): pass else: log.error('Received error from workstation: {0}'.format(error))
def OperationResponseHandler(self, response, args): if response.failed: if response.stderr: log.error(response.stderr) raise exceptions.Error('Command execution failed') if response.stderr: log.status.Print(response.stderr) if response.stdout: log.Print(response.stdout) return response.stdout
def LoginResponseHandler(response, list_clusters_only=False): """Handle Login Responses.""" if response.stdout: log.status.Print(response.stdout) if response.stderr: log.status.Print(response.stderr) if response.failed: log.error(messages.LOGIN_CONFIG_FAILED_MESSAGE.format(response.stderr)) return None if not list_clusters_only: log.status.Print(messages.LOGIN_CONFIG_SUCCESS_MESSAGE) return response.stdout
def UnidentifiedDirMatcher(path, stager): """Points out to the user that they need an app.yaml to deploy. Args: path: str, Unsanitized absolute path, may point to a directory or a file of any type. There is no guarantee that it exists. stager: staging.Stager, stager that will not be invoked. Returns: None """ del stager if os.path.isdir(path): log.error(NO_YAML_ERROR) return None
def TearDown(self): @retry.RetryOnException(max_retrials=DeployCustomTests.DELETE_RETRIALS) def _InnerTearDown(): self.ExecuteScript('gcloud', [ 'app', 'versions', 'delete', '--service', 'default', '-q', self.version, '--verbosity=debug' ], timeout=DeployCustomTests.DELETE_TIMEOUT) try: _InnerTearDown() except exec_utils.ExecutionError as e: log.error('Error {e} tearing down app version: {version}'.format( e=e, version=self.version))
def WaitForWaiter(waiter_resource, sleep=None, max_wait=None): """Wait for a waiter to finish. Args: waiter_resource: The waiter resource to wait for. sleep: The number of seconds to sleep between status checks. max_wait: The maximum number of seconds to wait before an error is raised. Returns: The last retrieved value of the Waiter. Raises: WaitTimeoutError: If the wait operation takes longer than the maximum wait time. """ sleep = sleep if sleep is not None else DEFAULT_WAITER_SLEEP max_wait = max_wait if max_wait is not None else MAX_WAITER_TIMEOUT waiter_client = WaiterClient() retryer = retry.Retryer(max_wait_ms=max_wait * 1000) request = (waiter_client.client.MESSAGES_MODULE. RuntimeconfigProjectsConfigsWaitersGetRequest( projectsId=waiter_resource.projectsId, configsId=waiter_resource.configsId, waitersId=waiter_resource.waitersId)) with progress_tracker.ProgressTracker( 'Waiting for waiter [{0}] to finish'.format( waiter_resource.Name())): try: result = retryer.RetryOnResult( waiter_client.Get, args=[request], sleep_ms=sleep * 1000, should_retry_if=lambda w, s: not w.done) except retry.WaitException: raise rtc_exceptions.WaitTimeoutError( 'Waiter [{0}] did not finish within {1} seconds.'.format( waiter_resource.Name(), max_wait)) if result.error is not None: if result.error.message is not None: message = 'Waiter [{0}] finished with an error: {1}'.format( waiter_resource.Name(), result.error.message) else: message = 'Waiter [{0}] finished with an error.'.format( waiter_resource.Name()) log.error(message) return result
def run_openssl_command(cls, openssl_executable, args, stdin=None): """Run the specified command, capturing and returning output as appropriate. Args: openssl_executable: The path to the openssl executable. args: The arguments to the openssl command to run. stdin: The input to the command. Returns: The output of the command. Raises: PersonalAuthError: If the call to openssl fails """ command = [openssl_executable] command.extend(args) stderr = None try: if getattr(subprocess, 'run', None): proc = subprocess.run(command, input=stdin, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False) stderr = proc.stderr.decode('utf-8').strip() # N.B. It would be better if we could simply call `subprocess.run` with # the `check` keyword arg set to true rather than manually calling # `check_returncode`. However, we want to capture the stderr when the # command fails, and the CalledProcessError type did not have a field # for the stderr until Python version 3.5. # # As such, we need to manually call `check_returncode` as long as we # are supporting Python versions prior to 3.5. proc.check_returncode() return proc.stdout else: p = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, _ = p.communicate(input=stdin) return stdout except Exception as ex: if stderr: log.error( 'OpenSSL command "%s" failed with error message "%s"', ' '.join(command), stderr) raise exceptions.PersonalAuthError( 'Failure running openssl command: "' + ' '.join(command) + '": ' + six.text_type(ex))