示例#1
0
 def suspend(self):
     if self.transport.pid is not None:
         p = Process(self.transport.pid)
         p.suspend()
         while p.status() == STATUS_RUNNING:
             print("suspend {}: still running".format(self._node_dir))
             continue
         print("  status: {}".format(p.status()))
     else:
         raise RuntimeError("Cannot suspend Tahoe: no PID available")
示例#2
0
def start():
    if os.path.exists('/opt/bin/ffmpeg.pid'):
        with open('/opt/bin/ffmpeg.pid', 'r') as f:
            parentPid = f.read()
        parentProcess = Process(int(parentPid))
        return jsonify({'started': 'false', 'status': parentProcess.status()})
    parentProcess = Popen(startCmd(), shell=False)
    parentPid = parentProcess.pid
    with open('/opt/bin/ffmpeg.pid', 'w') as f:
        f.write(str(parentPid))
    parentProcess = Process(parentPid)
    return jsonify({'started': 'true', 'status': parentProcess.status()})
示例#3
0
def is_running(process: psutil.Process) -> bool:
    if not process:
        return False
    try:
        return process.status() == psutil.STATUS_RUNNING
    except psutil.NoSuchProcess:
        return False
示例#4
0
    def is_process_alive(
        self,
        process: psutil.Process,
    ) -> bool:
        if not process.is_running():
            self.logger.info(msg='process status: not running', )

            return False

        try:
            process_status = process.status()
        except psutil.NoSuchProcess:
            self.logger.info(msg='pid does not exist anymore', )

            return False

        if process_status in [
                psutil.STATUS_DEAD,
                psutil.STATUS_ZOMBIE,
        ]:
            self.logger.error(
                msg=f'process became a zombie/dead process: {process_status}',
            )

            return False

        return True
示例#5
0
def cleanup_zombie_process(pid):
    try:
        if pid_exists(pid):
            p = Process(pid)
            if p.status() == STATUS_ZOMBIE:
                p.wait()
    except Exception as e:
        pass
示例#6
0
 def resume(self):
     if self.transport.pid is not None:
         p = Process(self.transport.pid)
         p.resume()
         while p.status() != STATUS_RUNNING:
             print("resume {}: not running".format(self._node_dir))
     else:
         raise RuntimeError("Cannot resume Tahoe: no PID available")
示例#7
0
def collect_status(pid, appname, site):
    ip_out = get_host_info()[0]
    ip_inner = get_host_info()[1]
    server_id = get_host_info()[2]
    physical_mem = psutil.virtual_memory().total / 1024 / 1024  #Unit of M
    cpu_count = psutil.cpu_count()
    its = int(time.time())
    p_ins = Process(pid)
    pstatus = p_ins.status()
    create_time = time.strftime("%Y%m%d %H:%M:%S",
                                time.localtime(p_ins.create_time()))
    memory_percent = p_ins.memory_percent()
    memory_used = memory_percent * physical_mem
    cpu_calc_list = []
    for i in range(6):
        cpu_calc = p_ins.cpu_percent(interval=0.1)
        cpu_calc_list.append(cpu_calc)
    cpu_percent = float(sum(cpu_calc_list) / len(cpu_calc_list))
    num_fds = p_ins.num_fds()
    connections = p_ins.connections()
    connections_num = len(connections)

    #appname=p_ins.cwd()
    if p_ins.name() == 'jsvc':
        app_path = p_ins.exe().split('/')[:-2]
    else:
        app_path = p_ins.cwd()

    #appname = app_path.split('/')[-1]
    appname = appname
    if p_ins.children(recursive=True):
        children_list = str(p_ins.children(recursive=True))
    else:
        children_list = None
    message = {
        'site': site,
        'ip': ip_out,
        'ip_inner': ip_inner,
        'server_id': server_id,
        'pstatus': pstatus,
        'metric_name': 'app_monitor',
        'its': its,
        'pid': pid,
        'physical_mem': physical_mem,
        'memory_used': memory_used,
        'memory_percent': memory_percent,
        'cpu_count': cpu_count,
        'cpu_percent': cpu_percent,
        'num_fds': num_fds,
        'connections_num': connections_num,
        'create_time': create_time,
        'appname': appname,
        'app_path': app_path,
        'children': children_list
    }
    return message
示例#8
0
 async def _close_process(self, proc: psutil.Process):
     try:
         proc.terminate()
         await asyncio.sleep(1)
         try:
             if proc.status() != psutil.STATUS_ZOMBIE:
                 proc.kill()
         except Exception:
             pass
     except Exception:
         pass
     try:
         proc.wait(timeout=0)
     except Exception:
         pass
示例#9
0
def is_buzy(proc: psutil.Process) -> bool:
    """is_buzy.

    Parameters
    ----------
    proc : psutil.Process
        process

    Returns
    -------
    bool
        if the process or its subprocess buzy
    """
    try:
        p_status = proc.status()
        logger.debug(f"cmd: {proc.cmdline()}, status: {p_status}")
        if p_status in {psutil.STATUS_RUNNING, psutil.STATUS_DISK_SLEEP}:
            return True
        for ch_proc in proc.children():
            if is_buzy(ch_proc):
                return True
        return False
    except psutil.NoSuchProcess:
        return False
class FactorioManager(object):
    def __init__(self, name: str, port: int, root_path, is_steam=False):
        self.name = name
        self.port = port
        self.process = None
        self.root_path = Path(root_path)
        self.log = make_log(f'{name}_factorio')
        self.update_available = False
        self._ps_proc = None
        self._virtual_mem = VIRTUAL_MEMORY
        self._is_steam = is_steam
        self._player_data = None
        self._config = None
        self._server_config = None
        self._version_info = None
        self._available_versions = None
        self._temp_update = None
        self._log_queue = deque(maxlen=20)
        self._status_history = deque(maxlen=50)

    @property
    def version(self):
        if self._version_info is None:
            self.set_version_info()
        return self._version_info['version']

    @property
    def build(self):
        if self._version_info is None:
            self.set_version_info()
        return self._version_info['build']

    @property
    def build_num(self):
        if self._version_info is None:
            self.set_version_info()
        return self._version_info['build']['number']

    @property
    def build_platform(self):
        if self._version_info is None:
            self.set_version_info()
        return self._version_info['build']['platform']

    @property
    def build_mode(self):
        if self._version_info is None:
            self.set_version_info()
        return self._version_info['build']['mode']

    @property
    def bin_version(self):
        if self._version_info is None:
            self.set_version_info()
        return self._version_info['binary version']

    @property
    def map_in_version(self):
        if self._version_info is None:
            self.set_version_info()
        return self._version_info['map input version']

    @property
    def map_out_version(self):
        if self._version_info is None:
            self.set_version_info()
        return self._version_info['map output version']

    @property
    def is_experimental(self):
        if not self._available_versions:
            t = self.fetch_factorio_versions()
            t.join()
        if self.version_list.index(self.stable) < self.version_list.index(
                self.version):
            return True
        return False

    @property
    def stable(self):
        if not self._available_versions:
            t = self.fetch_factorio_versions()
            t.join()
        return self._available_versions['stable']

    @property
    def version_list(self):
        if not self._available_versions:
            t = self.fetch_factorio_versions()
            t.join()
        return self._available_versions['version_list']

    @property
    def experimental_version_list(self):
        if not self._available_versions:
            t = self.fetch_factorio_versions()
            t.join()
        return self.version_list[self.version_list.index(self.stable) + 1:]

    @property
    def stable_version_list(self):
        if not self._available_versions:
            t = self.fetch_factorio_versions()
            t.join()
        return self.version_list[:self.version_list.index(self.stable) + 1]

    @property
    def executable(self):
        if OS_WIN:
            return (self.root_path / 'bin' / 'x64' / 'factorio.exe').resolve()
        else:
            return (self.root_path / 'bin' / 'x64' / 'factorio').resolve()

    @property
    def save_file(self):
        return (self.root_path / 'saves' / self.name /
                f'{self.name}.zip').resolve()

    @property
    def player_data(self):
        if not self._player_data:
            self._player_data = json.load(
                (self.root_path / 'player-data.json').resolve().open())
        return self._player_data

    @property
    def service_username(self):
        if not self._player_data:
            self._player_data = json.load(
                (self.root_path / 'player-data.json').resolve().open())
        return self._player_data['service-username']

    @property
    def service_token(self):
        if not self._player_data:
            self._player_data = json.load(
                (self.root_path / 'player-data.json').resolve().open())
        return self._player_data['service-token']

    @property
    def config(self):
        if not self._config:
            conf_parser = ConfigParser()
            self._config = conf_parser.read(
                (self.root_path / 'config' /
                 'config.ini').resolve().as_posix())
        return self._config

    @property
    def server_config(self):
        if not self._server_config:
            self._server_config = json.load(
                (self.root_path / 'config' /
                 'server-settings.json').resolve().open())
        return self._server_config

    @server_config.setter
    def server_config(self, config):
        self._server_config = merge_two_dicts(config, self._server_config)
        save_settings(self._server_config, (self.root_path / 'config' /
                                            'server-settings.json').resolve())

    @property
    def bits(self):
        if self.build_platform[-2:] == '64':
            return '64'
        else:
            return '32'  # I don't have any 32 bit systems so I wasn't sure what factorio would respond with

    @property
    def core_str(self):
        core = f'core-{self.build_platform[:-2]}'
        if self.build_mode == 'headless':
            core = core + '_headless'
        core = core + self.bits
        return core

    def set_version_info(self):
        log.info(f'Getting the version info for {self.name}')
        commands = [self.executable.as_posix(), '--version']
        p = Popen(commands, stdout=PIPE, stderr=PIPE)
        std_out, std_err = p.communicate()
        self._version_info = std_out.decode().splitlines()
        self._version_info = {
            l.split(':')[0].lower(): l.split(':')[1]
            for l in self._version_info
        }
        self._version_info['build'] = self._version_info['version'].split(
            '(')[1]
        self._version_info['build'] = self._version_info['build'].replace(
            ')', '').split(', ')
        self._version_info['build'] = {
            'number': self._version_info['build'][0].replace('build', ''),
            'platform': self._version_info['build'][1],
            'mode': self._version_info['build'][2]
        }
        self._version_info['version'] = self._version_info['version'].split(
            '(')[0].strip()

    def status(self):
        if self.process:
            if not self._ps_proc:
                self._ps_proc = Process(self.process.pid)
            try:
                data = {
                    'status': self._ps_proc.status(),
                    'cpu': self._ps_proc.cpu_percent(interval=2),
                    'mem': naturalsize(self._ps_proc.memory_info().rss),
                    'mem_raw': self._ps_proc.memory_info().rss,
                    'available_mem': naturalsize(self._virtual_mem.available),
                    'available_mem_raw': self._virtual_mem.available,
                    'total_mem': naturalsize(TOTAL_MEMORY),
                    'total_mem_raw': TOTAL_MEMORY,
                }
            except (NoSuchProcess, AttributeError):
                log.warn(
                    f'Factorio Process {self.name} does not exist anymore')
                return
            self._status_history.appendleft(data)
            return list(self._status_history)

    @run_in_thread
    def start(self):
        log.info(f'Starting Factorio instance {self.name}')
        if self.name in app_settings.factorio_instances:
            if isinstance(self.process, Popen):
                # TODO: need to do more here to actually check if it is running
                log.warn(f'{self.name} factorio instance is already running')
                return
        if self.name not in app_settings.factorio_instances:
            log.warn(f'{self.name} factorio instance does not exist')
            return
        commands = [
            self.executable.as_posix(), '--start-server', self.save_file,
            '--port',
            str(self.port)
        ]
        log.debug(f'Starting {self.name}')
        self.process = Popen(commands, stdin=PIPE, stdout=PIPE, stderr=PIPE)
        self.output_log()

    @run_in_thread
    def output_log(self):
        while True:
            std_out = self.process.stdout.readline()
            if std_out:
                std_out = std_out.decode()
                self._log_queue.append('{} {}: {}'.format(
                    datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3],
                    self.name.upper(), std_out.replace('\n', '')))
                self.log.info(std_out)
            else:
                sleep(.05)
            if self.process is None:
                break
            if self.process.poll() is not None:
                break

    def get_log_line(self):
        if len(self._log_queue):
            return self._log_queue.pop()
        else:
            return

    @run_in_thread
    def stop(self):
        log.debug(f'Stopping {self.name}')
        if self.process:
            self.process.terminate()
            self.process = None
            self._ps_proc = None

    @run_in_thread
    def kill(self):
        log.debug(f'Killing {self.name}')
        if self.process:
            self.process.kill()
            self.process = None
            self._ps_proc = None

    @run_in_thread
    def send_command(self, command):
        # TODO: This does not work. No idea how it should work
        if self.process:
            self.process.communicate(f'{command}\n'.encode())

    def create_save_file(self,
                         map_gen_file_path=None,
                         map_settings_path=None,
                         preset=None,
                         map_preview_path=None):
        if not self.save_file.is_file():
            if not (self.save_file / '..').resolve().is_dir():
                (self.save_file / '..').resolve().mkdir()
            commands = [
                self.executable.as_posix(), '--create',
                self.save_file.as_posix()
            ]
            # TODO: Add the optional arguments to commands
            p = Popen(commands, stdout=PIPE, stderr=PIPE)
            log.info(p.communicate())

    def get_version_info(self):
        if self._version_info is None:
            self.set_version_info()
        return self._version_info

    def check_for_update(self):
        self.get_version_info()
        t = self.fetch_factorio_versions()
        t.join()
        if self.is_experimental:
            version_list = self.experimental_version_list
        else:
            version_list = self.stable_version_list
        if self.version != version_list[-1]:
            self.update_available = version_list[-1]
            return version_list[-1]
        else:
            self.update_available = False

    def get_download_link(self, version):
        get_link_url = 'https://www.factorio.com/get-download-link'
        update_version_info = list(
            filter(lambda x: x['to'] == version,
                   self._available_versions['available_versions']))[0]
        data = {
            'username': self.service_username,
            'token': self.service_token,
            'package': self.core_str,
            'from': update_version_info['from'],
            'to': update_version_info['to'],
            'apiVersion': 2
        }
        req = request.Request(get_link_url + '?' + parse.urlencode(data))
        resp = request.urlopen(req)
        download_link = json.loads(resp.read())
        return download_link[0]

    def download_update(self, version):
        link = self.get_download_link(version)
        log.info(link)
        with TqdmUpTo(unit='B',
                      unit_scale=True,
                      miniters=1,
                      desc=link.split('/')[-1]) as t:
            self._temp_update = request.urlretrieve(
                link, reporthook=t.download_progress)[0]

    @run_in_thread
    def apply_update(self):
        if self._temp_update:
            commands = [
                self.executable.as_posix(), '--apply-update', self._temp_update
            ]
            p = Popen(commands, stdout=PIPE, stderr=PIPE)
            log.info(p.communicate())
            p.terminate()
        self.set_version_info()
        self.update_available = False

    @run_in_thread
    def fetch_factorio_versions(self):
        available_versions_url = 'https://www.factorio.com/get-available-versions'
        data = parse.urlencode({
            'username': self.service_username,
            'token': self.service_token,
            'apiVersion': 2
        })
        req = request.Request(available_versions_url + '?' + data)
        resp = request.urlopen(req)
        json_resp = json.loads(resp.read())
        available_versions = json_resp[self.core_str]
        stable_version = list(
            filter(lambda x: True if 'stable' in x else False,
                   available_versions))[0]['stable']
        available_versions = list(
            filter(lambda x: False
                   if 'stable' in x else True, available_versions))
        version_list = sorted(
            available_versions,
            key=lambda s: [int(u) for u in s['to'].split('.')])
        version_list = [u['to'] for u in version_list]
        self._available_versions = {
            'stable': stable_version,
            'version_list': version_list,
            'available_versions': available_versions
        }
        return json_resp
示例#11
0
 def _get_status(process: psutil.Process):
     # status = process.status()
     return process.status()