def Run(self, args): if util.IsPy2() and not args.IsSpecified('python_to_use'): log.error('Virtual env support requires Python 3.') raise exceptions.ExitCodeNoError(exit_code=3) if util.IsWindows(): log.error('Virtual env support not enabled on Windows.') raise exceptions.ExitCodeNoError(exit_code=4) if args.IsSpecified('python_to_use'): python = args.python_to_use else: try: python = execution_utils.GetPythonExecutable() except ValueError: log.error('Failed to resolve python to use for virtual env.') raise exceptions.ExitCodeNoError(exit_code=5) ve_dir = config.Paths().virtualenv_dir if util.VirtualEnvExists(ve_dir): log.error('Virtual env setup {} already exists.'.format(ve_dir)) raise exceptions.ExitCodeNoError(exit_code=5) succeeded_making_venv = False try: log.status.Print('Creating virtualenv...') # python -m venv is preferred as it aligns the python used with # the current in used Python. ec = execution_utils.Exec([python, '-m', 'venv', ve_dir], no_exit=True, err_func=log.file_only_logger.debug, out_func=log.file_only_logger.debug) if ec != 0: # Many linux vendors havea a history of having a broken python-venv # package that will not work correctly, debian for example. If -m venv # failed above we will attempt to use the virtualenv tool if it is # installed and exists in $PATH. ec = execution_utils.Exec( ['virtualenv', '-q', '-p', python, ve_dir], no_exit=True) if ec != 0: log.error('Virtual env setup failed.') raise exceptions.ExitCodeNoError(exit_code=ec) log.status.Print('Installing modules...') install_modules = [ '{}/bin/pip3'.format(ve_dir), 'install', '--log', '{}/install_module.log'.format(ve_dir), '-q', '--disable-pip-version-check' ] install_modules.extend(util.MODULES) ec = execution_utils.Exec(install_modules, no_exit=True) if ec == 0: # prevent the cleanup that occurs in finally block succeeded_making_venv = True else: log.error('Virtual env setup failed.') raise exceptions.ExitCodeNoError(exit_code=ec) finally: # If something went wrong we clean up any partial created ve_dir if not succeeded_making_venv: if util.VirtualEnvExists(ve_dir): files.RmTree(ve_dir)
def testPythonArgComplete(self): gcloud_py_dir = os.path.dirname(config.GcloudPath()) compdir = os.path.dirname(gcloud_py_dir) prog_dir = os.path.dirname(__file__) testfile = os.path.join(prog_dir, 'completion_test.sh') exitval = execution_utils.Exec([testfile, compdir], no_exit=True) self.assertTrue(exitval == 0) # Testing /bin/zsh requires running in a local environment that has zsh # installed. if os.path.isfile('/bin/zsh') and os.access('/bin/zsh', os.X_OK): exitval = execution_utils.Exec([testfile, '--shell=/bin/zsh', compdir], no_exit=True) self.assertTrue(exitval == 0)
def _ProvisionClientCert(self, cmd, cert_path): """Executes certificate provider to obtain client certificate and keys.""" try: # monkey-patch command line args to get password protected cert pass_arg = '--with_passphrase' if '--print_certificate' in cmd and pass_arg not in cmd: cmd.append(pass_arg) cert_pem_io = io.StringIO() ret_val = execution_utils.Exec(cmd, no_exit=True, out_func=cert_pem_io.write, err_func=log.file_only_logger.debug) if ret_val: raise CertProviderUnexpectedExit( 'certificate provider exited with error') sections = _SplitPemIntoSections(cert_pem_io.getvalue()) with files.FileWriter(cert_path) as f: f.write(sections['CERTIFICATE']) f.write(sections['ENCRYPTED PRIVATE KEY']) self.client_cert_password = sections['PASSPHRASE'].splitlines()[1] except (files.Error, execution_utils.PermissionError, execution_utils.InvalidCommandError, CertProviderUnexpectedExit) as e: raise CertProvisionException(e) except KeyError as e: raise CertProvisionException( 'Invalid output format from certificate provider, no %s' % e)
def Execute(self, scenario_context): original_data = scenario_context.resource_ref_resolver.Resolve( self._original_data) original_data.setdefault('expect_exit', {}) exit_event = events.ExitEvent.FromData(original_data) stdout_event = events.StdoutEvent.FromData(original_data) stderr_event = events.StderrEvent.FromData(original_data) stdout = io.StringIO() stderr = io.StringIO() return_code = execution_utils.Exec(self._args, no_exit=True, in_str=self._stdin, out_func=stdout.write, err_func=stderr.write) action_location = updates.Context(self._original_data, None, None).Location() try: with assertions.FailureCollector( scenario_context.update_modes, spec_name=scenario_context.spec_name, action_location=action_location, execution_mode=scenario_context.execution_mode.name ) as failures: failures.AddAll(exit_event.HandleReturnCode(return_code)) failures.AddAll(stdout_event.Handle(stdout.getvalue())) failures.AddAll(stderr_event.Handle(stderr.getvalue())) finally: if scenario_context.update_modes: scenario_context.RewriteScenario()
def _RunKubectlDiff(self, args, stdin=None): """Runs a kubectl diff command with the specified args. Args: args: command line arguments to pass to kubectl stdin: text to be passed to kubectl via stdin Returns: The contents of stdout if the return code is 1, stderr (or a fabricated error if stderr is empty) otherwise """ cmd = [c_util.CheckKubectlInstalled()] if self.context: cmd.extend(['--context', self.context]) if self.kubeconfig: cmd.extend(['--kubeconfig', self.kubeconfig]) cmd.extend(['--request-timeout', self.kubectl_timeout]) cmd.extend(args) out = io.StringIO() err = io.StringIO() returncode = execution_utils.Exec(cmd, no_exit=True, out_func=out.write, err_func=err.write, in_str=stdin) # kubectl diff return is different with other CLI. # Exit status: 0 No differences were found. 1 Differences were found. # >1 Kubectl or diff failed with an error. return out.getvalue() if returncode == 1 else None, err.getvalue( ) if returncode > 1 else None
def Run(self, staging_area, descriptor, app_dir, explicit_appyaml=None): """Invokes a staging command with a given <service>.yaml and temp dir. Args: staging_area: str, path to the staging area. descriptor: str, path to the unstaged <service>.yaml or appengine-web.xml app_dir: str, path to the unstaged app directory explicit_appyaml: str or None, the app.yaml location to used for deployment. Returns: str, the path to the staged directory or None if staging was not required. Raises: StagingCommandFailedError: if the staging command process exited non-zero. """ staging_dir = tempfile.mkdtemp(dir=staging_area) args = self.GetArgs(descriptor, app_dir, staging_dir) log.info('Executing staging command: [{0}]\n\n'.format(' '.join(args))) out = io.StringIO() err = io.StringIO() return_code = execution_utils.Exec( args, no_exit=True, out_func=out.write, err_func=err.write) message = _STAGING_COMMAND_OUTPUT_TEMPLATE.format( out=out.getvalue(), err=err.getvalue()) message = message.replace('\r\n', '\n') log.info(message) if return_code: raise StagingCommandFailedError(args, return_code, message) # Optionally use the custom app yaml if available: if explicit_appyaml: shutil.copyfile(explicit_appyaml, os.path.join(staging_dir, 'app.yaml')) return staging_dir
def _ExecuteTool(args): """Executes a new tool with the given args, plus the args from the cmdline. Args: args: [str], The args of the command to execute. """ execution_utils.Exec(args + sys.argv[1:], env=_GetToolEnv())
def _GitInit(self): def _SwallowOutput(_): pass execution_utils.Exec(['git', 'init'], no_exit=True, out_func=_SwallowOutput)
def RunGsutilCommand(command_name, command_args=None, run_concurrent=False): """Runs the specified gsutil command and returns the command's exit code. This is more reliable than storage_api.StorageClient.CopyFilesToGcs especially for large files. Args: command_name: The gsutil command to run. command_args: List of arguments to pass to the command. run_concurrent: Whether concurrent uploads should be enabled while running the command. Returns: The exit code of the call to the gsutil command. """ command_path = _GetGsutilPath() args = ['-m', command_name] if run_concurrent else [command_name] if command_args is not None: args += command_args if platforms.OperatingSystem.Current( ) == platforms.OperatingSystem.WINDOWS: gsutil_args = execution_utils.ArgsForCMDTool(command_path + '.cmd', *args) else: gsutil_args = execution_utils.ArgsForExecutableTool( command_path, *args) log.debug('Running command: [{args}]]'.format(args=' '.join(gsutil_args))) return execution_utils.Exec(gsutil_args, no_exit=True, out_func=log.file_only_logger.debug, err_func=log.file_only_logger.debug)
def _RunGcloud(args): """Runs a gcloud command. Args: args: command line arguments to pass to gcloud Returns: The contents of stdout if the return code is 0, stderr (or a fabricated error if stderr is empty) otherwise """ cmd = execution_utils.ArgsForGcloud() cmd.extend(args) out = io.StringIO() err = io.StringIO() env = _GetEnvs() returncode = execution_utils.Exec(cmd, no_exit=True, out_func=out.write, err_func=err.write, in_str=None, env=env) if returncode != 0 and not err.getvalue(): err.write('gcloud exited with return code {}'.format(returncode)) return out.getvalue() if returncode == 0 else None, err.getvalue( ) if returncode != 0 else None
def RunGsutilCommand(command_name, command_arg_str, run_concurrent=False): """Runs the specified gsutil command and returns the command's exit code. Args: command_name: The gsutil command to run. command_arg_str: Arguments to pass to the command. run_concurrent: Whether concurrent uploads should be enabled while running the command. Returns: The exit code of the call to the gsutil command. """ command_path = _GetGsutilPath() if run_concurrent: command_args = ['-m', command_name] else: command_args = [command_name] command_args += command_arg_str.split(' ') if platforms.OperatingSystem.Current( ) == platforms.OperatingSystem.WINDOWS: gsutil_args = execution_utils.ArgsForCMDTool(command_path + '.cmd', *command_args) else: gsutil_args = execution_utils.ArgsForExecutableTool( command_path, *command_args) log.debug('Running command: [{args}]]'.format(args=' '.join(gsutil_args))) return execution_utils.Exec(gsutil_args, no_exit=True, out_func=log.file_only_logger.debug, err_func=log.file_only_logger.debug)
def _StageUsingGivenCommand(command_path, service_yaml): """Invokes a staging command with a given <service>.yaml and temp dir. This is a context manager because the temporary staging directory should always be deleted, independent of potential errors. Args: command_path: str, path to the staging command service_yaml: str, path to the unstaged <service>.yaml Yields: str, the path to the staged directory. Raises: StagingCommandFailedError: if the staging command process exited non-zero. """ with files.TemporaryDirectory() as temp_directory: args = [command_path, service_yaml, temp_directory] log.info('Executing staging command: [{0}]\n\n'.format(' '.join(args))) out = cStringIO.StringIO() err = cStringIO.StringIO() return_code = execution_utils.Exec(args, no_exit=True, out_func=out.write, err_func=err.write) message = _STAGING_COMMAND_OUTPUT_TEMPLATE.format(out=out.getvalue(), err=err.getvalue()) log.info(message) if return_code: raise StagingCommandFailedError(args, return_code, message) yield temp_directory
def Run(self, staging_area, descriptor, app_dir): """Invokes a staging command with a given <service>.yaml and temp dir. Args: staging_area: str, path to the staging area. descriptor: str, path to the unstaged <service>.yaml or appengine-web.xml app_dir: str, path to the unstaged app directory Returns: str, the path to the staged directory or None if staging was not required. Raises: StagingCommandFailedError: if the staging command process exited non-zero. """ staging_dir = tempfile.mkdtemp(dir=staging_area) args = self.GetArgs(descriptor, app_dir, staging_dir) log.info('Executing staging command: [{0}]\n\n'.format(' '.join(args))) out = cStringIO.StringIO() err = cStringIO.StringIO() return_code = execution_utils.Exec(args, no_exit=True, out_func=out.write, err_func=err.write) message = _STAGING_COMMAND_OUTPUT_TEMPLATE.format(out=out.getvalue(), err=err.getvalue()) log.info(message) if return_code: raise StagingCommandFailedError(args, return_code, message) return staging_dir
def Run(self, env=None, force_connect=False): """Run the SSH command using the given environment. Args: env: Environment, environment to run in (or current if None). force_connect: bool, whether to inject 'y' into the prompts for `plink`, which is insecure and not recommended. It serves legacy compatibility purposes only. Raises: MissingCommandError: If SSH command(s) not found. CommandError: SSH command failed (not to be confused with the eventual failure of the remote command). Returns: int, The exit code of the remote command, forwarded from the client. """ env = env or Environment.Current() args = self.Build(env) log.debug('Running command [{}].'.format(' '.join(args))) # PuTTY and friends always ask on fingerprint mismatch in_str = 'y\n' if env.suite is Suite.PUTTY and force_connect else None status = execution_utils.Exec(args, no_exit=True, in_str=in_str) if status == env.ssh_exit_code: raise CommandError(args[0], return_code=status) return status
def testExecPipeErr(self): execution_utils.Exec(os.path.join(self.scripts_dir, self._SCRIPT), in_str='test Ṳᾔḯ¢◎ⅾℯ input\n', err_func=log.err.write) self.exit_mock.assert_called_once_with(1) self.AssertOutputNotContains('test Ṳᾔḯ¢◎ⅾℯ output') self.AssertErrContains('test Ṳᾔḯ¢◎ⅾℯ error')
def RunKubectl(args): """Runs a kubectl command with the cluster referenced by this client. Args: args: command line arguments to pass to kubectl Returns: The contents of stdout if the return code is 0, stderr (or a fabricated error if stderr is empty) otherwise """ cmd = [util.CheckKubectlInstalled()] cmd.extend(args) out = io.StringIO() err = io.StringIO() env = _GetEnvs() returncode = execution_utils.Exec(cmd, no_exit=True, out_func=out.write, err_func=err.write, in_str=None, env=env) if returncode != 0 and not err.getvalue(): err.write('kubectl exited with return code {}'.format(returncode)) return out.getvalue() if returncode == 0 else None, err.getvalue( ) if returncode != 0 else None
def _RunKubectl(self, args, stdin=None): """Runs a kubectl command with the cluster referenced by this client. Args: args: command line arguments to pass to kubectl stdin: text to be passed to kubectl via stdin Returns: The contents of stdout if the return code is 0, stderr (or a fabricated error if stderr is empty) otherwise """ cmd = [c_util.CheckKubectlInstalled()] if self.context: cmd.extend(['--context', self.context]) if self.kubeconfig: cmd.extend(['--kubeconfig', self.kubeconfig]) cmd.extend(['--request-timeout', self.kubectl_timeout]) cmd.extend(args) out = io.StringIO() err = io.StringIO() returncode = execution_utils.Exec(cmd, no_exit=True, out_func=out.write, err_func=err.write, in_str=stdin) if returncode != 0 and not err.getvalue(): err.write('kubectl exited with return code {}'.format(returncode)) return out.getvalue() if returncode == 0 else None, err.getvalue( ) if returncode != 0 else None
def Run(self, env=None, force_connect=False): """Run the SCP command using the given environment. Args: env: Environment, environment to run in (or current if None). force_connect: bool, whether to inject 'y' into the prompts for `pscp`, which is insecure and not recommended. It serves legacy compatibility purposes only. Raises: InvalidConfigurationError: The source/destination configuration is invalid. MissingCommandError: If SCP command(s) not found. CommandError: SCP command failed to copy the file(s). """ env = env or Environment.Current() args = self.Build(env) log.debug('Running command [{}].'.format(' '.join(args))) # pscp asks on (1) first connection and (2) fingerprint mismatch. # This ensures pscp will always allow the connection. # TODO(b/35355795): Work out a better solution for PuTTY. in_str = 'y\n' if env.suite is Suite.PUTTY and force_connect else None status = execution_utils.Exec(args, no_exit=True, in_str=in_str) if status: raise CommandError(args[0], return_code=status)
def _RunGsutilCommand(command_name, command_args, run_concurrent=False): """Runs the specified gsutil command and returns the command's exit code. Args: command_name: The gsutil command to run. command_args: List of arguments to pass to the command. run_concurrent: Whether concurrent uploads should be enabled while running the command. Returns: The exit code of the call to the gsutil command. """ gsutil_path = _GetGsutilPath() gsutil_args = [] if run_concurrent: gsutil_args += ['-m'] gsutil_args += [command_name] gsutil_args += command_args env = None gsutil_cmd = execution_utils.ArgsForExecutableTool(gsutil_path, *gsutil_args) log.debug('Running command: [{args}], Env: [{env}]'.format( args=' '.join(gsutil_cmd), env=env)) return execution_utils.Exec(gsutil_cmd, no_exit=True, env=env)
def MakeProcess(module_name, package_root, args=None, cluster=None, task_type=None, index=None, **extra_popen_args): """Make a Popen object that runs the module, with the correct env. If task_type is 'master' instead replaces the current process with the subprocess via execution_utils.Exec Args: module_name: str. Name of the module to run, e.g. trainer.task package_root: str. Absolute path to the package root for the module. used as CWD for the subprocess. args: [str]. Additional user args. Any relative paths will not work. cluster: dict. Cluster configuration dictionary. Suitable for passing to tf.train.ClusterSpec. task_type: str. Task type of this process. Only relevant if cluster is specified. index: int. Task index of this process. **extra_popen_args: extra args passed to Popen. Used for testing. Returns: a subprocess.Popen object corresponding to the subprocesses or an int corresponding to the return value of the subprocess (if task_type is 'master') """ if args is None: args = [] python = execution_utils.GetPythonExecutable() cmd = [python, '-m', module_name] + args config = { 'job': {'job_name': module_name, 'args': args}, 'task': {'type': task_type, 'index': index} if cluster else {}, 'cluster': cluster or {}, 'environment': 'cloud' } log.info(('launching training process:\n' 'command: {cmd}\n config: {config}').format( cmd=' '.join(cmd), config=json.dumps(config, indent=2, sort_keys=True))) env = os.environ.copy() # the tf_config environment variable is used to pass the tensorflow # configuration options to the training module. the module specific # arguments are passed as comand line arguments. env['TF_CONFIG'] = json.dumps(config) if task_type == 'master': return execution_utils.Exec( cmd, env=env, no_exit=True, cwd=package_root, **extra_popen_args) else: task = subprocess.Popen( cmd, env=env, cwd=package_root, **extra_popen_args ) atexit.register(execution_utils.KillSubprocess, task) return task
def testExecPipeIn(self): execution_utils.Exec(os.path.join(self.scripts_dir, self._SCRIPT), in_str='test Ṳᾔḯ¢◎ⅾℯ input\n') self.exit_mock.assert_called_once_with(1) # Has no output self.AssertOutputNotContains('test Ṳᾔḯ¢◎ⅾℯ input') self.AssertOutputNotContains('test Ṳᾔḯ¢◎ⅾℯ output') self.AssertErrNotContains('test Ṳᾔḯ¢◎ⅾℯ error')
def _GitAddDryRun(self): output = io.StringIO() execution_utils.Exec(['git', 'add', '--dry-run', '.'], no_exit=True, out_func=output.write) text = output.getvalue() if not text: return [] text = text[len('add \''):-len('\'\n')] return text.split('\'\nadd \'')
def testExec_NoExit(self): ret_val = execution_utils.Exec(os.path.join(self.scripts_dir, self._SCRIPT), in_str='test Ṳᾔḯ¢◎ⅾℯ input\n', no_exit=True) self.assertEqual(ret_val, 1) self.AssertOutputNotContains('test Ṳᾔḯ¢◎ⅾℯ output') self.AssertLogNotContains('test Ṳᾔḯ¢◎ⅾℯ output') self.assertFalse(self.exit_mock.called)
def _ExecuteTool(args, **extra_popen_kwargs): """Executes a new tool with the given args, plus the args from the cmdline. Args: args: [str], The args of the command to execute. **extra_popen_kwargs: [dict], kwargs to be unpacked in Popen call for tool. """ execution_utils.Exec( args + sys.argv[1:], env=_GetToolEnv(), **extra_popen_kwargs)
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 _ExecuteBinary(cmd, in_str=None): output_value = io.StringIO() error_value = io.StringIO() exit_code = execution_utils.Exec(args=cmd, no_exit=True, in_str=in_str, out_func=output_value.write, err_func=error_value.write) return exit_code, output_value.getvalue(), error_value.getvalue()
def RunExec(self, args, env=None, no_exit=False, out_func=None, err_func=None, in_str=None, **extra_popen_kwargs): return execution_utils.Exec(args, env, no_exit, out_func, err_func, in_str, **extra_popen_kwargs)
def _RunSetupTools(package_root, setup_py_path, output_dir): """Executes the setuptools `sdist` command. Specifically, runs `python setup.py sdist` (with the full path to `setup.py` given by setup_py_path) with arguments to put the final output in output_dir and all possible temporary files in a temporary directory. package_root is used as the working directory. package_root must be writable, or setuptools will fail (there are temporary files from setuptools that get put in the CWD). Args: package_root: str, the directory containing the package (that is, the *parent* of the package itself). setup_py_path: str, the path to the `setup.py` file to execute. output_dir: str, path to a directory in which the built packages should be created. Returns: list of str, the full paths to the generated packages. Raises: SysExecutableMissingError: if sys.executable is None RuntimeError: if the execution of setuptools exited non-zero. """ if not sys.executable: raise SysExecutableMissingError() # We could just include the 'sdist' command and its flags here, but we want # to avoid leaving artifacts in the setup directory. That's what the # 'egg_info' and 'build' options do (these are both invoked as subcommands # of 'sdist'). # Unfortunately, there doesn't seem to be any easy way to move *all* # temporary files out of the current directory, so we'll fail here if we # can't write to it. with files.TemporaryDirectory() as temp_dir: args = [ sys.executable, setup_py_path, 'egg_info', '--egg-base', temp_dir, 'build', '--build-base', temp_dir, '--build-temp', temp_dir, 'sdist', '--dist-dir', output_dir ] out = cStringIO.StringIO() if execution_utils.Exec(args, no_exit=True, out_func=out.write, err_func=out.write, cwd=package_root): raise RuntimeError(out.getvalue()) local_paths = [ os.path.join(output_dir, rel_file) for rel_file in os.listdir(output_dir) ] log.debug('Python packaging resulted in [%s]', ', '.join(local_paths)) return local_paths
def _Execute(self, cmd, stdin=None, env=None, **kwargs): """Execute binary and return operation result. Will parse args from kwargs into a list of args to pass to underlying binary and then attempt to execute it. Will use configured stdout, stderr and failure handlers for this operation if configured or module defaults. Args: cmd: [str], command to be executed with args stdin: str, data to send to binary on stdin env: {str, str}, environment vars to send to binary. **kwargs: mapping of additional arguments to pass to the underlying executor. Returns: OperationResult: execution result for this invocation of the binary. Raises: ArgumentError, if there is an error parsing the supplied arguments. BinaryOperationError, if there is an error executing the binary. """ op_context = { 'env': env, 'stdin': stdin, 'exec_dir': kwargs.get('execution_dir') } result_holder = self.OperationResult(command_str=cmd, execution_context=op_context) std_out_handler = (self.std_out_handler or DefaultStdOutHandler(result_holder)) std_err_handler = (self.std_out_handler or DefaultStdErrHandler(result_holder)) failure_handler = (self.set_failure_status or DefaultFailureHandler) short_cmd_name = os.path.basename(cmd[0]) # useful for error messages try: working_dir = kwargs.get('execution_dir') if working_dir and not os.path.isdir(working_dir): raise InvalidWorkingDirectoryError(short_cmd_name, working_dir) exit_code = exec_utils.Exec(args=cmd, no_exit=True, out_func=std_out_handler, err_func=std_err_handler, in_str=stdin, cwd=working_dir, env=env) except (exec_utils.PermissionError, exec_utils.InvalidCommandError) as e: raise ExecutionError(short_cmd_name, e) result_holder.exit_code = exit_code failure_handler(result_holder, kwargs.get('show_exec_error', False)) return result_holder
def _RunGsutilCommand(gsutil_args): """Run a gsutil command. Args: gsutil_args: The list of arguments to pass to gsutil. Returns: The exit code of the call to the gsutil command. """ args = execution_utils.ArgsForBinaryTool(_GetGsutilPath(), *gsutil_args) return execution_utils.Exec(args, no_exit=True)