Skip to content

Commit

Permalink
Adding empty injector
Browse files Browse the repository at this point in the history
  • Loading branch information
Wh1isper committed Nov 27, 2023
1 parent 5727a3d commit cffd508
Show file tree
Hide file tree
Showing 15 changed files with 217 additions and 30 deletions.
4 changes: 4 additions & 0 deletions duetector/extension/injector/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import pluggy

project_name = "duetector.injector"
hookimpl = pluggy.HookimplMarker(project_name)
11 changes: 5 additions & 6 deletions duetector/filters/base.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
from __future__ import annotations

import os
from collections import namedtuple

from duetector.config import Configuable
from duetector.extension.filter import hookimpl


class Filter(Configuable):
Expand All @@ -22,17 +20,18 @@ class Filter(Configuable):
.. code-block:: python
from duetector.filters import Filter
from duetector.collectors.models import Tracking
from collections import namedtuple
class MyFilter(Filter):
def filter(self, data: Tracking) -> Optional[Tracking]:
def filter(self, data: namedtuple) -> namedtuple | None:
if data.fname == "/etc/passwd":
return None
return data
f = MyFilter()
f(Tracking(fname="/etc/passwd")) # None
f(Tracking(fname="/etc/shadow")) # Tracking(fname="/etc/shadow")
data_t = namedtuple("Tracking", "fname")
f(data_t(fname="/etc/passwd")) # None
f(data_t(fname="/etc/shadow")) # Tracking(fname="/etc/shadow")
"""

default_config = {
Expand Down
Empty file added duetector/injectors/__init__.py
Empty file.
58 changes: 58 additions & 0 deletions duetector/injectors/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from __future__ import annotations

import os
from collections import namedtuple

from duetector.config import Configuable


class NamespaceMixin:
pass


class CgroupMixin:
pass


class Injector(Configuable):
"""
A base class for all Injectors.
Default config scope is ``Injector.{class_name}``.
subclass should override ``inject`` method and ``super`` it.
User should call Injector() directly to Injector data,
"""

default_config = {
"disabled": False,
}
"""
Default config for ``Injector``.
"""

@property
def config_scope(self):
"""
Config scope for current Injector.
"""
return self.__class__.__name__

@property
def disabled(self):
"""
If current Injector is disabled.
"""
return self.config.disabled

def inject(self, data: namedtuple) -> namedtuple:
"""
Implement this method to patch ``data``
"""
return data

def __call__(self, data: namedtuple) -> namedtuple | None:
if self.disabled:
return data
return self.inject(data)
11 changes: 11 additions & 0 deletions duetector/injectors/docker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from duetector.extension.injector import hookimpl
from duetector.injectors.base import Injector


class DockerInjector(Injector):
pass


@hookimpl
def init_injector(config=None):
return DockerInjector(config=config)
11 changes: 11 additions & 0 deletions duetector/injectors/k8s.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from duetector.extension.injector import hookimpl
from duetector.injectors.base import Injector


class K8SInjector(Injector):
pass


@hookimpl
def init_injector(config=None):
return K8SInjector(config=config)
4 changes: 4 additions & 0 deletions duetector/injectors/register.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Expose for plugin system
from . import docker, k8s

registers = [docker, k8s]
68 changes: 68 additions & 0 deletions duetector/managers/injector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from __future__ import annotations

import sys
from typing import Any

import pluggy

import duetector.injectors.register
from duetector.extension.injector import project_name
from duetector.injectors.base import Injector
from duetector.log import logger
from duetector.managers.base import Manager

PROJECT_NAME = project_name #: Default project name for pluggy
hookspec = pluggy.HookspecMarker(PROJECT_NAME)


@hookspec
def init_injector(config) -> Injector | None:
"""
Initialize Injector from config
None means the Injector is not available
Also the Injector can be disabled by config, Manager will discard disabled Injector
"""


class InjectorManager(Manager):
"""
Manager for all Injectors.
Injectors are initialized from config, and can be ``disabled`` by config.
"""

config_scope = "injector"
"""
Config scope for ``InjectorManager``.
"""

def __init__(self, config: dict[str, Any] | None = None, *args, **kwargs):
super().__init__(config, *args, **kwargs)

self.pm = pluggy.PluginManager(PROJECT_NAME)
self.pm.add_hookspecs(sys.modules[__name__])
if self.include_extension:
self.pm.load_setuptools_entrypoints(PROJECT_NAME)
self.register(duetector.injectors.register)

def init(self, ignore_disabled=True, *args, **kwargs) -> list[Injector]:
"""
Initialize all Injectors from config.
Args:
ignore_disabled: Ignore disabled Injectors
"""
if self.disabled:
logger.info("InjectorManager disabled.")
return []
objs = []
for f in self.pm.hook.init_injector(config=self.config._config_dict):
if not f:
continue
if f.disabled and ignore_disabled:
logger.info(f"Injector {f.__class__.__name__} is disabled")
continue

objs.append(f)

return objs
39 changes: 31 additions & 8 deletions duetector/monitors/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

from collections import namedtuple

from duetector.injectors.base import Injector
from duetector.managers.collector import CollectorManager
from duetector.managers.filter import FilterManager
from duetector.managers.injector import InjectorManager

try:
from functools import cache
except ImportError:
Expand Down Expand Up @@ -30,7 +35,6 @@ class Monitor(Configuable):
"""
A list of tracers, should be initialized by ``TracerManager``
"""

filters: list[Filter]
"""
A list of filters, should be initialized by ``FilterManager``
Expand All @@ -39,6 +43,10 @@ class Monitor(Configuable):
"""
A list of collectors, should be initialized by ``CollectorManager``
"""
injectors: list[Injector]
"""
A list of collectors, should be initialized by ``InjectorManager``
"""

config_scope = "monitor"
"""
Expand Down Expand Up @@ -72,6 +80,16 @@ def __init__(self, config: dict[str, Any] | None = None, *args, **kwargs):
self._backend = self._backend_imp(**self.backend_args._config_dict)
self.poller = Poller(self.config._config_dict)

if self.disabled:
self.tracers = []
self.filters = []
self.collectors = []
self.injectors = []
return
self.filters: list[Filter] = FilterManager(config).init()
self.collectors: list[Collector] = CollectorManager(config).init()
self.injectors: list[Injector] = InjectorManager(config).init()

@property
def disabled(self):
"""
Expand Down Expand Up @@ -126,18 +144,23 @@ def shutdown(self):
c.shutdown()

def _inject_extra_info(self, data: namedtuple) -> namedtuple:
for injector in self.injectors:
data = injector(data)
return data

@cache
def _get_callback_fn(self, tracer) -> Callable[[namedtuple], None]:
def _(data):
for filter in self.filters:
data = filter(data)
if not data:
return
data = self._inject_extra_info(data)
for collector in self.collectors:
collector.emit(tracer, data)
try:
for filter in self.filters:
data = filter(data)
if not data:
return
data = self._inject_extra_info(data)
for collector in self.collectors:
collector.emit(tracer, data)
except Exception as e:
logger.exception(e)

return _

Expand Down
8 changes: 3 additions & 5 deletions duetector/monitors/bcc_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
from typing import Any, Callable

from duetector.collectors.base import Collector
from duetector.filters.base import Filter
from duetector.injectors.base import Injector
from duetector.log import logger
from duetector.managers.collector import CollectorManager
from duetector.managers.filter import FilterManager
from duetector.managers.injector import InjectorManager
from duetector.managers.tracer import TracerManager
from duetector.monitors.base import Monitor
from duetector.tracers import BccTracer
Expand Down Expand Up @@ -45,14 +48,9 @@ def __init__(self, config: dict[str, Any] | None = None, *args, **kwargs):
super().__init__(config=config)
if self.disabled:
logger.info("BccMonitor disabled")
self.tracers = []
self.filters = []
self.collectors = []
return

self.tracers: list[BccTracer] = TracerManager(config).init(tracer_type=BccTracer) # type: ignore
self.filters: list[Callable] = FilterManager(config).init()
self.collectors: list[Collector] = CollectorManager(config).init()

self.bpf_tracers: dict[Any, BccTracer] = {}
if self.auto_init:
Expand Down
10 changes: 5 additions & 5 deletions duetector/monitors/sh_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
from datetime import datetime
from typing import Any, Callable

from duetector.filters.base import Filter
from duetector.injectors.base import Injector
from duetector.managers.injector import InjectorManager

try:
from functools import cache
except ImportError:
Expand Down Expand Up @@ -124,14 +128,10 @@ def __init__(self, config: dict[str, Any] | None = None, *args, **kwargs):
super().__init__(config=config, *args, **kwargs)
if self.disabled:
logger.info("ShMonitor disabled")
self.tracers = []
self.filters = []
self.collectors = []
return

self.tracers: list[ShellTracer] = TracerManager(config).init(tracer_type=ShellTracer) # type: ignore
self.filters: list[Callable] = FilterManager(config).init()
self.collectors: list[Collector] = CollectorManager(config).init()

self.host = ShTracerHost(self._backend, self.timeout)
if self.auto_init:
self.init()
Expand Down
7 changes: 2 additions & 5 deletions duetector/monitors/subprocess_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
import psutil

from duetector.collectors.base import Collector
from duetector.injectors.base import Injector
from duetector.log import logger
from duetector.managers.collector import CollectorManager
from duetector.managers.filter import FilterManager
from duetector.managers.injector import InjectorManager
from duetector.managers.tracer import TracerManager
from duetector.monitors.base import Monitor
from duetector.proto.subprocess import (
Expand Down Expand Up @@ -243,14 +245,9 @@ def __init__(self, config: dict[str, Any] | None = None, *args, **kwargs):
super().__init__(config=config, *args, **kwargs)
if self.disabled:
logger.info("SubprocessMonitor disabled")
self.tracers = []
self.filters = []
self.collectors = []
return

self.tracers: list[SubprocessTracer] = TracerManager(config).init(tracer_type=SubprocessTracer) # type: ignore
self.filters: list[Callable] = FilterManager(config).init()
self.collectors: list[Collector] = CollectorManager(config).init()

self.host = SubprocessHost(
timeout=self.timeout,
Expand Down
10 changes: 10 additions & 0 deletions duetector/static/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,16 @@ table_prefix = "duetector_tracking"
[analyzer.dbanalyzer.db.engine]
url = "sqlite:///duetector-dbcollector.sqlite3"

[injector]
disabled = false
include_extension = true

[injector.k8sinjector]
disabled = false

[injector.dockerinjector]
disabled = false

[monitor.bcc]
disabled = false
auto_init = true
Expand Down
3 changes: 2 additions & 1 deletion duetector/tools/config_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from duetector.managers.analyzer import AnalyzerManager
from duetector.managers.collector import CollectorManager
from duetector.managers.filter import FilterManager
from duetector.managers.injector import InjectorManager
from duetector.managers.tracer import TracerManager
from duetector.monitors import BccMonitor, ShMonitor, SubprocessMonitor
from duetector.service.config import ServerConfig
Expand Down Expand Up @@ -51,7 +52,7 @@ class ConfigGenerator:
"""

managers = [FilterManager, TracerManager, CollectorManager, AnalyzerManager]
managers = [FilterManager, TracerManager, CollectorManager, AnalyzerManager, InjectorManager]
"""
All managers to inspect.
"""
Expand Down
Loading

0 comments on commit cffd508

Please sign in to comment.