def which(program, paths): def is_exe(fpath): return os.path.exists(fpath) and os.access(fpath, os.X_OK) for path in paths: if not os.path.isdir(path): continue exe_file = os.path.join(u(path, fs_encoding), program) if is_exe(exe_file): return file_quote(exe_file) return None
def start(self, cb=None): def which(program, paths): def is_exe(fpath): return os.path.exists(fpath) and os.access(fpath, os.X_OK) for path in paths: if not os.path.isdir(path): continue exe_file = os.path.join(u(path, fs_encoding), program) if is_exe(exe_file): return file_quote(exe_file) return None def convert_environment_variables(env): """ This function is use to convert environment variable to string because environment variable must be string in popen :param env: Dict of environment variable :return: Encoded environment variable as string """ encoding = sys.getfilesystemencoding() if encoding is None or encoding == 'ascii': encoding = 'utf-8' temp_env = dict() for key, value in env.items(): if not isinstance(key, str): key = key.encode(encoding) if not isinstance(value, str): value = value.encode(encoding) temp_env[key] = value return temp_env if self.stime is not None: if self.etime is None: raise Exception(_('The process has already been started.')) raise Exception( _('The process has already finished and cannot be restarted.')) executor = file_quote( os.path.join(os.path.dirname(u(__file__)), u'process_executor.py')) paths = os.environ['PATH'].split(os.pathsep) interpreter = None if os.name == 'nt': paths.insert(0, os.path.join(u(sys.prefix), u'Scripts')) paths.insert(0, u(sys.prefix)) interpreter = which(u'pythonw.exe', paths) if interpreter is None: interpreter = which(u'python.exe', paths) if interpreter is None and current_app.PGADMIN_RUNTIME: # We've faced an issue with Windows 2008 R2 (x86) regarding, # not honouring the environment variables set under the Qt # (e.g. runtime), and also setting PYTHONHOME same as # sys.executable (i.e. pgAdmin4.exe). # # As we know, we're running it under the runtime, we can assume # that 'venv' directory will be available outside of 'bin' # directory. # # We would try out luck to find python executable based on that # assumptions. bin_path = os.path.dirname(sys.executable) venv = os.path.realpath(os.path.join(bin_path, u'..\\venv')) interpreter = which(u'pythonw.exe', [venv]) if interpreter is None: interpreter = which(u'pythonw.exe', [venv]) if interpreter is not None: # Our assumptions are proven right. # Let's append the 'bin' directory to the PATH environment # variable. And, also set PYTHONHOME environment variable # to 'venv' directory. os.environ['PATH'] = bin_path + ';' + os.environ['PATH'] os.environ['PYTHONHOME'] = venv else: # Let's not use sys.prefix in runtime. # 'sys.prefix' is not identified on *nix systems for some unknown # reason, while running under the runtime. # We're already adding '<installation path>/pgAdmin 4/venv/bin' # directory in the PATH environment variable. Hence - it will # anyway be the redundant value in paths. if not current_app.PGADMIN_RUNTIME: paths.insert(0, os.path.join(u(sys.prefix), u'bin')) interpreter = which(u'python', paths) p = None cmd = [ interpreter if interpreter is not None else 'python', executor, self.cmd ] cmd.extend(self.args) if os.name == 'nt' and IS_PY2: command = [] for c in cmd: command.append( c.encode('utf-8') if isinstance(c, unicode) else str(c)) current_app.logger.info( u"Executing the process executor with the arguments: %s", ''.join(command)) cmd = command else: current_app.logger.info( u"Executing the process executor with the arguments: %s", str(cmd)) # Make a copy of environment, and add new variables to support env = os.environ.copy() env['PROCID'] = self.id env['OUTDIR'] = self.log_dir env['PGA_BGP_FOREGROUND'] = "1" if cb is not None: cb(env) if IS_PY2: # We need environment variables & values in string env = convert_environment_variables(env) if os.name == 'nt': DETACHED_PROCESS = 0x00000008 from subprocess import CREATE_NEW_PROCESS_GROUP # We need to redirect the standard input, standard output, and # standard error to devnull in order to allow it start in detached # mode on stdout = os.devnull stderr = stdout stdin = open(os.devnull, "r") stdout = open(stdout, "a") stderr = open(stderr, "a") p = Popen(cmd, close_fds=False, env=env, stdout=stdout.fileno(), stderr=stderr.fileno(), stdin=stdin.fileno(), creationflags=(CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS)) else: def preexec_function(): import signal # Detaching from the parent process group os.setpgrp() # Explicitly ignoring signals in the child process signal.signal(signal.SIGINT, signal.SIG_IGN) p = Popen(cmd, close_fds=True, stdout=None, stderr=None, stdin=None, preexec_fn=preexec_function, env=env) self.ecode = p.poll() # Execution completed immediately. # Process executor cannot update the status, if it was not able to # start properly. if self.ecode is not None and self.ecode != 0: # There is no way to find out the error message from this process # as standard output, and standard error were redirected to # devnull. p = Process.query.filter_by(pid=self.id, user_id=current_user.id).first() p.start_time = p.end_time = get_current_time() if not p.exit_code: p.exit_code = self.ecode db.session.commit()
if scheme: environ["wsgi.url_scheme"] = scheme return self.app(environ, start_response) ########################################################################## # Sanity checks ########################################################################## config.SETTINGS_SCHEMA_VERSION = SCHEMA_VERSION # Check if the database exists. If it does not, create it. if not os.path.isfile(config.SQLITE_PATH): setup_py = os.path.join( os.path.dirname(os.path.realpath(u(__file__, fs_encoding))), u'setup.py') exec(open(file_quote(setup_py), 'r').read()) ########################################################################## # Create the app and configure it. It is created outside main so that # it can be imported ########################################################################## app = create_app() app.debug = False if config.SERVER_MODE: app.wsgi_app = ReverseProxied(app.wsgi_app) # Authentication sources app.PGADMIN_DEFAULT_AUTH_SOURCE = 'internal' app.PGADMIN_SUPPORTED_AUTH_SOURCE = ['internal', 'ldap'] if len(config.AUTHENTICATION_SOURCES) > 0: app.PGADMIN_EXTERNAL_AUTH_SOURCE = config.AUTHENTICATION_SOURCES[0]
def start(self, cb=None): self.check_start_end_time() executor = file_quote( os.path.join(os.path.dirname(u_encode(__file__)), 'process_executor.py')) paths = os.environ['PATH'].split(os.pathsep) current_app.logger.info("Process Executor: Operating System Path %s", str(paths)) interpreter = self.get_interpreter(paths) p = None cmd = [ interpreter if interpreter is not None else 'python', executor, self.cmd ] cmd.extend(self.args) current_app.logger.info( "Executing the process executor with the arguments: %s", str(cmd)) # Make a copy of environment, and add new variables to support env = os.environ.copy() env['PROCID'] = self.id env['OUTDIR'] = self.log_dir env['PGA_BGP_FOREGROUND'] = "1" if self.env: env.update(self.env) if cb is not None: cb(env) if os.name == 'nt': DETACHED_PROCESS = 0x00000008 from subprocess import CREATE_NEW_PROCESS_GROUP # We need to redirect the standard input, standard output, and # standard error to devnull in order to allow it start in detached # mode on stdout = os.devnull stderr = stdout stdin = open(os.devnull, "r") stdout = open(stdout, "a") stderr = open(stderr, "a") p = Popen(cmd, close_fds=False, env=env, stdout=stdout.fileno(), stderr=stderr.fileno(), stdin=stdin.fileno(), creationflags=(CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS)) else: # if in debug mode, wait for process to complete and # get the stdout and stderr of popen. if config.CONSOLE_LOG_LEVEL <= logging.DEBUG: output, error = self.get_process_output(cmd, env) else: p = Popen(cmd, close_fds=True, stdout=None, stderr=None, stdin=None, preexec_fn=self.preexec_function, env=env) self.ecode = p.poll() # Execution completed immediately. # Process executor cannot update the status, if it was not able to # start properly. if self.ecode is not None and self.ecode != 0: # There is no way to find out the error message from this process # as standard output, and standard error were redirected to # devnull. p = Process.query.filter_by(pid=self.id, user_id=current_user.id).first() p.start_time = p.end_time = get_current_time() if not p.exit_code: p.exit_code = self.ecode p.process_state = PROCESS_FINISHED db.session.commit() else: # Update the process state to "Started" p = Process.query.filter_by(pid=self.id, user_id=current_user.id).first() p.process_state = PROCESS_STARTED db.session.commit()
def start(self, cb=None): def which(program, paths): def is_exe(fpath): return os.path.exists(fpath) and os.access(fpath, os.X_OK) for path in paths: if not os.path.isdir(path): continue exe_file = os.path.join(u_encode(path, fs_encoding), program) if is_exe(exe_file): return file_quote(exe_file) return None if self.stime is not None: if self.etime is None: raise RuntimeError(_('The process has already been started.')) raise RuntimeError( _('The process has already finished and cannot be restarted.') ) executor = file_quote(os.path.join( os.path.dirname(u_encode(__file__)), u'process_executor.py' )) paths = os.environ['PATH'].split(os.pathsep) interpreter = None current_app.logger.info( u"Process Executor: Operating System Path %s", str(paths) ) if os.name == 'nt': paths.insert(0, os.path.join(u_encode(sys.prefix), u'Scripts')) paths.insert(0, u_encode(sys.prefix)) interpreter = which(u'pythonw.exe', paths) if interpreter is None: interpreter = which(u'python.exe', paths) current_app.logger.info( u"Process Executor: Interpreter value in path: %s", str(interpreter) ) if interpreter is None and current_app.PGADMIN_RUNTIME: # We've faced an issue with Windows 2008 R2 (x86) regarding, # not honouring the environment variables set under the Qt # (e.g. runtime), and also setting PYTHONHOME same as # sys.executable (i.e. pgAdmin4.exe). # # As we know, we're running it under the runtime, we can assume # that 'venv' directory will be available outside of 'bin' # directory. # # We would try out luck to find python executable based on that # assumptions. bin_path = os.path.dirname(sys.executable) venv = os.path.realpath( os.path.join(bin_path, u'..\\venv') ) interpreter = which(u'pythonw.exe', [venv]) if interpreter is None: interpreter = which(u'python.exe', [venv]) current_app.logger.info( u"Process Executor: Interpreter value in virtual " u"environment: %s", str(interpreter) ) if interpreter is not None: # Our assumptions are proven right. # Let's append the 'bin' directory to the PATH environment # variable. And, also set PYTHONHOME environment variable # to 'venv' directory. os.environ['PATH'] = bin_path + ';' + os.environ['PATH'] os.environ['PYTHONHOME'] = venv else: # Let's not use sys.prefix in runtime. # 'sys.prefix' is not identified on *nix systems for some unknown # reason, while running under the runtime. # We're already adding '<installation path>/pgAdmin 4/venv/bin' # directory in the PATH environment variable. Hence - it will # anyway be the redundant value in paths. if not current_app.PGADMIN_RUNTIME: paths.insert(0, os.path.join(u_encode(sys.prefix), u'bin')) python_binary_name = 'python{0}'.format(sys.version_info[0]) interpreter = which(u_encode(python_binary_name), paths) p = None cmd = [ interpreter if interpreter is not None else 'python', executor, self.cmd ] cmd.extend(self.args) current_app.logger.info( u"Executing the process executor with the arguments: %s", str(cmd) ) # Make a copy of environment, and add new variables to support env = os.environ.copy() env['PROCID'] = self.id env['OUTDIR'] = self.log_dir env['PGA_BGP_FOREGROUND'] = "1" if self.env: env.update(self.env) if cb is not None: cb(env) if os.name == 'nt': DETACHED_PROCESS = 0x00000008 from subprocess import CREATE_NEW_PROCESS_GROUP # We need to redirect the standard input, standard output, and # standard error to devnull in order to allow it start in detached # mode on stdout = os.devnull stderr = stdout stdin = open(os.devnull, "r") stdout = open(stdout, "a") stderr = open(stderr, "a") p = Popen( cmd, close_fds=False, env=env, stdout=stdout.fileno(), stderr=stderr.fileno(), stdin=stdin.fileno(), creationflags=(CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS) ) else: def preexec_function(): import signal # Detaching from the parent process group os.setpgrp() # Explicitly ignoring signals in the child process signal.signal(signal.SIGINT, signal.SIG_IGN) # if in debug mode, wait for process to complete and # get the stdout and stderr of popen. if config.CONSOLE_LOG_LEVEL <= logging.DEBUG: p = Popen( cmd, close_fds=True, stdout=PIPE, stderr=PIPE, stdin=None, preexec_fn=preexec_function, env=env ) output, errors = p.communicate() output = output.decode() \ if hasattr(output, 'decode') else output errors = errors.decode() \ if hasattr(errors, 'decode') else errors current_app.logger.debug( 'Process Watcher Out:{0}'.format(output)) current_app.logger.debug( 'Process Watcher Err:{0}'.format(errors)) else: p = Popen( cmd, close_fds=True, stdout=None, stderr=None, stdin=None, preexec_fn=preexec_function, env=env ) self.ecode = p.poll() # Execution completed immediately. # Process executor cannot update the status, if it was not able to # start properly. if self.ecode is not None and self.ecode != 0: # There is no way to find out the error message from this process # as standard output, and standard error were redirected to # devnull. p = Process.query.filter_by( pid=self.id, user_id=current_user.id ).first() p.start_time = p.end_time = get_current_time() if not p.exit_code: p.exit_code = self.ecode p.process_state = PROCESS_FINISHED db.session.commit() else: # Update the process state to "Started" p = Process.query.filter_by( pid=self.id, user_id=current_user.id ).first() p.process_state = PROCESS_STARTED db.session.commit()
def detached_process(p_cmd, p_ctime=None, report_file=None, stdin_str=None, is_local=False, process_type=None, exclude_str=None): executor = file_quote(os.path.join( os.path.dirname(u(__file__)), u'process_executor.py' )) if is_local: executor = file_quote(os.path.join( os.path.dirname(u(__file__)), u'local_process_executor.py' )) paths = sys.path[:] interpreter = None if os.name == 'nt': paths.insert(0, os.path.join(u(sys.prefix), u'Scripts')) paths.insert(0, u(sys.prefix)) interpreter = which(u'pythonw.exe', paths) if interpreter is None: interpreter = which(u'python.exe', paths) else: paths.insert(0, os.path.join(u(sys.prefix), u'bin')) interpreter = which(u'python', paths) p = None cmd = [ interpreter if interpreter is not None else 'python', executor, p_cmd ] #cmd.extend(self.args) if not p_ctime: ctime = get_current_time(format='%y%m%d%H%M%S%f') else: ctime = p_ctime log_dir = os.path.join( config.SESSION_DB_PATH, 'process_logs' ) if not os.path.exists(log_dir): os.mkdir(log_dir) id = ctime log_dir = os.path.join(log_dir, id) if not os.path.exists(log_dir): os.mkdir(log_dir) # Make a copy of environment, and add new variables to support env = os.environ.copy() env['PROCID'] = id env['OUTDIR'] = log_dir env['PGA_BGP_FOREGROUND'] = "1" if stdin_str: env['stdin_str'] = stdin_str if report_file: env['report_file'] = report_file if process_type: env['process_type'] = process_type if exclude_str: env["EXCLUDE_STR"] = exclude_str if IS_PY2: # We need environment variables & values in string env = convert_environment_variables(env) if os.name == 'nt': DETACHED_PROCESS = 0x00000008 from subprocess import CREATE_NEW_PROCESS_GROUP # We need to redirect the standard input, standard output, and # standard error to devnull in order to allow it start in detached # mode on stdout = os.devnull stderr = stdout stdin = open(os.devnull, "r") stdout = open(stdout, "a") stderr = open(stderr, "a") p = Popen( cmd, close_fds=False, env=env, stdout=stdout.fileno(), stderr=stderr.fileno(), stdin=stdin.fileno(), creationflags=(CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS) ) else: def preexec_function(): import signal # Detaching from the parent process group os.setpgrp() # Explicitly ignoring signals in the child process #signal.signal(signal.SIGINT, signal.SIG_IGN) p = Popen( cmd, close_fds=True, stdout=None, stderr=None, stdin=None, preexec_fn=preexec_function, env=env ) ecode = p.poll() # Execution completed immediately. # Process executor can not update the status, if it was not able to # start properly. process_completed=False if ecode is not None and ecode != 0: # There is no way to find out the error message from this process # as standard output, and standard error were redirected to # devnull. process_completed=True return {"status":process_completed, "log_dir":log_dir, 'process_log_id':id}
def start(self, cb=None): def which(program, paths): def is_exe(fpath): return os.path.exists(fpath) and os.access(fpath, os.X_OK) for path in paths: if not os.path.isdir(path): continue exe_file = os.path.join(u(path, fs_encoding), program) if is_exe(exe_file): return file_quote(exe_file) return None def convert_environment_variables(env): """ This function is use to convert environment variable to string because environment variable must be string in popen :param env: Dict of environment variable :return: Encoded environment variable as string """ encoding = sys.getdefaultencoding() if encoding is None or encoding == 'ascii': encoding = 'utf-8' temp_env = dict() for key, value in env.items(): if not isinstance(key, str): key = key.encode(encoding) if not isinstance(value, str): value = value.encode(encoding) temp_env[key] = value return temp_env if self.stime is not None: if self.etime is None: raise Exception(_('The process has already been started.')) raise Exception( _('The process has already finished and cannot be restarted.') ) executor = file_quote(os.path.join( os.path.dirname(u(__file__)), u'process_executor.py' )) paths = os.environ['PATH'].split(os.pathsep) interpreter = None if os.name == 'nt': paths.insert(0, os.path.join(u(sys.prefix), u'Scripts')) paths.insert(0, u(sys.prefix)) interpreter = which(u'pythonw.exe', paths) if interpreter is None: interpreter = which(u'python.exe', paths) if interpreter is None and current_app.PGADMIN_RUNTIME: # We've faced an issue with Windows 2008 R2 (x86) regarding, # not honouring the environment variables set under the Qt # (e.g. runtime), and also setting PYTHONHOME same as # sys.executable (i.e. pgAdmin4.exe). # # As we know, we're running it under the runtime, we can assume # that 'venv' directory will be available outside of 'bin' # directory. # # We would try out luck to find python executable based on that # assumptions. bin_path = os.path.dirname(sys.executable) venv = os.path.realpath( os.path.join(bin_path, u'..\\venv') ) interpreter = which(u'pythonw.exe', [venv]) if interpreter is None: interpreter = which(u'pythonw.exe', [venv]) if interpreter is not None: # Our assumptions are proven right. # Let's append the 'bin' directory to the PATH environment # variable. And, also set PYTHONHOME environment variable # to 'venv' directory. os.environ['PATH'] = bin_path + ';' + os.environ['PATH'] os.environ['PYTHONHOME'] = venv else: # Let's not use sys.prefix in runtime. # 'sys.prefix' is not identified on *nix systems for some unknown # reason, while running under the runtime. # We're already adding '<installation path>/pgAdmin 4/venv/bin' # directory in the PATH environment variable. Hence - it will # anyway be the redundant value in paths. if not current_app.PGADMIN_RUNTIME: paths.insert(0, os.path.join(u(sys.prefix), u'bin')) interpreter = which(u'python', paths) p = None cmd = [ interpreter if interpreter is not None else 'python', executor, self.cmd ] cmd.extend(self.args) if os.name == 'nt' and IS_PY2: command = [] for c in cmd: command.append( c.encode('utf-8') if isinstance(c, unicode) else str(c) ) current_app.logger.info( u"Executing the process executor with the arguments: %s", ''.join(command) ) cmd = command else: current_app.logger.info( u"Executing the process executor with the arguments: %s", str(cmd) ) # Make a copy of environment, and add new variables to support env = os.environ.copy() env['PROCID'] = self.id env['OUTDIR'] = self.log_dir env['PGA_BGP_FOREGROUND'] = "1" if self.env: env.update(self.env) if cb is not None: cb(env) if IS_PY2: # We need environment variables & values in string env = convert_environment_variables(env) if os.name == 'nt': DETACHED_PROCESS = 0x00000008 from subprocess import CREATE_NEW_PROCESS_GROUP # We need to redirect the standard input, standard output, and # standard error to devnull in order to allow it start in detached # mode on stdout = os.devnull stderr = stdout stdin = open(os.devnull, "r") stdout = open(stdout, "a") stderr = open(stderr, "a") p = Popen( cmd, close_fds=False, env=env, stdout=stdout.fileno(), stderr=stderr.fileno(), stdin=stdin.fileno(), creationflags=(CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS) ) else: def preexec_function(): import signal # Detaching from the parent process group os.setpgrp() # Explicitly ignoring signals in the child process signal.signal(signal.SIGINT, signal.SIG_IGN) p = Popen( cmd, close_fds=True, stdout=None, stderr=None, stdin=None, preexec_fn=preexec_function, env=env ) self.ecode = p.poll() # Execution completed immediately. # Process executor cannot update the status, if it was not able to # start properly. if self.ecode is not None and self.ecode != 0: # There is no way to find out the error message from this process # as standard output, and standard error were redirected to # devnull. p = Process.query.filter_by( pid=self.id, user_id=current_user.id ).first() p.start_time = p.end_time = get_current_time() if not p.exit_code: p.exit_code = self.ecode db.session.commit()