예제 #1
0
    def __init__(self, uwsgi_ini_file, servicelib_ini_file, pid_file, log_file,
                 scratch_dir):
        self.servicelib_ini_file = servicelib_ini_file
        self.pid_file = pid_file
        self.log_file = log_file
        self.host = "127.0.0.1"
        self.port = utils.available_port()

        servicelib_dir = Path(__file__, "..", "..").resolve()
        services_dir = servicelib_dir / "samples"

        self.uwsgi_ini = UWSGI_INI_TEMPLATE.format(
            host=self.host,
            log_file=log_file,
            pid_file=pid_file,
            port=self.port,
            services_dir=services_dir,
        )
        with open(uwsgi_ini_file, "wt") as f:
            f.write(self.uwsgi_ini)

        self.servicelib_ini = SERVICELIB_INI_TEMPLATE.format(
            host=self.host,
            port=self.port,
            scratch_dir=scratch_dir,
            services_dir=services_dir,
            uwsgi_config_file=uwsgi_ini_file,
        )
        with open(servicelib_ini_file, "wt") as f:
            f.write(self.servicelib_ini)

        scratch_dir.mkdir(parents=True, exist_ok=True)
예제 #2
0
    def __exit__(self, *exc_info):
        # self.log.debug("uwsgi.ini:\n%s", self.uwsgi_ini)
        # self.log.debug("servicelib.ini:\n%s", self.servicelib_ini)
        try:
            with open(self.log_file, "rt") as f:
                self.log.debug("uwsgi.log:\n%s", f.read())
        except Exception:
            pass

        with open(self.pid_file, "rt") as f:
            pid = int(f.read().strip())
        os.kill(pid, signal.SIGTERM)
예제 #3
0
    def start(self, background=True):
        with open(self.config_file, "wb") as f:
            yaml.safe_dump(self.initial_config,
                           f,
                           encoding="utf-8",
                           allow_unicode=True)

        cmdline = [
            "servicelib-config-server",
            "--port",
            self.port,
            "--log-file",
            self.log_file,
            "--config-file",
            self.config_file,
        ]
        if background:
            cmdline.extend([
                "--pid-file",
                self.pid_file,
            ])
        if self.read_only:
            cmdline.append("--read-only")
        cmdline = " ".join(str(c) for c in cmdline)

        p = subprocess.Popen(cmdline, shell=True)
        if background:
            rc = p.wait()
            if rc:
                raise Exception("Error running {}".format(cmdline))
        else:
            self.p = p

        utils.wait_for_url(self.client.url)
예제 #4
0
    def __enter__(self):
        env = dict(os.environ)
        env["SERVICELIB_CONFIG_URL"] = self.servicelib_yaml_file.resolve(
        ).as_uri()
        cmdline = ["servicelib-worker"]
        cmdline.extend(self.cmdline_args)
        p = subprocess.Popen(
            " ".join(cmdline),
            shell=True,
            env=env,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
        )
        stdout, _ = p.communicate()
        if p.returncode:
            raise Exception(stdout)
        try:
            utils.wait_for_url("http://{}:{}/health".format(
                self.host, self.port))
        except Exception as exc:
            try:
                with open(self.log_file, "rt") as f:
                    exc = Exception(f.read())
            except Exception:
                pass
            raise exc

        return self
예제 #5
0
    def stop(self):
        try:
            if self.p is not None:
                self.p.terminate()
                self.p.wait()
            else:
                with open(self.pid_file, "rt") as f:
                    pid = int(f.read().strip())
                os.kill(pid, signal.SIGTERM)
        except Exception:
            pass

        try:
            with open(self.log_file, "rt") as f:
                self.log.debug("uwsgi.log:\n%s", f.read())
        except Exception:
            pass
예제 #6
0
def test_handle_signals_in_spawn_process(context, tmp_path):
    script = tmp_path / "script.py"
    with open(script, "wt") as f:
        f.write(SLEEP_PY)

    pid_file = tmp_path / "script.pid"
    cmdline = [sys.executable, str(script), str(pid_file)]

    class p(process.Process):
        def __init__(self):
            super(p, self).__init__("sleep", cmdline)

        def results(self):
            return self.output.decode("utf-8")

    result = []

    def spawn():
        try:
            res = context.spawn_process(p())
            result.append(res)
        except Exception as exc:
            result.append(exc)

    t = threading.Thread(target=spawn)
    t.start()

    time.sleep(1)

    with open(pid_file, "rt") as f:
        pid = int(f.read().strip())

    os.kill(pid, signal.SIGTERM)
    t.join()

    assert isinstance(result[0], Exception)
    assert str(result[0]).startswith("'sleep' killed by signal")
예제 #7
0
def test_interleaved_output_in_spawn_process(context, tmp_path):
    script = tmp_path / "script.py"
    with open(script, "wt") as f:
        f.write(STDERR_PY)

    pid_file = tmp_path / "script.pid"
    cmdline = [sys.executable, str(script), str(pid_file)]

    class p(process.Process):
        def __init__(self):
            super(p, self).__init__("stderr", cmdline)

        def results(self):
            return self.output.decode("utf-8")

    res = context.spawn_process(p())
    assert res == "foo\nbar\nbaz\n"
예제 #8
0
def test_spawn_process_with_unlimited_output(context, tmp_path):
    zeroes = tmp_path / "zeroes"
    cmdline = ["cat", str(zeroes)]

    class p(process.Process):

        max_output_size = 0

        def __init__(self):
            super(p, self).__init__("cat-zeores", cmdline)

        def results(self):
            return self.output.decode("utf-8")

    with open(zeroes, "wb") as f:
        f.write(("0" * process.DEFAULT_MAX_PROCESS_OUTPUT_SIZE).encode("utf-8"))

    res = context.spawn_process(p())
    assert res == "0" * zeroes.stat().st_size
예제 #9
0
def test_spawn_process_with_truncated_output(context, tmp_path):
    zeroes = tmp_path / "zeroes"
    cmdline = ["cat", str(zeroes)]

    class p(process.Process):

        max_output_size = 42

        def __init__(self):
            super(p, self).__init__("cat-zeroes", cmdline)

        def results(self):
            return self.output.decode("utf-8")

    with open(zeroes, "wb") as f:
        f.write(("0" * p.max_output_size).encode("utf-8"))
        f.write("and some extra data which will be truncated".encode("utf-8"))

    res = context.spawn_process(p())
    assert res == "0" * p.max_output_size
예제 #10
0
def test_spawn_process_with_truncated_output_2(context, tmp_path):
    foo_bar = tmp_path / "foo-bar"
    cmdline = ["cat", str(foo_bar)]

    # The newline in the output will trigger two calls to the process object's
    # `stdout_data`, the first one of which fill fill the output capacity.
    with open(foo_bar, "wb") as f:
        f.write("foo\nbar".encode("utf-8"))

    class p(process.Process):

        max_output_size = 3

        def __init__(self):
            super(p, self).__init__("cat-foo-bar", cmdline)

        def results(self):
            return self.output.decode("utf-8")

    res = context.spawn_process(p())
    assert res == "foo"
예제 #11
0
 def _open(self):
     self._file_obj = open(self._path, "wb", buffering=0)
예제 #12
0
def test_diff(tmp_path, script_runner):
    config_a = tmp_path / "config-a.yaml"
    with open(config_a, "wb") as f:
        yaml.safe_dump(
            {
                "foo": 24,
                "bzzz": 17,
                "bar": {
                    "bazz": [
                        True,
                        False,
                    ],
                    "boo": [
                        "some-string",
                        {
                            "a-float": 42.0
                        },
                        ["one", "nested", "list"],
                    ],
                },
                "boo": True,
            },
            f,
            encoding="utf-8",
            allow_unicode=True,
        )

    config_b = tmp_path / "config-b.yaml"
    with open(config_b, "wb") as f:
        yaml.safe_dump(
            {
                "bar": {
                    "bazz": [
                        False,
                        True,
                    ],
                    "boo": [
                        "some-string",
                        {
                            "a-float": 42.0
                        },
                        ["one", "nested", "list", "but", "longer"],
                    ],
                    "moo":
                    24,
                },
                "foo": 42,
                "boo": True,
            },
            f,
            encoding="utf-8",
            allow_unicode=True,
        )

    expected = _EXPECTED_DIFF.format(config_a=config_a.as_uri(),
                                     config_b=config_b.as_uri()).strip()
    r = script_runner.run("servicelib-config-client", "diff",
                          config_a.as_uri(), config_b.as_uri())
    assert r.success
    assert r.stdout.strip() == expected
    assert r.stderr == ""
예제 #13
0
    def __init__(self, uwsgi_ini_file, servicelib_yaml_file, pid_file,
                 log_file, scratch_dir, *cmdline_args):
        self.servicelib_yaml_file = servicelib_yaml_file
        self.pid_file = pid_file
        self.log_file = log_file
        self.host = "127.0.0.1"
        self.port = utils.available_port()

        # Some tests in `tests/test_client.py` call service `proxy`, which
        # calls other services. We need several uWSGI processes to be ready
        # to accept requests.
        self.num_processes = 4

        # Set to 1 because we're assuming `servicelib` (and the services built
        # upon it) are not thread-safe.
        #
        # We do want to set it explicitly to 1, so that Python's threading
        # machinery gets initialised.
        self.num_threads = 1

        scratch_dir.mkdir(parents=True, exist_ok=True)

        servicelib_dir = Path(__file__, "..", "..").resolve()
        scratch_dir = str(scratch_dir)
        uwsgi_ini_file = str(uwsgi_ini_file)

        for a in cmdline_args:
            if a.startswith("--worker-services-dir="):
                services_dir = a[len("--worker-services-dir="):]
                break
        else:
            services_dir = str(servicelib_dir / "samples")

        self.uwsgi_ini = UWSGI_INI_TEMPLATE.format(
            host=self.host,
            log_file=log_file,
            num_processes=self.num_processes,
            num_threads=self.num_threads,
            pid_file=pid_file,
            port=self.port,
            services_dir=services_dir,
        )
        with open(uwsgi_ini_file, "wt") as f:
            f.write(self.uwsgi_ini)

        self.servicelib_conf = {
            "worker": {
                "hostname": self.host,
                "port": self.port,
                "serve_results": scratch_dir,
                "services_dir": services_dir,
                "static_map": "/services-source-code={}".format(services_dir),
                "swagger_ui_path": "{}/swagger-ui".format(services_dir),
                "uwsgi_config_file": uwsgi_ini_file,
            },
            "inventory": {
                "class": "default",
            },
            "registry": {
                "class": "redis",
                "url": "redis://localhost/0",
            },
            "cache": {
                "class": "memcached",
                "memcached_addresses": ["localhost:11211"],
            },
            "log": {
                "level": "debug",
                "type": "text",
            },
            "results": {
                "class": "http-files",
                "dirs": [scratch_dir],
                "http_hostname": self.host,
            },
            "scratch": {
                "strategy": "random",
                "dirs": [scratch_dir],
            },
        }
        with open(servicelib_yaml_file, "wb") as f:
            yaml.safe_dump(self.servicelib_conf,
                           f,
                           encoding="utf-8",
                           allow_unicode=True)

        self.cmdline_args = cmdline_args