Ejemplo n.º 1
0
    def test_defaults_multiline(self):
        out = FakeOutput()
        p = Printer(output=out, env=FakeEnv())
        p.write("one\ntwo\nthree")

        expect = "12:42:00 unknown | one\n12:42:00 unknown | two\n12:42:00 unknown | three"
        self.assertEqual(expect, out.last_write())
Ejemplo n.º 2
0
def command_start(args):
    procfile_path = _procfile_path(args.app_root, _choose_procfile(args))
    procfile = _procfile(procfile_path)

    concurrency = _parse_concurrency(args.concurrency)
    env = _read_env(args.app_root, args.env)
    quiet = _parse_quiet(args.quiet)
    port = _choose_port(args, env)

    if args.processes:
        processes = compat.OrderedDict()
        for name in args.processes:
            try:
                processes[name] = procfile.processes[name]
            except KeyError:
                raise CommandError("Process type '{0}' does not exist in Procfile".format(name))
    else:
        processes = procfile.processes

    manager = Manager(Printer(sys.stdout,
                              colour=(not args.no_colour),
                              prefix=(not args.no_prefix)))

    for p in environ.expand_processes(processes,
                                      concurrency=concurrency,
                                      env=env,
                                      quiet=quiet,
                                      port=port):
        e = os.environ.copy()
        e.update(p.env)
        manager.add_process(p.name, p.cmd, quiet=p.quiet, env=e)

    manager.loop()
    sys.exit(manager.returncode)
Ejemplo n.º 3
0
class TestPrinter(object):
    def setup(self):
        self.out = MagicMock()

        self._dt_patch = patch('honcho.printer.datetime')
        self._dt = self._dt_patch.start()
        self._dt.now.return_value = datetime.datetime(2012, 8, 11, 12, 42)

    def teardown(self):
        self._dt_patch.stop()

    def test_defaults_simple(self):
        self.p = Printer(output=self.out)
        self.p.write("monkeys")
        self.out.write.assert_called_once_with("12:42:00 unknown | monkeys")

    def test_defaults_multiline(self):
        self.p = Printer(output=self.out)
        self.p.write("one\ntwo\nthree")

        expect = "12:42:00 unknown | one\n12:42:00 unknown | two\n12:42:00 unknown | three"
        self.out.write.assert_called_once_with(expect)

    def test_name_simple(self):
        self.p = Printer(output=self.out, name="Robert Louis Stevenson")
        self.p.write("quiescent")
        self.out.write.assert_called_once_with(
            "12:42:00 Robert Louis Stevenson | quiescent")

    def test_length_simple(self):
        self.p = Printer(output=self.out, name="oop", width=6)
        self.p.write("narcissist")
        self.out.write.assert_called_once_with("12:42:00 oop    | narcissist")

    def test_colour_simple(self):
        self.p = Printer(output=self.out, name="red", colour="31")
        self.p.write("conflate")
        self.out.write.assert_called_once_with(
            "\033[31m12:42:00 red | \033[0mconflate")
Ejemplo n.º 4
0
class TestPrinter(object):
    def setup(self):
        self.out = MagicMock()

        self._dt_patch = patch('honcho.printer.datetime')
        self._dt = self._dt_patch.start()
        self._dt.now.return_value = datetime.datetime(2012, 8, 11, 12, 42)

    def teardown(self):
        self._dt_patch.stop()

    def test_defaults_simple(self):
        self.p = Printer(output=self.out)
        self.p.write("monkeys")
        self.out.write.assert_called_once_with("12:42:00 unknown | monkeys")

    def test_defaults_multiline(self):
        self.p = Printer(output=self.out)
        self.p.write("one\ntwo\nthree")

        expect = "12:42:00 unknown | one\n12:42:00 unknown | two\n12:42:00 unknown | three"
        self.out.write.assert_called_once_with(expect)

    def test_name_simple(self):
        self.p = Printer(output=self.out, name="Robert Louis Stevenson")
        self.p.write("quiescent")
        self.out.write.assert_called_once_with("12:42:00 Robert Louis Stevenson | quiescent")

    def test_length_simple(self):
        self.p = Printer(output=self.out, name="oop", width=6)
        self.p.write("narcissist")
        self.out.write.assert_called_once_with("12:42:00 oop    | narcissist")

    def test_colour_simple(self):
        self.p = Printer(output=self.out, name="red", colour="31")
        self.p.write("conflate")
        self.out.write.assert_called_once_with("\033[31m12:42:00 red | \033[0mconflate")
Ejemplo n.º 5
0
 def test_write_with_colour_non_tty(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("conflate\n", name="foo", colour="31"))
     assert out.string() == "12:42:00 foo | conflate\n"
Ejemplo n.º 6
0
 def test_write_with_name(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("quiescent\n", name="Robert Louis Stevenson"))
     assert out.string() == "12:42:00 Robert Louis Stevenson | quiescent\n"
Ejemplo n.º 7
0
 def test_write_with_name_and_set_width(self):
     out = FakeOutput()
     p = Printer(output=out, width=6)
     p.write(fake_message("narcissist\n", name="oop"))
     assert out.string() == "12:42:00 oop    | narcissist\n"
Ejemplo n.º 8
0
 def test_write_wrong_type(self):
     out = FakeOutput()
     p = Printer(output=out)
     with pytest.raises(RuntimeError):
         p.write(fake_message("monkeys\n", type="error"))
Ejemplo n.º 9
0
 def test_write_no_newline(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("monkeys"))
     assert out.string() == "12:42:00 | monkeys\n"
Ejemplo n.º 10
0
 def test_length_simple(self):
     out = FakeOutput()
     p = Printer(output=out, name="oop", width=6, env=FakeEnv())
     p.write("narcissist")
     self.assertEqual("12:42:00 oop    | narcissist", out.last_write())
Ejemplo n.º 11
0
 def test_colour_simple(self):
     self.p = Printer(output=self.out, name="red", colour="31")
     self.p.write("conflate")
     self.out.write.assert_called_once_with(
         "\033[31m12:42:00 red | \033[0mconflate")
Ejemplo n.º 12
0
 def test_colour_simple(self):
     self.p = Printer(output=self.out, name="red", colour="31")
     self.p.write("conflate")
     self.out.write.assert_called_once_with("\033[31m12:42:00 red | \033[0mconflate")
Ejemplo n.º 13
0
 def test_defaults_simple(self):
     self.p = Printer(output=self.out)
     self.p.write("monkeys")
     self.out.write.assert_called_once_with("12:42:00 unknown | monkeys")
Ejemplo n.º 14
0
 def test_name_simple(self):
     self.p = Printer(output=self.out, name="Robert Louis Stevenson")
     self.p.write("quiescent")
     self.out.write.assert_called_once_with("12:42:00 Robert Louis Stevenson | quiescent")
Ejemplo n.º 15
0
 def test_length_simple(self):
     self.p = Printer(output=self.out, name="oop", width=6)
     self.p.write("narcissist")
     self.out.write.assert_called_once_with("12:42:00 oop    | narcissist")
Ejemplo n.º 16
0
    def test_defaults_multiline(self):
        self.p = Printer(output=self.out)
        self.p.write("one\ntwo\nthree")

        expect = "12:42:00 unknown | one\n12:42:00 unknown | two\n12:42:00 unknown | three"
        self.out.write.assert_called_once_with(expect)
Ejemplo n.º 17
0
 def test_defaults_simple(self):
     self.p = Printer(output=self.out)
     self.p.write("monkeys")
     self.out.write.assert_called_once_with("12:42:00 unknown | monkeys")
Ejemplo n.º 18
0
 def test_name_simple(self):
     self.p = Printer(output=self.out, name="Robert Louis Stevenson")
     self.p.write("quiescent")
     self.out.write.assert_called_once_with(
         "12:42:00 Robert Louis Stevenson | quiescent")
def devserver(reload, watchers, workers, browser_reload, styleguide, prefix,
              environment, bind):
    "Starts a lightweight web server for development."
    if ':' in bind:
        host, port = bind.split(':', 1)
        port = int(port)
    else:
        host = bind
        port = None

    import os

    os.environ['SENTRY_ENVIRONMENT'] = environment

    from django.conf import settings
    from sentry import options
    from sentry.services.http import SentryHTTPServer

    url_prefix = options.get('system.url-prefix', '')
    parsed_url = urlparse(url_prefix)
    # Make sure we're trying to use a port that we can actually bind to
    needs_https = (parsed_url.scheme == 'https'
                   and (parsed_url.port or 443) > 1024)
    has_https = False

    if needs_https:
        from subprocess import check_output
        try:
            check_output(['which', 'https'])
            has_https = True
        except Exception:
            has_https = False
            from sentry.runner.initializer import show_big_error
            show_big_error([
                'missing `https` on your `$PATH`, but https is needed',
                '`$ brew install mattrobenolt/stuff/https`',
            ])

    uwsgi_overrides = {
        # Make sure we don't try and use uwsgi protocol
        'protocol': 'http',
        # Make sure we reload really quickly for local dev in case it
        # doesn't want to shut down nicely on it's own, NO MERCY
        'worker-reload-mercy': 2,
        # We need stdin to support pdb in devserver
        'honour-stdin': True,
        # accept ridiculously large files
        'limit-post': 1 << 30,
        # do something with chunked
        'http-chunked-input': True,
    }

    if reload:
        uwsgi_overrides['py-autoreload'] = 1

    daemons = []

    if watchers and not browser_reload:
        daemons += settings.SENTRY_WATCHERS

    # For javascript dev, if browser reload and watchers, then:
    # devserver listen on PORT + 1
    # webpack dev server listen on PORT + 2
    # proxy listen on PORT
    if watchers and browser_reload:
        new_port = port + 1
        os.environ['WEBPACK_DEV_PROXY'] = '%s' % port
        os.environ['WEBPACK_DEV_PORT'] = '%s' % (new_port + 1)
        os.environ['SENTRY_DEVSERVER_PORT'] = '%s' % new_port
        port = new_port

        daemons += [('jsproxy', ['yarn', 'dev-proxy']),
                    ('webpack', ['yarn', 'dev-server'])]

    if workers:
        if settings.CELERY_ALWAYS_EAGER:
            raise click.ClickException(
                'Disable CELERY_ALWAYS_EAGER in your settings file to spawn workers.'
            )

        daemons += [
            ('worker', ['sentry', 'run', 'worker', '-c', '1', '--autoreload']),
            ('cron', ['sentry', 'run', 'cron', '--autoreload']),
        ]

    if needs_https and has_https:
        https_port = six.text_type(parsed_url.port)
        https_host = parsed_url.hostname

        # Determine a random port for the backend http server
        import socket
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind((host, 0))
        port = s.getsockname()[1]
        s.close()
        bind = '%s:%d' % (host, port)

        daemons += [
            ('https', [
                'https', '-host', https_host, '-listen',
                host + ':' + https_port, bind
            ]),
        ]

    # A better log-format for local dev when running through honcho,
    # but if there aren't any other daemons, we don't want to override.
    if daemons:
        uwsgi_overrides[
            'log-format'] = '"%(method) %(uri) %(proto)" %(status) %(size)'
    else:
        uwsgi_overrides[
            'log-format'] = '[%(ltime)] "%(method) %(uri) %(proto)" %(status) %(size)'

    server = SentryHTTPServer(host=host,
                              port=port,
                              workers=1,
                              extra_options=uwsgi_overrides)

    # If we don't need any other daemons, just launch a normal uwsgi webserver
    # and avoid dealing with subprocesses
    if not daemons:
        return server.run()

    import sys
    from subprocess import list2cmdline
    from honcho.manager import Manager
    from honcho.printer import Printer

    os.environ['PYTHONUNBUFFERED'] = 'true'

    # Make sure that the environment is prepared before honcho takes over
    # This sets all the appropriate uwsgi env vars, etc
    server.prepare_environment()
    daemons += [
        ('server', ['sentry', 'run', 'web']),
    ]

    if styleguide:
        daemons += [('storybook', ['yarn', 'storybook'])]

    cwd = os.path.realpath(
        os.path.join(settings.PROJECT_ROOT, os.pardir, os.pardir))

    manager = Manager(Printer(prefix=prefix))
    for name, cmd in daemons:
        manager.add_process(
            name,
            list2cmdline(cmd),
            quiet=False,
            cwd=cwd,
        )

    manager.loop()
    sys.exit(manager.returncode)
Ejemplo n.º 20
0
 def test_write_with_name(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("quiescent\n", name="Robert Louis Stevenson"))
     self.assertEqual("12:42:00 Robert Louis Stevenson | quiescent\n",
                      out.string())
Ejemplo n.º 21
0
    def test_defaults_multiline(self):
        self.p = Printer(output=self.out)
        self.p.write("one\ntwo\nthree")

        expect = "12:42:00 unknown | one\n12:42:00 unknown | two\n12:42:00 unknown | three"
        self.out.write.assert_called_once_with(expect)
Ejemplo n.º 22
0
 def test_write_with_name_and_set_width(self):
     out = FakeOutput()
     p = Printer(output=out, width=6)
     p.write(fake_message("narcissist\n", name="oop"))
     self.assertEqual("12:42:00 oop    | narcissist\n", out.string())
Ejemplo n.º 23
0
def devserver(reload, watchers, workers, experimental_spa, styleguide, prefix, environment, bind):
    "Starts a lightweight web server for development."
    if ":" in bind:
        host, port = bind.split(":", 1)
        port = int(port)
    else:
        host = bind
        port = None

    import os

    os.environ["SENTRY_ENVIRONMENT"] = environment

    from django.conf import settings
    from sentry import options
    from sentry.services.http import SentryHTTPServer

    url_prefix = options.get("system.url-prefix", "")
    parsed_url = urlparse(url_prefix)
    # Make sure we're trying to use a port that we can actually bind to
    needs_https = parsed_url.scheme == "https" and (parsed_url.port or 443) > 1024
    has_https = False

    if needs_https:
        from subprocess import check_output

        try:
            check_output(["which", "https"])
            has_https = True
        except Exception:
            has_https = False
            from sentry.runner.initializer import show_big_error

            show_big_error(
                [
                    "missing `https` on your `$PATH`, but https is needed",
                    "`$ brew install mattrobenolt/stuff/https`",
                ]
            )

    uwsgi_overrides = {
        # Make sure we don't try and use uwsgi protocol
        "protocol": "http",
        # Make sure we reload really quickly for local dev in case it
        # doesn't want to shut down nicely on it's own, NO MERCY
        "worker-reload-mercy": 2,
        # We need stdin to support pdb in devserver
        "honour-stdin": True,
        # accept ridiculously large files
        "limit-post": 1 << 30,
        # do something with chunked
        "http-chunked-input": True,
        "thunder-lock": False,
        "timeout": 600,
        "harakiri": 600,
    }

    if reload:
        uwsgi_overrides["py-autoreload"] = 1

    daemons = []

    if experimental_spa:
        os.environ["SENTRY_EXPERIMENTAL_SPA"] = "1"
        if not watchers:
            click.secho(
                "Using experimental SPA mode without watchers enabled has no effect",
                err=True,
                fg="yellow",
            )

    # We proxy all requests through webpacks devserver on the configured port.
    # The backend is served on port+1 and is proxied via the webpack
    # configuration.
    if watchers:
        daemons += settings.SENTRY_WATCHERS

        proxy_port = port
        port = port + 1

        os.environ["SENTRY_WEBPACK_PROXY_PORT"] = "%s" % proxy_port
        os.environ["SENTRY_BACKEND_PORT"] = "%s" % port

        # Replace the webpack watcher with the drop-in webpack-dev-server
        webpack_config = next(w for w in daemons if w[0] == "webpack")[1]
        webpack_config[0] = os.path.join(
            *os.path.split(webpack_config[0])[0:-1] + ("webpack-dev-server",)
        )

        daemons = [w for w in daemons if w[0] != "webpack"] + [("webpack", webpack_config)]

    if workers:
        if settings.CELERY_ALWAYS_EAGER:
            raise click.ClickException(
                "Disable CELERY_ALWAYS_EAGER in your settings file to spawn workers."
            )

        daemons += [
            ("worker", ["sentry", "run", "worker", "-c", "1", "--autoreload"]),
            ("cron", ["sentry", "run", "cron", "--autoreload"]),
        ]

        from sentry import eventstream

        if eventstream.requires_post_process_forwarder():
            daemons += [
                (
                    "relay",
                    [
                        "sentry",
                        "run",
                        "post-process-forwarder",
                        "--loglevel=debug",
                        "--commit-batch-size=1",
                    ],
                )
            ]

    if needs_https and has_https:
        https_port = six.text_type(parsed_url.port)
        https_host = parsed_url.hostname

        # Determine a random port for the backend http server
        import socket

        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind((host, 0))
        port = s.getsockname()[1]
        s.close()
        bind = "%s:%d" % (host, port)

        daemons += [
            ("https", ["https", "-host", https_host, "-listen", host + ":" + https_port, bind])
        ]

    # A better log-format for local dev when running through honcho,
    # but if there aren't any other daemons, we don't want to override.
    if daemons:
        uwsgi_overrides["log-format"] = '"%(method) %(uri) %(proto)" %(status) %(size)'
    else:
        uwsgi_overrides["log-format"] = '[%(ltime)] "%(method) %(uri) %(proto)" %(status) %(size)'

    server = SentryHTTPServer(host=host, port=port, workers=1, extra_options=uwsgi_overrides)

    # If we don't need any other daemons, just launch a normal uwsgi webserver
    # and avoid dealing with subprocesses
    if not daemons:
        return server.run()

    import sys
    from subprocess import list2cmdline
    from honcho.manager import Manager
    from honcho.printer import Printer

    os.environ["PYTHONUNBUFFERED"] = "true"

    # Make sure that the environment is prepared before honcho takes over
    # This sets all the appropriate uwsgi env vars, etc
    server.prepare_environment()
    daemons += [("server", ["sentry", "run", "web"])]

    if styleguide:
        daemons += [("storybook", ["./bin/yarn", "storybook"])]

    cwd = os.path.realpath(os.path.join(settings.PROJECT_ROOT, os.pardir, os.pardir))

    manager = Manager(Printer(prefix=prefix))
    for name, cmd in daemons:
        manager.add_process(name, list2cmdline(cmd), quiet=False, cwd=cwd)

    manager.loop()
    sys.exit(manager.returncode)
Ejemplo n.º 24
0
 def test_length_simple(self):
     self.p = Printer(output=self.out, name="oop", width=6)
     self.p.write("narcissist")
     self.out.write.assert_called_once_with("12:42:00 oop    | narcissist")
Ejemplo n.º 25
0
 def test_write_multiline(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("one\ntwo\nthree\n"))
     expect = "12:42:00 | one\n12:42:00 | two\n12:42:00 | three\n"
     self.assertEqual(expect, out.string())
Ejemplo n.º 26
0
 def test_write_without_colour_tty(self):
     out = FakeTTY()
     p = Printer(output=out, prefix=True, colour=False)
     p.write(fake_message("paranoid android\n", name="foo", colour="31"))
     assert out.string() == "12:42:00 foo | paranoid android\n"
Ejemplo n.º 27
0
 def test_write_with_set_width(self):
     out = FakeOutput()
     p = Printer(output=out, width=6)
     p.write(fake_message("giraffe\n"))
     self.assertEqual("12:42:00        | giraffe\n", out.string())
Ejemplo n.º 28
0
 def test_write_without_prefix_non_tty(self):
     out = FakeOutput()
     p = Printer(output=out, prefix=False)
     p.write(fake_message("paranoid android\n", name="foo", colour="31"))
     assert out.string() == "paranoid android\n"
Ejemplo n.º 29
0
 def test_write_with_colour(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("conflate\n", name="foo", colour="31"))
     self.assertEqual("\033[31m12:42:00 foo | \033[0mconflate\n",
                      out.string())
Ejemplo n.º 30
0
 def test_write_with_colour_tty(self):
     out = FakeTTY()
     p = Printer(output=out)
     p.write(fake_message("conflate\n", name="foo", colour="31"))
     assert out.string() == "\033[0m\033[31m12:42:00 foo | \033[0mconflate\n"
Ejemplo n.º 31
0
 def test_write_invalid_utf8(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message(b"\xfe\xff\n"))
     assert out.string() == "12:42:00 | \ufffd\ufffd\n"
Ejemplo n.º 32
0
 def test_write_with_colour_non_tty(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("conflate\n", name="foo", colour="31"))
     assert out.string() == "12:42:00 foo | conflate\n"
Ejemplo n.º 33
0
 def test_write_multiline(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("one\ntwo\nthree\n"))
     expect = "12:42:00 | one\n12:42:00 | two\n12:42:00 | three\n"
     assert out.string() == expect
Ejemplo n.º 34
0
 def test_write(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("monkeys\n"))
     assert out.string() == "12:42:00 | monkeys\n"
Ejemplo n.º 35
0
 def test_write_with_set_width(self):
     out = FakeOutput()
     p = Printer(output=out, width=6)
     p.write(fake_message("giraffe\n"))
     assert out.string() == "12:42:00        | giraffe\n"
Ejemplo n.º 36
0
 def test_write_wrong_type(self):
     out = FakeOutput()
     p = Printer(output=out)
     with pytest.raises(RuntimeError):
         p.write(fake_message("monkeys\n", type="error"))
Ejemplo n.º 37
0
 def test_write_with_colour_tty(self):
     out = FakeTTY()
     p = Printer(output=out)
     p.write(fake_message("conflate\n", name="foo", colour="31"))
     assert out.string(
     ) == "\033[0m\033[31m12:42:00 foo | \033[0mconflate\n"
Ejemplo n.º 38
0
 def test_write(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("monkeys\n"))
     self.assertEqual("12:42:00 | monkeys\n", out.string())
Ejemplo n.º 39
0
 def test_write_without_prefix_tty(self):
     out = FakeTTY()
     p = Printer(output=out, prefix=False, colour=True)
     p.write(fake_message("paranoid android\n", name="foo", colour="31"))
     assert out.string() == "paranoid android\n"
Ejemplo n.º 40
0
 def test_write_wrong_type(self):
     out = FakeOutput()
     p = Printer(output=out)
     self.assertRaises(RuntimeError, p.write,
                       fake_message("monkeys\n", type="error"))
Ejemplo n.º 41
0
 def test_defaults_simple(self):
     out = FakeOutput()
     p = Printer(output=out, env=FakeEnv())
     p.write("monkeys")
     self.assertEqual("12:42:00 unknown | monkeys", out.last_write())
Ejemplo n.º 42
0
 def test_write_with_colour(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("conflate\n", name="foo", colour="31"))
     self.assertEqual("\033[31m12:42:00 foo | \033[0mconflate\n",
                      out.string())
Ejemplo n.º 43
0
 def test_name_simple(self):
     out = FakeOutput()
     p = Printer(output=out, name="Robert Louis Stevenson", env=FakeEnv())
     p.write("quiescent")
     self.assertEqual("12:42:00 Robert Louis Stevenson | quiescent",
                      out.last_write())
Ejemplo n.º 44
0
 def test_write_invalid_utf8(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message(b"\xfe\xff\n"))
     self.assertEqual("12:42:00 | \ufffd\ufffd\n", out.string())
Ejemplo n.º 45
0
 def test_colour_simple(self):
     out = FakeOutput()
     p = Printer(output=out, name="red", colour="31", env=FakeEnv())
     p.write("conflate")
     self.assertEqual("\033[31m12:42:00 red | \033[0mconflate",
                      out.last_write())
Ejemplo n.º 46
0
 def test_write_no_newline(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("monkeys"))
     self.assertEqual("12:42:00 | monkeys\n", out.string())
Ejemplo n.º 47
0
def devserver(
    reload,
    watchers,
    workers,
    experimental_spa,
    styleguide,
    prefix,
    pretty,
    environment,
    debug_server,
    bind,
):
    "Starts a lightweight web server for development."

    if bind is None:
        bind = "127.0.0.1:8000"

    if ":" in bind:
        host, port = bind.split(":", 1)
        port = int(port)
    else:
        host = bind
        port = None

    import os

    os.environ["SENTRY_ENVIRONMENT"] = environment
    # NODE_ENV *must* use production for any prod-like environment as third party libraries look
    # for this magic constant
    os.environ["NODE_ENV"] = "production" if environment.startswith(
        "prod") else environment

    from django.conf import settings
    from sentry import options
    from sentry.services.http import SentryHTTPServer

    url_prefix = options.get("system.url-prefix", "")
    parsed_url = urlparse(url_prefix)
    # Make sure we're trying to use a port that we can actually bind to
    needs_https = parsed_url.scheme == "https" and (parsed_url.port
                                                    or 443) > 1024
    has_https = False

    if needs_https:
        from subprocess import check_output

        try:
            check_output(["which", "https"])
            has_https = True
        except Exception:
            has_https = False
            from sentry.runner.initializer import show_big_error

            show_big_error([
                "missing `https` on your `$PATH`, but https is needed",
                "`$ brew install mattrobenolt/stuff/https`",
            ])

    uwsgi_overrides = {
        "http-keepalive": True,
        # Make sure we reload really quickly for local dev in case it
        # doesn't want to shut down nicely on it's own, NO MERCY
        "worker-reload-mercy": 2,
        # We need stdin to support pdb in devserver
        "honour-stdin": True,
        # accept ridiculously large files
        "limit-post": 1 << 30,
        # do something with chunked
        "http-chunked-input": True,
        "thunder-lock": False,
        "timeout": 600,
        "harakiri": 600,
    }

    if reload:
        uwsgi_overrides["py-autoreload"] = 1

    daemons = []

    if experimental_spa:
        os.environ["SENTRY_UI_DEV_ONLY"] = "1"
        if not watchers:
            click.secho(
                "Using experimental SPA mode without watchers enabled has no effect",
                err=True,
                fg="yellow",
            )

    # We proxy all requests through webpacks devserver on the configured port.
    # The backend is served on port+1 and is proxied via the webpack
    # configuration.
    if watchers:
        daemons += settings.SENTRY_WATCHERS

        proxy_port = port
        port = port + 1

        uwsgi_overrides["protocol"] = "http"

        os.environ["FORCE_WEBPACK_DEV_SERVER"] = "1"
        os.environ["SENTRY_WEBPACK_PROXY_PORT"] = "%s" % proxy_port
        os.environ["SENTRY_BACKEND_PORT"] = "%s" % port

        # webpack and/or typescript is causing memory issues
        os.environ["NODE_OPTIONS"] = ((os.environ.get("NODE_OPTIONS", "") +
                                       " --max-old-space-size=4096")).lstrip()

        # Replace the webpack watcher with the drop-in webpack-dev-server
        webpack_config = next(w for w in daemons if w[0] == "webpack")[1]
        webpack_config[0] = os.path.join(
            *os.path.split(webpack_config[0])[0:-1] + ("webpack-dev-server", ))

        daemons = [w for w in daemons if w[0] != "webpack"
                   ] + [("webpack", webpack_config)]
    else:
        # If we are the bare http server, use the http option with uwsgi protocol
        # See https://uwsgi-docs.readthedocs.io/en/latest/HTTP.html
        uwsgi_overrides.update({
            # Make sure uWSGI spawns an HTTP server for us as we don't
            # have a proxy/load-balancer in front in dev mode.
            "http": "%s:%s" % (host, port),
            "protocol": "uwsgi",
            # This is needed to prevent https://git.io/fj7Lw
            "uwsgi-socket": None,
        })

    if workers:
        if settings.CELERY_ALWAYS_EAGER:
            raise click.ClickException(
                "Disable CELERY_ALWAYS_EAGER in your settings file to spawn workers."
            )

        daemons += [_get_daemon("worker"), _get_daemon("cron")]

        from sentry import eventstream

        if eventstream.requires_post_process_forwarder():
            daemons += [_get_daemon("post-process-forwarder")]

        if settings.SENTRY_DEV_PROCESS_SUBSCRIPTIONS:
            if not settings.SENTRY_EVENTSTREAM == "sentry.eventstream.kafka.KafkaEventStream":
                raise click.ClickException(
                    "`SENTRY_DEV_PROCESS_SUBSCRIPTIONS` can only be used when "
                    "`SENTRY_EVENTSTREAM=sentry.eventstream.kafka.KafkaEventStream`."
                )
            for name, topic in settings.KAFKA_SUBSCRIPTION_RESULT_TOPICS.items(
            ):
                daemons += [
                    _get_daemon("subscription-consumer",
                                "--topic",
                                topic,
                                suffix=name)
                ]

    if settings.SENTRY_USE_RELAY:
        daemons += [_get_daemon("ingest")]

    if needs_https and has_https:
        https_port = six.text_type(parsed_url.port)
        https_host = parsed_url.hostname

        # Determine a random port for the backend http server
        import socket

        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind((host, 0))
        port = s.getsockname()[1]
        s.close()
        bind = "%s:%d" % (host, port)

        daemons += [("https", [
            "https", "-host", https_host, "-listen", host + ":" + https_port,
            bind
        ])]

    from sentry.runner.commands.devservices import _prepare_containers

    for name, container_options in _prepare_containers("sentry",
                                                       silent=True).items():
        if container_options.get("with_devserver", False):
            daemons += [(name,
                         ["sentry", "devservices", "attach", "--fast", name])]

    # A better log-format for local dev when running through honcho,
    # but if there aren't any other daemons, we don't want to override.
    if daemons:
        uwsgi_overrides[
            "log-format"] = "%(method) %(status) %(uri) %(proto) %(size)"
    else:
        uwsgi_overrides[
            "log-format"] = "[%(ltime)] %(method) %(status) %(uri) %(proto) %(size)"

    server = SentryHTTPServer(host=host,
                              port=port,
                              workers=1,
                              extra_options=uwsgi_overrides,
                              debug=debug_server)

    # If we don't need any other daemons, just launch a normal uwsgi webserver
    # and avoid dealing with subprocesses
    if not daemons:
        return server.run()

    import sys
    from subprocess import list2cmdline
    from honcho.manager import Manager
    from honcho.printer import Printer

    os.environ["PYTHONUNBUFFERED"] = "true"

    if debug_server:
        threading.Thread(target=server.run).start()
    else:
        # Make sure that the environment is prepared before honcho takes over
        # This sets all the appropriate uwsgi env vars, etc
        server.prepare_environment()
        daemons += [_get_daemon("server")]

    if styleguide:
        daemons += [_get_daemon("storybook")]

    cwd = os.path.realpath(
        os.path.join(settings.PROJECT_ROOT, os.pardir, os.pardir))

    honcho_printer = Printer(prefix=prefix)

    if pretty:
        from sentry.runner.formatting import monkeypatch_honcho_write

        honcho_printer.write = types.MethodType(monkeypatch_honcho_write,
                                                honcho_printer)

    manager = Manager(honcho_printer)
    for name, cmd in daemons:
        manager.add_process(name, list2cmdline(cmd), quiet=False, cwd=cwd)

    manager.loop()
    sys.exit(manager.returncode)
Ejemplo n.º 48
0
 def test_write_flushes_output(self):
     out = FakeOutput()
     p = Printer(output=out, prefix=False)
     p.write(fake_message("paranoid android\n"))
     assert out.flushcount == 1