Пример #1
0
 async def sysfs_impl(container_id):
     mem_prefix = f'/sys/fs/cgroup/memory/docker/{container_id}/'
     io_prefix = f'/sys/fs/cgroup/blkio/docker/{container_id}/'
     try:
         mem_cur_bytes = read_sysfs(
             mem_prefix + 'memory.usage_in_bytes', int)
         io_stats = Path(io_prefix +
                         'blkio.throttle.io_service_bytes').read_text()
         # example data:
         #   8:0 Read 13918208
         #   8:0 Write 0
         #   8:0 Sync 0
         #   8:0 Async 13918208
         #   8:0 Total 13918208
         #   Total 13918208
         io_read_bytes = 0
         io_write_bytes = 0
         for line in io_stats.splitlines():
             if line.startswith('Total '):
                 continue
             dev, op, nbytes = line.strip().split()
             if op == 'Read':
                 io_read_bytes += int(nbytes)
             elif op == 'Write':
                 io_write_bytes += int(nbytes)
     except IOError as e:
         log.warning(
             'cannot read stats: sysfs unreadable for container {0}\n{1!r}',
             container_id[:7], e)
         return None
     loop = current_loop()
     scratch_sz = await loop.run_in_executor(None, get_scratch_size,
                                             container_id)
     return mem_cur_bytes, io_read_bytes, io_write_bytes, scratch_sz
Пример #2
0
async def proxy_connection(upper_sock_path: Path,
                           down_reader: asyncio.StreamReader,
                           down_writer: asyncio.StreamWriter) -> None:

    up_reader, up_writer = await asyncio.open_unix_connection(
        str(upper_sock_path))

    async def _downstream():
        try:
            while True:
                data = await up_reader.read(4096)
                if not data:
                    break
                down_writer.write(data)
                await down_writer.drain()
        except asyncio.CancelledError:
            pass
        finally:
            down_writer.close()
            await down_writer.wait_closed()
            await asyncio.sleep(0)

    async def _upstream():
        try:
            while True:
                data = await down_reader.read(4096)
                if not data:
                    break
                up_writer.write(data)
                await up_writer.drain()
        except asyncio.CancelledError:
            pass
        finally:
            up_writer.close()
            await up_writer.wait_closed()
            await asyncio.sleep(0)

    loop = current_loop()
    downstream_task = loop.create_task(_downstream())
    upstream_task = loop.create_task(_upstream())
    tasks = [upstream_task, downstream_task]
    # Since we cannot determine which side (the server or client) disconnects first,
    # await until any task that completes first.
    # For example, when proxying the docker domain socket, the proxy connections for one-shot
    # docker commands are usually disconnected by the client first, but the connections for
    # long-running streaming commands are disconnected by the server first when the server-side
    # processing finishes.
    try:
        task_results: Tuple[Set[Future], Set[Future]] = \
            await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
        done, pending = task_results
    except asyncio.CancelledError:
        pass
    finally:
        # And then cancel all remaining tasks.
        for t in pending:
            t.cancel()
            await t
Пример #3
0
async def read_tail(path: Path, nbytes: int) -> bytes:
    file_size = path.stat().st_size

    def _read_tail() -> bytes:
        with open(path, 'rb') as f:
            f.seek(max(file_size - nbytes, 0), io.SEEK_SET)
            return f.read(nbytes)

    loop = current_loop()
    return await loop.run_in_executor(None, _read_tail)
Пример #4
0
 async def __ainit__(self) -> None:
     loop = current_loop()
     self.input_sock.connect(await self.get_repl_in_addr())
     self.input_sock.setsockopt(zmq.LINGER, 50)
     self.output_sock.connect(await self.get_repl_out_addr())
     self.output_sock.setsockopt(zmq.LINGER, 50)
     self.status_task = loop.create_task(self.ping_status())
     self.read_task = loop.create_task(self.read_output())
     if self.exec_timeout > 0:
         self.watchdog_task = loop.create_task(self.watchdog())
     else:
         self.watchdog_task = None
Пример #5
0
 def __init__(
     self,
     etcd: AsyncEtcd,
     local_config: Mapping[str, Any],
     *,
     skip_detect_manager: bool = False,
 ) -> None:
     self.loop = current_loop()
     self.etcd = etcd
     self.local_config = local_config
     self.skip_detect_manager = skip_detect_manager
     self._stop_signal = signal.SIGTERM
Пример #6
0
 async def api_impl(container_id):
     container = DockerContainer(ctx.agent.docker, id=container_id)
     ret = await fetch_api_stats(container)
     if ret is None:
         return None
     mem_cur_bytes = nmget(ret, 'memory_stats.usage', 0)
     io_read_bytes = 0
     io_write_bytes = 0
     for item in nmget(ret, 'blkio_stats.io_service_bytes_recursive',
                       []):
         if item['op'] == 'Read':
             io_read_bytes += item['value']
         elif item['op'] == 'Write':
             io_write_bytes += item['value']
     loop = current_loop()
     scratch_sz = await loop.run_in_executor(None, get_scratch_size,
                                             container_id)
     return mem_cur_bytes, io_read_bytes, io_write_bytes, scratch_sz
Пример #7
0
    async def delete_vfolders(
        cls,
        conn: SAConnection,
        user_uuid: uuid.UUID,
        config_server,
    ) -> int:
        """
        Delete user's all virtual folders as well as their physical data.

        :param conn: DB connection
        :param user_uuid: user's UUID to delete virtual folders

        :return: number of deleted rows
        """
        from . import vfolders
        mount_prefix = Path(await config_server.get('volumes/_mount'))
        fs_prefix = await config_server.get('volumes/_fsprefix')
        fs_prefix = Path(fs_prefix.lstrip('/'))
        query = (
            sa.select([vfolders.c.id, vfolders.c.host, vfolders.c.unmanaged_path])
            .select_from(vfolders)
            .where(vfolders.c.user == user_uuid)
        )
        async for row in conn.execute(query):
            if row['unmanaged_path']:
                folder_path = Path(row['unmanaged_path'])
            else:
                folder_path = (mount_prefix / row['host'] / fs_prefix / row['id'].hex)
            log.info('deleting physical files: {0}', folder_path)
            try:
                loop = current_loop()
                await loop.run_in_executor(None, lambda: shutil.rmtree(folder_path))  # type: ignore
            except IOError:
                pass
        query = (
            vfolders.delete()
            .where(vfolders.c.user == user_uuid)
        )
        result = await conn.execute(query)
        if result.rowcount > 0:
            log.info('deleted {0} user\'s virtual folders ({1})', result.rowcount, user_uuid)
        return result.rowcount
Пример #8
0
def handle_loop_error(
    root_app: web.Application,
    loop: asyncio.AbstractEventLoop,
    context: Mapping[str, Any],
) -> None:
    if isinstance(loop, aiojobs.Scheduler):
        loop = current_loop()
    exception = context.get('exception')
    msg = context.get('message', '(empty message)')
    if exception is not None:
        if sys.exc_info()[0] is not None:
            log.exception('Error inside event loop: {0}', msg)
            if 'error_monitor' in root_app:
                loop.create_task(root_app['error_monitor'].capture_exception())
        else:
            exc_info = (type(exception), exception, exception.__traceback__)
            log.error('Error inside event loop: {0}', msg, exc_info=exc_info)
            if 'error_monitor' in root_app:
                loop.create_task(root_app['error_monitor'].capture_exception(
                    exc_instance=exception))
Пример #9
0
    async def accept_file(self, filename: str, filedata: bytes):
        loop = current_loop()
        work_dir = self.agent_config['container']['scratch-root'] / str(
            self.kernel_id) / 'work'
        try:
            # create intermediate directories in the path
            dest_path = (work_dir / filename).resolve(strict=False)
            parent_path = dest_path.parent
        except ValueError:  # parent_path does not start with work_dir!
            raise AssertionError('malformed upload filename and path.')

        def _write_to_disk():
            parent_path.mkdir(parents=True, exist_ok=True)
            dest_path.write_bytes(filedata)

        try:
            await loop.run_in_executor(None, _write_to_disk)
        except FileNotFoundError:
            log.error('{0}: writing uploaded file failed: {1} -> {2}',
                      self.kernel_id, filename, dest_path)
Пример #10
0
 def __init__(self, app: web.Application) -> None:
     self.loop = current_loop()
     self.root_app = app
     self.consumers = defaultdict(set)
     self.subscribers = defaultdict(set)
Пример #11
0
    async def gather_node_measures(
            self, ctx: StatContext) -> Sequence[NodeMeasurement]:
        _mstat = psutil.virtual_memory()
        total_mem_used_bytes = Decimal(_mstat.total - _mstat.available)
        total_mem_capacity_bytes = Decimal(_mstat.total)
        _nstat = psutil.net_io_counters()
        net_rx_bytes = _nstat.bytes_recv
        net_tx_bytes = _nstat.bytes_sent

        def get_disk_stat():
            pruned_disk_types = frozenset(['squashfs', 'vfat', 'tmpfs'])
            total_disk_usage = Decimal(0)
            total_disk_capacity = Decimal(0)
            per_disk_stat = {}
            for disk_info in psutil.disk_partitions():
                if disk_info.fstype not in pruned_disk_types:
                    dstat = os.statvfs(disk_info.mountpoint)
                    disk_usage = Decimal(dstat.f_frsize *
                                         (dstat.f_blocks - dstat.f_bavail))
                    disk_capacity = Decimal(dstat.f_frsize * dstat.f_blocks)
                    per_disk_stat[disk_info.device] = Measurement(
                        disk_usage, disk_capacity)
                    total_disk_usage += disk_usage
                    total_disk_capacity += disk_capacity
            return total_disk_usage, total_disk_capacity, per_disk_stat

        loop = current_loop()
        total_disk_usage, total_disk_capacity, per_disk_stat = \
            await loop.run_in_executor(None, get_disk_stat)
        return [
            NodeMeasurement(
                MetricKey('mem'),
                MetricTypes.USAGE,
                unit_hint='bytes',
                stats_filter=frozenset({'max'}),
                per_node=Measurement(total_mem_used_bytes,
                                     total_mem_capacity_bytes),
                per_device={
                    DeviceId('root'):
                    Measurement(total_mem_used_bytes, total_mem_capacity_bytes)
                },
            ),
            NodeMeasurement(
                MetricKey('disk'),
                MetricTypes.USAGE,
                unit_hint='bytes',
                per_node=Measurement(total_disk_usage, total_disk_capacity),
                per_device=per_disk_stat,
            ),
            NodeMeasurement(
                MetricKey('net_rx'),
                MetricTypes.RATE,
                unit_hint='bps',
                current_hook=lambda metric: metric.stats.rate,
                per_node=Measurement(Decimal(net_rx_bytes)),
                per_device={
                    DeviceId('node'): Measurement(Decimal(net_rx_bytes))
                },
            ),
            NodeMeasurement(
                MetricKey('net_tx'),
                MetricTypes.RATE,
                unit_hint='bps',
                current_hook=lambda metric: metric.stats.rate,
                per_node=Measurement(Decimal(net_tx_bytes)),
                per_device={
                    DeviceId('node'): Measurement(Decimal(net_tx_bytes))
                },
            ),
        ]