From 4af769f84cae5d091034e648429f3666542082c7 Mon Sep 17 00:00:00 2001 From: Leonardo Grasso Date: Mon, 1 Jun 2020 14:13:30 +0200 Subject: [PATCH] new(test): add gRPC unix socket support Signed-off-by: Leonardo Grasso --- docker/tester/Dockerfile | 2 ++ test/falco_test.py | 56 ++++++++++++++++++++++++++++++++++++++-- test/requirements.txt | 2 ++ 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/docker/tester/Dockerfile b/docker/tester/Dockerfile index ab0c4132..87dae67b 100644 --- a/docker/tester/Dockerfile +++ b/docker/tester/Dockerfile @@ -12,6 +12,8 @@ RUN dnf install -y python-pip python docker findutils jq unzip && dnf clean all ENV PATH="/root/.local/bin/:${PATH}" RUN pip install --user avocado-framework==69.0 RUN pip install --user avocado-framework-plugin-varianter-yaml-to-mux==69.0 +RUN pip install --user watchdog==0.10.2 +RUN pip install --user pathtools==0.1.2 RUN tar -C /usr/bin -xvf grpcurl_1.6.0_linux_x86_64.tar.gz COPY ./root / diff --git a/test/falco_test.py b/test/falco_test.py index 77abb57b..53f2bbb5 100644 --- a/test/falco_test.py +++ b/test/falco_test.py @@ -28,6 +28,8 @@ import urllib.request from avocado import Test from avocado import main from avocado.utils import process +from watchdog.observers import Observer +from watchdog.events import PatternMatchingEventHandler class FalcoTest(Test): @@ -195,18 +197,23 @@ class FalcoTest(Test): os.makedirs(filedir) self.outputs = outputs - self.grpc_unix_socket_path = self.params.get('grpc_unix_socket_path', '*', default='/var/run/falco.sock') + self.grpcurl_res = None + self.grpc_observer = None self.grpc_address = self.params.get('address', 'grpc/*', default='/var/run/falco.sock') if self.grpc_address.startswith("unix://"): self.is_grpc_using_unix_socket = True self.grpc_address = self.grpc_address[len("unix://"):] + else: + self.is_grpc_using_unix_socket = False self.grpc_proto = self.params.get('proto', 'grpc/*', default='') self.grpc_service = self.params.get('service', 'grpc/*', default='') self.grpc_method = self.params.get('method', 'grpc/*', default='') self.grpc_results = self.params.get('results', 'grpc/*', default='') - # todo: if string wrap in an array if self.grpc_results == '': self.grpc_results = [] + else: + if type(self.grpc_results) == str: + self.grpc_results = [self.grpc_results] self.disable_tags = self.params.get('disable_tags', '*', default='') @@ -430,6 +437,48 @@ class FalcoTest(Test): self.log.debug("Copying {} to {}".format(driver_path, module_path)) shutil.copyfile(driver_path, module_path) + def init_grpc_handler(self): + self.grpcurl_res = None + if len(self.grpc_results) > 0: + if not self.is_grpc_using_unix_socket: + self.fail("This test suite supports gRPC with unix socket only") + + cmdline = "grpcurl -import-path ../userspace/falco " \ + "-proto {} -plaintext -unix {} " \ + "{}/{}".format(self.grpc_proto, self.grpc_address, self.grpc_service, self.grpc_method) + that = self + class GRPCUnixSocketEventHandler(PatternMatchingEventHandler): + def on_created(self, event): + # that.log.info("EVENT: {}", event) + that.grpcurl_res = process.run(cmdline) + + path = os.path.dirname(self.grpc_address) + process.run("mkdir -p {}".format(path)) + event_handler = GRPCUnixSocketEventHandler(patterns=['*'], + ignore_directories=True) + self.grpc_observer = Observer() + self.grpc_observer.schedule(event_handler, path, recursive=False) + self.grpc_observer.start() + + def check_grpc(self): + if self.grpc_observer is not None: + self.grpc_observer.stop() + self.grpc_observer = None + if self.grpcurl_res is None: + self.fail("gRPC responses not found") + + for exp_result in self.grpc_results: + found = False + for line in self.grpcurl_res.stdout.decode("utf-8").splitlines(): + match = re.search(exp_result, line) + + if match is not None: + found = True + + if found == False: + self.fail("Could not find a line '{}' in gRPC responses".format(exp_result)) + + def test(self): self.log.info("Trace file %s", self.trace_file) @@ -437,6 +486,8 @@ class FalcoTest(Test): self.possibly_copy_driver() + self.init_grpc_handler() + if self.package != 'None': # This sets falco_binary_path as a side-effect. self.install_package() @@ -539,6 +590,7 @@ class FalcoTest(Test): self.check_detections_by_rule(res) self.check_json_output(res) self.check_outputs() + self.check_grpc() pass diff --git a/test/requirements.txt b/test/requirements.txt index 3bbeea3b..8134a110 100644 --- a/test/requirements.txt +++ b/test/requirements.txt @@ -3,9 +3,11 @@ avocado-framework-plugin-varianter-yaml-to-mux==69.0 certifi==2020.4.5.1 chardet==3.0.4 idna==2.9 +pathtools==0.1.2 pbr==5.4.5 PyYAML==5.3.1 requests==2.23.0 six==1.14.0 stevedore==1.32.0 urllib3==1.25.9 +watchdog==0.10.2 \ No newline at end of file