From 3dd616ab8c24db0dd780306c25d3097f8dcaf1f8 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Thu, 22 Jul 2021 12:54:38 +0300 Subject: chore: add rustfmt.toml to force rustfmt to use 2018 edition My new Emacs config with rustic and rust-analyzer doesn't catch the setting in Config.toml, and complains that main is async. See also https://github.com/rust-lang/rustfmt/issues/4454 . Sponsored-by: author --- rustfmt.toml | 1 + 1 file changed, 1 insertion(+) create mode 100644 rustfmt.toml diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..c51666e --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +edition = "2018" \ No newline at end of file -- cgit v1.2.1 From 41c1a815c517472e2f3a076a307c2fc1d0175a10 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Thu, 22 Jul 2021 10:22:04 +0300 Subject: chore: tell shellcheck to not worry about unquoted variable In this case, not quoting is the right thing to do. Sponsored-by: author --- check | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/check b/check index b55a411..606241e 100755 --- a/check +++ b/check @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash set -eu @@ -48,9 +48,13 @@ docgen() { $hideok cargo build --all-targets if cargo --list | awk '{ print $1 }' | grep 'clippy$' > /dev/null then + # shellcheck disable=SC2086 cargo clippy $quiet fi + +# shellcheck disable=SC2086 $hideok cargo test $quiet + if cargo fmt --help > /dev/null 2> /dev/null then $hideok cargo fmt -- --check -- cgit v1.2.1 From a6cd8fb0c3f8310ffd86d00a63dff5b593a13446 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Thu, 22 Jul 2021 12:57:07 +0300 Subject: test: run test.py so it creates a log Sponsored-by: author --- check | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/check b/check index 606241e..272ee63 100755 --- a/check +++ b/check @@ -3,7 +3,6 @@ set -eu verbose=false -runtest=true moar=true while [ "$#" -gt 0 ] && $moar do @@ -12,10 +11,6 @@ do verbose=true shift 1 ;; - -c | --codegen) - runtest=false - shift 1 - ;; esac done @@ -33,12 +28,9 @@ fi codegen() { - local run= - if $runtest - then - run=--run - fi - $hideok subplot codegen "$1" --output "$2" $run + $hideok subplot codegen "$1" --output "$2" + rm -f test.log + $hideok python3 test.py --log test.log } docgen() { -- cgit v1.2.1 From dd6bf8292fbe53eac2c528ff613cd4420ba46655 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Thu, 22 Jul 2021 12:57:33 +0300 Subject: chore: don't vendor Subplot libraries Sponsored-by: author --- ewww.md | 12 +- subplot/daemon.py | 77 ------------- subplot/vendored/daemon.py | 262 ------------------------------------------- subplot/vendored/daemon.yaml | 37 ------ subplot/vendored/files.py | 194 -------------------------------- subplot/vendored/files.yaml | 83 -------------- subplot/vendored/runcmd.py | 252 ----------------------------------------- subplot/vendored/runcmd.yaml | 83 -------------- 8 files changed, 6 insertions(+), 994 deletions(-) delete mode 100644 subplot/daemon.py delete mode 100644 subplot/vendored/daemon.py delete mode 100644 subplot/vendored/daemon.yaml delete mode 100644 subplot/vendored/files.py delete mode 100644 subplot/vendored/files.yaml delete mode 100644 subplot/vendored/runcmd.py delete mode 100644 subplot/vendored/runcmd.yaml diff --git a/ewww.md b/ewww.md index d1c9faf..8de29d7 100644 --- a/ewww.md +++ b/ewww.md @@ -151,15 +151,15 @@ author: Lars Wirzenius template: python bindings: - subplot/ewww.yaml - - subplot/vendored/daemon.yaml - - subplot/vendored/files.yaml - - subplot/vendored/runcmd.yaml + - lib/daemon.yaml + - lib/files.yaml + - lib/runcmd.yaml functions: - subplot/ewww.py - subplot/http.py - - subplot/vendored/daemon.py - - subplot/vendored/files.py - - subplot/vendored/runcmd.py + - lib/daemon.py + - lib/files.py + - lib/runcmd.py classes: - scenario-disabled ... diff --git a/subplot/daemon.py b/subplot/daemon.py deleted file mode 100644 index 00c9d2d..0000000 --- a/subplot/daemon.py +++ /dev/null @@ -1,77 +0,0 @@ -############################################################################# -# Start and stop daemons, or background processes. - - -import logging -import os -import signal - - -# Start a process in the background. -def start_daemon(ctx, name, argv): - runcmd_run = globals()["runcmd_run"] - runcmd_exit_code_is = globals()["runcmd_exit_code_is"] - - logging.debug(f"Starting daemon {name}") - logging.debug(f" ctx={ctx.as_dict()}") - logging.debug(f" name={name}") - logging.debug(f" argv={argv}") - - if "daemon" not in ctx.as_dict(): - ctx["daemon"] = {} - assert name not in ctx["daemon"] - this = ctx["daemon"][name] = { - "pid-file": f"{name}.pid", - "stderr": f"{name}.stderr", - "stdout": f"{name}.stdout", - } - runcmd_run( - ctx, - [ - "/usr/sbin/daemonize", - "-c", - os.getcwd(), - "-p", - this["pid-file"], - "-e", - this["stderr"], - "-o", - this["stdout"], - ] - + argv, - ) - runcmd_exit_code_is(ctx, 0) - this["pid"] = int(open("ewww.pid").read().strip()) - assert process_exists(this["pid"]) - - logging.debug(f"Started daemon {name}") - logging.debug(f" ctx={ctx.as_dict()}") - - -# Stop a daemon. -def stop_daemon(ctx, name): - logging.debug(f"Stopping daemon {name}") - logging.debug(f" ctx={ctx.as_dict()}") - logging.debug(f" ctx['daemon']={ctx.as_dict()['daemon']}") - - this = ctx["daemon"][name] - terminate_process(this["pid"], signal.SIGKILL) - - -# Does a process exist? -def process_exists(pid): - try: - os.kill(pid, 0) - except ProcessLookupError: - return False - return True - - -# Terminate process. -def terminate_process(pid, signalno): - logging.debug(f"Terminating process {pid} with signal {signalno}") - try: - os.kill(pid, signalno) - except ProcessLookupError: - logging.debug("Process did not actually exist (anymore?)") - pass diff --git a/subplot/vendored/daemon.py b/subplot/vendored/daemon.py deleted file mode 100644 index 11f65bf..0000000 --- a/subplot/vendored/daemon.py +++ /dev/null @@ -1,262 +0,0 @@ -import logging -import os -import signal -import socket -import subprocess -import time - - -# A helper function for testing lib/daemon itself. -def _daemon_shell_script(ctx, filename=None): - get_file = globals()["get_file"] - data = get_file(filename) - with open(filename, "wb") as f: - f.write(data) - os.chmod(filename, 0o755) - - -# Start a daemon that will open a port on localhost. -def daemon_start_on_port(ctx, path=None, args=None, name=None, port=None): - _daemon_start(ctx, path=path, args=args, name=name) - daemon_wait_for_port("localhost", port) - - -# Start a daemon after a little wait. This is used only for testing the -# port-waiting code. -def _daemon_start_soonish(ctx, path=None, args=None, name=None, port=None): - _daemon_start(ctx, path=os.path.abspath(path), args=args, name=name) - daemon = ctx.declare("_daemon") - - # Store the PID of the process we just started so that _daemon_stop_soonish - # can kill it during the cleanup phase. This works around the Subplot - # Python template not giving the step captures to cleanup functions. Note - # that this code assume at most one _soonish function is called. - daemon["_soonish"] = daemon[name]["pid"] - - try: - daemon_wait_for_port("localhost", port) - except Exception as e: - daemon["_start_error"] = repr(e) - - logging.info("pgrep: %r", _daemon_pgrep(path)) - - -def _daemon_stop_soonish(ctx, path=None, args=None, name=None, port=None): - ns = ctx.declare("_daemon") - pid = ns["_soonish"] - logging.debug(f"Stopping soonishly-started daemon, {pid}") - signo = signal.SIGKILL - try: - os.kill(pid, signo) - except ProcessLookupError: - logging.warning("Process did not actually exist (anymore?)") - - -# Start a daeamon, get its PID. Don't wait for a port or anything. This is -# meant for background processes that don't have port. Useful for testing the -# lib/daemon library of Subplot, but not much else. -def _daemon_start(ctx, path=None, args=None, name=None): - runcmd_run = globals()["runcmd_run"] - runcmd_exit_code_is = globals()["runcmd_exit_code_is"] - runcmd_get_exit_code = globals()["runcmd_get_exit_code"] - runcmd_get_stderr = globals()["runcmd_get_stderr"] - runcmd_prepend_to_path = globals()["runcmd_prepend_to_path"] - - path = os.path.abspath(path) - argv = [path] + args.split() - - logging.debug(f"Starting daemon {name}") - logging.debug(f" ctx={ctx.as_dict()}") - logging.debug(f" name={name}") - logging.debug(f" path={path}") - logging.debug(f" args={args}") - logging.debug(f" argv={argv}") - - ns = ctx.declare("_daemon") - - this = ns[name] = { - "pid-file": f"{name}.pid", - "stderr": f"{name}.stderr", - "stdout": f"{name}.stdout", - } - - # Debian installs `daemonize` to /usr/sbin, which isn't part of the minimal - # environment that Subplot sets up. So we add /usr/sbin to the PATH. - runcmd_prepend_to_path(ctx, "/usr/sbin") - runcmd_run( - ctx, - [ - "daemonize", - "-c", - os.getcwd(), - "-p", - this["pid-file"], - "-e", - this["stderr"], - "-o", - this["stdout"], - ] - + argv, - ) - - # Check that daemonize has exited OK. If it hasn't, it didn't start the - # background process at all. If so, log the stderr in case there was - # something useful there for debugging. - exit = runcmd_get_exit_code(ctx) - if exit != 0: - stderr = runcmd_get_stderr(ctx) - logging.error(f"daemon {name} stderr: {stderr}") - runcmd_exit_code_is(ctx, 0) - - # Get the pid of the background process, from the pid file created by - # daemonize. We don't need to wait for it, since we know daemonize already - # exited. If it isn't there now, it's won't appear later. - if not os.path.exists(this["pid-file"]): - raise Exception("daemonize didn't create a PID file") - - this["pid"] = _daemon_wait_for_pid(this["pid-file"], 10.0) - - logging.debug(f"Started daemon {name}") - logging.debug(f" pid={this['pid']}") - logging.debug(f" ctx={ctx.as_dict()}") - - -def _daemon_wait_for_pid(filename, timeout): - start = time.time() - while time.time() < start + timeout: - with open(filename) as f: - data = f.read().strip() - if data: - return int(data) - raise Exception("daemonize created a PID file without a PID") - - -def daemon_wait_for_port(host, port, timeout=5.0): - addr = (host, port) - until = time.time() + timeout - while True: - try: - s = socket.create_connection(addr, timeout=timeout) - s.close() - return - except socket.timeout: - logging.error( - f"daemon did not respond at port {port} within {timeout} seconds" - ) - raise - except socket.error as e: - logging.info(f"could not connect to daemon at {port}: {e}") - pass - if time.time() >= until: - logging.error( - f"could not connect to daemon at {port} within {timeout} seconds" - ) - raise ConnectionRefusedError() - # Sleep a bit to avoid consuming too much CPU while busy-waiting. - time.sleep(0.1) - - -# Stop a daemon. -def daemon_stop(ctx, path=None, args=None, name=None): - logging.debug(f"Stopping daemon {name}") - - ns = ctx.declare("_daemon") - logging.debug(f" ns={ns}") - pid = ns[name]["pid"] - signo = signal.SIGTERM - - this = ns[name] - data = open(this["stdout"]).read() - logging.debug(f"{name} stdout, before: {data!r}") - data = open(this["stderr"]).read() - logging.debug(f"{name} stderr, before: {data!r}") - - logging.debug(f"Terminating process {pid} with signal {signo}") - try: - os.kill(pid, signo) - except ProcessLookupError: - logging.warning("Process did not actually exist (anymore?)") - - while True: - try: - os.kill(pid, 0) - logging.debug(f"Daemon {name}, pid {pid} still exists") - time.sleep(1) - except ProcessLookupError: - break - logging.debug(f"Daemon {name} is gone") - - data = open(this["stdout"]).read() - logging.debug(f"{name} stdout, after: {data!r}") - data = open(this["stderr"]).read() - logging.debug(f"{name} stderr, after: {data!r}") - - -def daemon_no_such_process(ctx, args=None): - assert not _daemon_pgrep(args) - - -def daemon_process_exists(ctx, args=None): - assert _daemon_pgrep(args) - - -def _daemon_pgrep(pattern): - logging.info(f"checking if process exists: pattern={pattern}") - exit = subprocess.call( - ["pgrep", "-laf", pattern], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL - ) - logging.info(f"exit code: {exit}") - return exit == 0 - - -def daemon_start_fails_with(ctx, message=None): - daemon = ctx.declare("_daemon") - error = daemon["_start_error"] - logging.debug(f"daemon_start_fails_with: error={error!r}") - logging.debug(f"daemon_start_fails_with: message={message!r}") - assert message.lower() in error.lower() - - -def daemon_get_stdout(ctx, name): - return _daemon_get_output(ctx, name, "stdout") - - -def daemon_get_stderr(ctx, name): - return _daemon_get_output(ctx, name, "stderr") - - -def _daemon_get_output(ctx, name, which): - ns = ctx.declare("_daemon") - this = ns[name] - filename = this[which] - data = open(filename).read() - logging.debug(f"Read {which} of daemon {name} from {filename}: {data!r}") - return data - - -def daemon_has_produced_output(ctx, name=None): - started = time.time() - timeout = 5.0 - while time.time() < started + timeout: - stdout = daemon_get_stdout(ctx, name) - stderr = daemon_get_stderr(ctx, name) - if stdout and stderr: - break - time.sleep(0.1) - - -def daemon_stdout_is(ctx, name=None, text=None): - daemon_get_stdout = globals()["daemon_get_stdout"] - _daemon_output_is(ctx, name, text, daemon_get_stdout) - - -def daemon_stderr_is(ctx, name=None, text=None): - daemon_get_stderr = globals()["daemon_get_stderr"] - _daemon_output_is(ctx, name, text, daemon_get_stderr) - - -def _daemon_output_is(ctx, name, text, getter): - assert_eq = globals()["assert_eq"] - text = bytes(text, "UTF-8").decode("unicode_escape") - output = getter(ctx, name) - assert_eq(text, output) diff --git a/subplot/vendored/daemon.yaml b/subplot/vendored/daemon.yaml deleted file mode 100644 index 4fab1f6..0000000 --- a/subplot/vendored/daemon.yaml +++ /dev/null @@ -1,37 +0,0 @@ -- given: there is no "{args:text}" process - function: daemon_no_such_process - -- given: a daemon helper shell script {filename} - function: _daemon_shell_script - -- when: I start "{path}{args:text}" as a background process as {name}, on port {port} - function: daemon_start_on_port - -- when: I try to start "{path}{args:text}" as {name}, on port {port} - function: _daemon_start_soonish - cleanup: _daemon_stop_soonish - -- when: I start "{path}{args:text}" as a background process as {name} - function: _daemon_start - -- when: I stop background process {name} - function: daemon_stop - -- when: daemon {name} has produced output - function: daemon_has_produced_output - -- then: a process "{args:text}" is running - function: daemon_process_exists - -- then: there is no "{args:text}" process - function: daemon_no_such_process - -- then: starting daemon fails with "{message:text}" - function: daemon_start_fails_with - -- then: daemon {name} stdout is "{text:text}" - function: daemon_stdout_is - -- then: daemon {name} stderr is "{text:text}" - function: daemon_stderr_is - diff --git a/subplot/vendored/files.py b/subplot/vendored/files.py deleted file mode 100644 index dd5b9f8..0000000 --- a/subplot/vendored/files.py +++ /dev/null @@ -1,194 +0,0 @@ -import logging -import os -import re -import shutil -import time - - -def files_create_from_embedded(ctx, filename=None): - files_make_directory(ctx, path=os.path.dirname(filename) or ".") - files_create_from_embedded_with_other_name( - ctx, filename_on_disk=filename, embedded_filename=filename - ) - - -def files_create_from_embedded_with_other_name( - ctx, filename_on_disk=None, embedded_filename=None -): - get_file = globals()["get_file"] - - files_make_directory(ctx, path=os.path.dirname(filename_on_disk) or ".") - with open(filename_on_disk, "wb") as f: - f.write(get_file(embedded_filename)) - - -def files_create_from_text(ctx, filename=None, text=None): - files_make_directory(ctx, path=os.path.dirname(filename) or ".") - with open(filename, "w") as f: - f.write(text) - - -def files_make_directory(ctx, path=None): - path = "./" + path - if not os.path.exists(path): - os.makedirs(path) - - -def files_remove_directory(ctx, path=None): - path = "./" + path - shutil.rmtree(path) - - -def files_file_exists(ctx, filename=None): - assert_eq = globals()["assert_eq"] - assert_eq(os.path.exists(filename), True) - - -def files_file_does_not_exist(ctx, filename=None): - assert_eq = globals()["assert_eq"] - assert_eq(os.path.exists(filename), False) - - -def files_directory_exists(ctx, path=None): - assert_eq = globals()["assert_eq"] - assert_eq(os.path.isdir(path), True) - - -def files_directory_does_not_exist(ctx, path=None): - assert_eq = globals()["assert_eq"] - assert_eq(os.path.isdir(path), False) - - -def files_directory_is_empty(ctx, path=None): - assert_eq = globals()["assert_eq"] - assert_eq(os.listdir(path), []) - - -def files_directory_is_not_empty(ctx, path=None): - assert_ne = globals()["assert_ne"] - assert_ne(os.listdir(path), False) - - -def files_only_these_exist(ctx, filenames=None): - assert_eq = globals()["assert_eq"] - filenames = filenames.replace(",", "").split() - assert_eq(set(os.listdir(".")), set(filenames)) - - -def files_file_contains(ctx, filename=None, data=None): - assert_eq = globals()["assert_eq"] - with open(filename, "rb") as f: - actual = f.read() - actual = actual.decode("UTF-8") - assert_eq(data in actual, True) - - -def files_file_matches_regex(ctx, filename=None, regex=None): - assert_eq = globals()["assert_eq"] - with open(filename) as f: - content = f.read() - m = re.search(regex, content) - if m is None: - logging.debug(f"files_file_matches_regex: no match") - logging.debug(f" filenamed: {filename}") - logging.debug(f" regex: {regex}") - logging.debug(f" content: {regex}") - logging.debug(f" match: {m}") - assert_eq(bool(m), True) - - -def files_match(ctx, filename1=None, filename2=None): - assert_eq = globals()["assert_eq"] - with open(filename1, "rb") as f: - data1 = f.read() - with open(filename2, "rb") as f: - data2 = f.read() - assert_eq(data1, data2) - - -def files_touch_with_timestamp( - ctx, - filename=None, - year=None, - month=None, - day=None, - hour=None, - minute=None, - second=None, -): - t = ( - int(year), - int(month), - int(day), - int(hour), - int(minute), - int(second), - -1, - -1, - -1, - ) - ts = time.mktime(t) - _files_touch(filename, ts) - - -def files_touch(ctx, filename=None): - _files_touch(filename, None) - - -def _files_touch(filename, ts): - if not os.path.exists(filename): - open(filename, "w").close() - times = None - if ts is not None: - times = (ts, ts) - os.utime(filename, times=times) - - -def files_mtime_is_recent(ctx, filename=None): - st = os.stat(filename) - age = abs(st.st_mtime - time.time()) - assert age < 1.0 - - -def files_mtime_is_ancient(ctx, filename=None): - st = os.stat(filename) - age = abs(st.st_mtime - time.time()) - year = 365 * 24 * 60 * 60 - required = 39 * year - logging.debug(f"ancient? mtime={st.st_mtime} age={age} required={required}") - assert age > required - - -def files_remember_metadata(ctx, filename=None): - meta = _files_remembered(ctx) - meta[filename] = _files_get_metadata(filename) - logging.debug("files_remember_metadata:") - logging.debug(f" meta: {meta}") - logging.debug(f" ctx: {ctx}") - - -# Check that current metadata of a file is as stored in the context. -def files_has_remembered_metadata(ctx, filename=None): - assert_eq = globals()["assert_eq"] - meta = _files_remembered(ctx) - logging.debug("files_has_remembered_metadata:") - logging.debug(f" meta: {meta}") - logging.debug(f" ctx: {ctx}") - assert_eq(meta[filename], _files_get_metadata(filename)) - - -def files_has_different_metadata(ctx, filename=None): - assert_ne = globals()["assert_ne"] - meta = _files_remembered(ctx) - assert_ne(meta[filename], _files_get_metadata(filename)) - - -def _files_remembered(ctx): - ns = ctx.declare("_files") - return ns.get("remembered-metadata", {}) - - -def _files_get_metadata(filename): - st = os.lstat(filename) - keys = ["st_dev", "st_gid", "st_ino", "st_mode", "st_mtime", "st_size", "st_uid"] - return {key: getattr(st, key) for key in keys} diff --git a/subplot/vendored/files.yaml b/subplot/vendored/files.yaml deleted file mode 100644 index f18b8cd..0000000 --- a/subplot/vendored/files.yaml +++ /dev/null @@ -1,83 +0,0 @@ -- given: file {filename} - function: files_create_from_embedded - types: - filename: file - -- given: file {filename_on_disk} from {embedded_filename} - function: files_create_from_embedded_with_other_name - types: - embedded_filename: file - -- given: file {filename} has modification time {year}-{month}-{day} {hour}:{minute}:{second} - function: files_touch_with_timestamp - -- when: I write "(?P.*)" to file (?P\S+) - regex: true - function: files_create_from_text - -- when: I remember metadata for file {filename} - function: files_remember_metadata - -- when: I touch file {filename} - function: files_touch - -- then: file {filename} exists - function: files_file_exists - -- then: file {filename} does not exist - function: files_file_does_not_exist - -- then: only files (?P.+) exist - function: files_only_these_exist - regex: true - -- then: file (?P\S+) contains "(?P.*)" - regex: true - function: files_file_contains - -- then: file (?P\S+) matches regex /(?P.*)/ - regex: true - function: files_file_matches_regex - -- then: file (?P\S+) matches regex "(?P.*)" - regex: true - function: files_file_matches_regex - -- then: files {filename1} and {filename2} match - function: files_match - -- then: file {filename} has same metadata as before - function: files_has_remembered_metadata - -- then: file {filename} has different metadata from before - function: files_has_different_metadata - -- then: file {filename} has changed from before - function: files_has_different_metadata - -- then: file {filename} has a very recent modification time - function: files_mtime_is_recent - -- then: file {filename} has a very old modification time - function: files_mtime_is_ancient - -- given: a directory {path} - function: files_make_directory - -- when: I create directory {path} - function: files_make_directory - -- when: I remove directory {path} - function: files_remove_directory - -- then: directory {path} exists - function: files_directory_exists - -- then: directory {path} does not exist - function: files_directory_does_not_exist - -- then: directory {path} is empty - function: files_directory_is_empty - -- then: directory {path} is not empty - function: files_directory_is_not_empty diff --git a/subplot/vendored/runcmd.py b/subplot/vendored/runcmd.py deleted file mode 100644 index a2564c6..0000000 --- a/subplot/vendored/runcmd.py +++ /dev/null @@ -1,252 +0,0 @@ -import logging -import os -import re -import shlex -import subprocess - - -# -# Helper functions. -# - -# Get exit code or other stored data about the latest command run by -# runcmd_run. - - -def _runcmd_get(ctx, name): - ns = ctx.declare("_runcmd") - return ns[name] - - -def runcmd_get_exit_code(ctx): - return _runcmd_get(ctx, "exit") - - -def runcmd_get_stdout(ctx): - return _runcmd_get(ctx, "stdout") - - -def runcmd_get_stdout_raw(ctx): - return _runcmd_get(ctx, "stdout.raw") - - -def runcmd_get_stderr(ctx): - return _runcmd_get(ctx, "stderr") - - -def runcmd_get_stderr_raw(ctx): - return _runcmd_get(ctx, "stderr.raw") - - -def runcmd_get_argv(ctx): - return _runcmd_get(ctx, "argv") - - -# Run a command, given an argv and other arguments for subprocess.Popen. -# -# This is meant to be a helper function, not bound directly to a step. The -# stdout, stderr, and exit code are stored in the "_runcmd" namespace in the -# ctx context. -def runcmd_run(ctx, argv, **kwargs): - ns = ctx.declare("_runcmd") - - # The Subplot Python template empties os.environ at startup, modulo a small - # number of variables with carefully chosen values. Here, we don't need to - # care about what those variables are, but we do need to not overwrite - # them, so we just add anything in the env keyword argument, if any, to - # os.environ. - env = dict(os.environ) - for key, arg in kwargs.pop("env", {}).items(): - env[key] = arg - - pp = ns.get("path-prefix") - if pp: - env["PATH"] = pp + ":" + env["PATH"] - - logging.debug(f"runcmd_run") - logging.debug(f" argv: {argv}") - logging.debug(f" env: {env}") - p = subprocess.Popen( - argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, **kwargs - ) - stdout, stderr = p.communicate("") - ns["argv"] = argv - ns["stdout.raw"] = stdout - ns["stderr.raw"] = stderr - ns["stdout"] = stdout.decode("utf-8") - ns["stderr"] = stderr.decode("utf-8") - ns["exit"] = p.returncode - logging.debug(f" ctx: {ctx}") - logging.debug(f" ns: {ns}") - - -# Step: prepend srcdir to PATH whenever runcmd runs a command. -def runcmd_helper_srcdir_path(ctx): - srcdir = globals()["srcdir"] - runcmd_prepend_to_path(ctx, srcdir) - - -# Step: This creates a helper script. -def runcmd_helper_script(ctx, filename=None): - get_file = globals()["get_file"] - with open(filename, "wb") as f: - f.write(get_file(filename)) - - -# -# Step functions for running commands. -# - - -def runcmd_prepend_to_path(ctx, dirname=None): - ns = ctx.declare("_runcmd") - pp = ns.get("path-prefix", "") - if pp: - pp = f"{pp}:{dirname}" - else: - pp = dirname - ns["path-prefix"] = pp - - -def runcmd_step(ctx, argv0=None, args=None): - runcmd_try_to_run(ctx, argv0=argv0, args=args) - runcmd_exit_code_is_zero(ctx) - - -def runcmd_try_to_run(ctx, argv0=None, args=None): - argv = [shlex.quote(argv0)] + shlex.split(args) - runcmd_run(ctx, argv) - - -# -# Step functions for examining exit codes. -# - - -def runcmd_exit_code_is_zero(ctx): - runcmd_exit_code_is(ctx, exit=0) - - -def runcmd_exit_code_is(ctx, exit=None): - assert_eq = globals()["assert_eq"] - assert_eq(runcmd_get_exit_code(ctx), int(exit)) - - -def runcmd_exit_code_is_nonzero(ctx): - runcmd_exit_code_is_not(ctx, exit=0) - - -def runcmd_exit_code_is_not(ctx, exit=None): - assert_ne = globals()["assert_ne"] - assert_ne(runcmd_get_exit_code(ctx), int(exit)) - - -# -# Step functions and helpers for examining output in various ways. -# - - -def runcmd_stdout_is(ctx, text=None): - _runcmd_output_is(runcmd_get_stdout(ctx), text) - - -def runcmd_stdout_isnt(ctx, text=None): - _runcmd_output_isnt(runcmd_get_stdout(ctx), text) - - -def runcmd_stderr_is(ctx, text=None): - _runcmd_output_is(runcmd_get_stderr(ctx), text) - - -def runcmd_stderr_isnt(ctx, text=None): - _runcmd_output_isnt(runcmd_get_stderr(ctx), text) - - -def _runcmd_output_is(actual, wanted): - assert_eq = globals()["assert_eq"] - wanted = bytes(wanted, "utf8").decode("unicode_escape") - logging.debug("_runcmd_output_is:") - logging.debug(f" actual: {actual!r}") - logging.debug(f" wanted: {wanted!r}") - assert_eq(actual, wanted) - - -def _runcmd_output_isnt(actual, wanted): - assert_ne = globals()["assert_ne"] - wanted = bytes(wanted, "utf8").decode("unicode_escape") - logging.debug("_runcmd_output_isnt:") - logging.debug(f" actual: {actual!r}") - logging.debug(f" wanted: {wanted!r}") - assert_ne(actual, wanted) - - -def runcmd_stdout_contains(ctx, text=None): - _runcmd_output_contains(runcmd_get_stdout(ctx), text) - - -def runcmd_stdout_doesnt_contain(ctx, text=None): - _runcmd_output_doesnt_contain(runcmd_get_stdout(ctx), text) - - -def runcmd_stderr_contains(ctx, text=None): - _runcmd_output_contains(runcmd_get_stderr(ctx), text) - - -def runcmd_stderr_doesnt_contain(ctx, text=None): - _runcmd_output_doesnt_contain(runcmd_get_stderr(ctx), text) - - -def _runcmd_output_contains(actual, wanted): - assert_eq = globals()["assert_eq"] - wanted = bytes(wanted, "utf8").decode("unicode_escape") - logging.debug("_runcmd_output_contains:") - logging.debug(f" actual: {actual!r}") - logging.debug(f" wanted: {wanted!r}") - assert_eq(wanted in actual, True) - - -def _runcmd_output_doesnt_contain(actual, wanted): - assert_ne = globals()["assert_ne"] - wanted = bytes(wanted, "utf8").decode("unicode_escape") - logging.debug("_runcmd_output_doesnt_contain:") - logging.debug(f" actual: {actual!r}") - logging.debug(f" wanted: {wanted!r}") - assert_ne(wanted in actual, True) - - -def runcmd_stdout_matches_regex(ctx, regex=None): - _runcmd_output_matches_regex(runcmd_get_stdout(ctx), regex) - - -def runcmd_stdout_doesnt_match_regex(ctx, regex=None): - _runcmd_output_doesnt_match_regex(runcmd_get_stdout(ctx), regex) - - -def runcmd_stderr_matches_regex(ctx, regex=None): - _runcmd_output_matches_regex(runcmd_get_stderr(ctx), regex) - - -def runcmd_stderr_doesnt_match_regex(ctx, regex=None): - _runcmd_output_doesnt_match_regex(runcmd_get_stderr(ctx), regex) - - -def _runcmd_output_matches_regex(actual, regex): - assert_ne = globals()["assert_ne"] - r = re.compile(regex) - m = r.search(actual) - logging.debug("_runcmd_output_matches_regex:") - logging.debug(f" actual: {actual!r}") - logging.debug(f" regex: {regex!r}") - logging.debug(f" match: {m}") - assert_ne(m, None) - - -def _runcmd_output_doesnt_match_regex(actual, regex): - assert_eq = globals()["assert_eq"] - r = re.compile(regex) - m = r.search(actual) - logging.debug("_runcmd_output_doesnt_match_regex:") - logging.debug(f" actual: {actual!r}") - logging.debug(f" regex: {regex!r}") - logging.debug(f" match: {m}") - assert_eq(m, None) diff --git a/subplot/vendored/runcmd.yaml b/subplot/vendored/runcmd.yaml deleted file mode 100644 index 48dde90..0000000 --- a/subplot/vendored/runcmd.yaml +++ /dev/null @@ -1,83 +0,0 @@ -# Steps to run commands. - -- given: helper script {filename} for runcmd - function: runcmd_helper_script - -- given: srcdir is in the PATH - function: runcmd_helper_srcdir_path - -- when: I run (?P\S+)(?P.*) - regex: true - function: runcmd_step - -- when: I try to run (?P\S+)(?P.*) - regex: true - function: runcmd_try_to_run - -# Steps to examine exit code of latest command. - -- then: exit code is {exit} - function: runcmd_exit_code_is - -- then: exit code is not {exit} - function: runcmd_exit_code_is_not - -- then: command is successful - function: runcmd_exit_code_is_zero - -- then: command fails - function: runcmd_exit_code_is_nonzero - -# Steps to examine stdout/stderr for exact content. - -- then: stdout is exactly "(?P.*)" - regex: true - function: runcmd_stdout_is - -- then: "stdout isn't exactly \"(?P.*)\"" - regex: true - function: runcmd_stdout_isnt - -- then: stderr is exactly "(?P.*)" - regex: true - function: runcmd_stderr_is - -- then: "stderr isn't exactly \"(?P.*)\"" - regex: true - function: runcmd_stderr_isnt - -# Steps to examine stdout/stderr for sub-strings. - -- then: stdout contains "(?P.*)" - regex: true - function: runcmd_stdout_contains - -- then: "stdout doesn't contain \"(?P.*)\"" - regex: true - function: runcmd_stdout_doesnt_contain - -- then: stderr contains "(?P.*)" - regex: true - function: runcmd_stderr_contains - -- then: "stderr doesn't contain \"(?P.*)\"" - regex: true - function: runcmd_stderr_doesnt_contain - -# Steps to match stdout/stderr against regular expressions. - -- then: stdout matches regex (?P.*) - regex: true - function: runcmd_stdout_matches_regex - -- then: stdout doesn't match regex (?P.*) - regex: true - function: runcmd_stdout_doesnt_match_regex - -- then: stderr matches regex (?P.*) - regex: true - function: runcmd_stderr_matches_regex - -- then: stderr doesn't match regex (?P.*) - regex: true - function: runcmd_stderr_doesnt_match_regex -- cgit v1.2.1 From 16ba7070a6e040918f354b87f952cc47a7df6b5a Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Thu, 22 Jul 2021 11:19:57 +0300 Subject: feat! allow/require setting address on which to listen This will break all existing config file, of which there should be none. Sponsored-by: author --- src/main.rs | 13 ++++++++++--- subplot/ewww.py | 10 ++++++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index e120534..38a6c44 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ use serde::Deserialize; +use std::net::{SocketAddr, ToSocketAddrs}; use std::path::{Path, PathBuf}; use structopt::StructOpt; use warp::Filter; @@ -8,7 +9,7 @@ extern crate log; #[derive(Debug, Deserialize)] struct Config { webroot: PathBuf, - port: u16, + listen: String, tls_key: PathBuf, tls_cert: PathBuf, } @@ -34,7 +35,7 @@ enum EwwwError { } #[tokio::main] -async fn main() { +async fn main() -> anyhow::Result<()> { pretty_env_logger::init(); info!("ewww starting up"); @@ -42,7 +43,11 @@ async fn main() { let config = read_config(&opt.config).unwrap(); let webroot = config.webroot.canonicalize().unwrap(); + let addr: SocketAddr = config.listen.to_socket_addrs().unwrap().next().unwrap(); + info!("webroot: {:?}", webroot); + info!("listen on {}", addr); + let log = warp::log("ewww"); let webroot = warp::any().and(warp::fs::dir(webroot)).with(log); @@ -50,8 +55,10 @@ async fn main() { .tls() .key_path(config.tls_key) .cert_path(config.tls_cert) - .run(([127, 0, 0, 1], config.port)) + .run(addr) .await; + + Ok(()) } fn read_config(filename: &Path) -> anyhow::Result { diff --git a/subplot/ewww.py b/subplot/ewww.py index e30c219..a6c4c4f 100644 --- a/subplot/ewww.py +++ b/subplot/ewww.py @@ -24,10 +24,10 @@ def _write(filename, content): # Construct a URL that points to server running on localhost by # replacing the actual scheme and host with ones that work for test. def _url(ctx, url): - port = ctx["config"]["port"] + listen = ctx["config"]["listen"] c = urllib.parse.urlparse(url) host = c[1] - c = (c[0], "localhost:{}".format(port)) + c[2:] + c = (c[0], "{}".format(listen)) + c[2:] return urllib.parse.urlunparse(c), host @@ -64,9 +64,11 @@ def start_server(ctx, filename=None): logging.debug(f"Starting ewww with config file {filename}") config = get_file(filename).decode("UTF-8") config = yaml.safe_load(config) - port = config["port"] = random.randint(2000, 30000) - logging.debug(f"Picked randomly port for ewww: {config['port']}") + port = random.randint(2000, 30000) + logging.debug(f"Picked randomly port for ewww: {port}") + config["listen"] = f"localhost:{port}" ctx["config"] = config + logging.debug(f"ewww config: {config!r}") config = yaml.safe_dump(config) _write(filename, config) -- cgit v1.2.1 From 0c46aec694080052a980ef7c95c642bb86124791 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Thu, 22 Jul 2021 11:18:39 +0300 Subject: chore: add start of Ansible playbook for deploying ewww Sponsored-by: author --- debian/rules | 2 + ewww-vars.yml | 30 +++++++++++++++ ewww.service | 5 +++ ewww.yaml | 2 + ewww.yml | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hosts | 1 + 6 files changed, 156 insertions(+) create mode 100644 ewww-vars.yml create mode 100644 ewww.service create mode 100644 ewww.yaml create mode 100644 ewww.yml create mode 100644 hosts diff --git a/debian/rules b/debian/rules index aaa5a27..e3d7fd8 100755 --- a/debian/rules +++ b/debian/rules @@ -8,6 +8,8 @@ override_dh_auto_build: override_dh_auto_install: cargo install --path=. --root=debian/ewww + install -d debian/ewww/lib/systemd/system + install -m 0644 ewww.service debian/ewww/lib/systemd/system/ewww.service rm -f debian/ewww/.crates.toml rm -f debian/ewww/.crates2.json diff --git a/ewww-vars.yml b/ewww-vars.yml new file mode 100644 index 0000000..e66d32c --- /dev/null +++ b/ewww-vars.yml @@ -0,0 +1,30 @@ +ci_prod_signing_key: | + -----BEGIN PGP PUBLIC KEY BLOCK----- + + mQINBFrLO7kBEADdz6mHstYmKU5Dp6OSjxWtWaqTDOX1sJdmmaIK/9EKVIH0Maxp + 5kvVO5G6mULLAjv/kLG0MxasHPrq8I2A/y8AqKAGVL8QelwLjQMIFZ30/VbGQPHS + +T5TZXEnoQtNce1GUhFwJ38ZyjjwHBFV9tSec7rZ2Q3YeM3nNnGPf6DacXGfEOPO + HIN4sXAN2hzNXNjKRzTIvxQseb6nr7afUh/SlZ3yhQOCrIzmYlD7tP9WJe7ofL0p + JY4pDQYw8rT6nC2BE/ioemh84kERCT1vCe+OVFlSRuMlqfEv+ZpKQ+itOmPDQ/lM + jpUm1K2hrW/lWpxT/ZxHKo/w1K36J5WshgMZxfUu5BMCL9LMqMcrXNhNjDMfxDMM + 3yBPOvQ4ls6fecOZ/bsFo1p8VzMk/w/eG8vPs5yuNa5XxN95yFMXoOHGb5Xbu8D4 + 6yiW+Af70LbiSNpGdmNdneiGB2fY38NxBukPw5u3S5qG8HedSmMr1RvSr5kHoAAe + UbOY+BYaaKsTAT7+1skUW1o3FJSqoRKCHAzTsMWC6zzhR8hRn7jVrrguH1hGbqq5 + TZSCFQZExuTJ7uXrTLG0WoBXIjB5wWNcSeXn8myUWYB51nJNF4tJBouZOz9JwWGl + kiAQkrHnBttLQWdW9FyjbIoTZMtpvVx+m6ObGTGdGL1cNlLAvWprMXGc+QARAQAB + tDJJY2sgQVBUIHJlcG9zaXRvcnkgc2lnbmluZyBrZXkgKDIwMTgpIDxsaXdAbGl3 + LmZpPokCTgQTAQgAOBYhBKL1uyDoXyxUH3O717Wr+TZVS6PGBQJayzu5AhsDBQsJ + CAcCBhUICQoLAgQWAgMBAh4BAheAAAoJELWr+TZVS6PGB5QQANTcikhRUHwt9N4h + dGc/Hp6CbqdshMoWlwpFskttoVDxQG5OAobuZl5XyzGcmja1lT85RGkZFfbca0IZ + LnXOLLSAu51QBkXNaj4OhjK/0uQ+ITrvL6RQSXNgHiUTR/W2XD1GIUq6nBqe2GSN + 31S1baYKKVj5QIMsi7Dq8ls3BBXuPCE+xTSaNmGWjes2t9pPidcRvxsksCLY1qgw + P1GFXBeMkBQ29kBP87SUL15SIk7OiQLlEURCy5iRls5rt/YEsdEpRWIb0Tm5Nrjv + 2M3VM+iBhfNXTwj0rJ34mlycF1qQmA7YcTEobT7z587GPY0VWzBpQUnEQj7rQWPM + cDYY0b+I6kQ8VKOaL4wVAtE98d7HzFIrIrwhTKufnrWrVDPYsmLZ+LPC1jiF7JBD + SR6Vftb+SdDR9xoE1yRuXbC6IfoW+5/qQNrdQ2mm9BFw5jOonBqchs18HTTf3441 + 6SWwP9fY3Vi+IZphPPi0Gf85oMStgnv/Wnw6LacEL32ek39Desero/D8iGLZernK + Q2mC9mua5A/bYGVhsNWyURNFkKdbFa+/wW3NfdKYyZnsSfo+jJ2luNewrhAY7Kod + GWXTer9RxzTGA3EXFGvNr+BBOOxSj0SfWTl0Olo7J5dnxof+jLAUS1VHpceHGHps + GSJSdir7NkZidgwoCPA7BTqsb5LN + =dXB0 + -----END PGP PUBLIC KEY BLOCK----- diff --git a/ewww.service b/ewww.service new file mode 100644 index 0000000..add9477 --- /dev/null +++ b/ewww.service @@ -0,0 +1,5 @@ +[Unit] +Description=Ewww web server + +[Service] +ExecStart=/usr/bin/ewww /etc/ewww.yaml diff --git a/ewww.yaml b/ewww.yaml new file mode 100644 index 0000000..5278fee --- /dev/null +++ b/ewww.yaml @@ -0,0 +1,2 @@ +# A vmadm spec file for a ewww VM. +ewww: {} diff --git a/ewww.yml b/ewww.yml new file mode 100644 index 0000000..d8a10af --- /dev/null +++ b/ewww.yml @@ -0,0 +1,116 @@ +# An Ansible playbook to deploy ewww. This is currently for demo +# purposes only, and installs a self-signed toy TLS certificate. + +- hosts: ewww + remote_user: debian + become: yes + roles: + - sane_debian_system + tasks: + - name: "Install ewww" + apt: + name: + - ewww + - psmisc + - curl + state: present + - name: "Create /srv/http" + file: + state: directory + path: /srv/http + - name: "Create ewww config directory" + file: + state: directory + path: /etc/ewww + - name: "Install ewww config" + copy: + content: | + webroot: /srv/http + listen: "0.0.0.0:443" + tls_cert: /etc/ewww/tls.pem + tls_key: /etc/ewww/tls.key + dest: /etc/ewww/ewww.yaml + - name: "Install TLS cert" + copy: + content: | + -----BEGIN CERTIFICATE----- + MIICrzCCAZcCFFusxXoXXAVCzpfNK5VlnS8vFnY/MA0GCSqGSIb3DQEBCwUAMBQx + EjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0yMTA3MjIwNzMzNThaFw0yMjA3MjIwNzMz + NThaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEP + ADCCAQoCggEBALhfy48gwIslLt5nCDSaPZeg52TwlZ8gWotnoprcv3cgTllDD/t7 + uLwRrYFJl2AheaNRP+ZOgXYzuS+pOz7YCdLg6bc1d8Dto69gQy848GnTtHINgy3Z + Ag0L5d2B8/PcpEagFe2z1cCDzxNxkhjWisb0Rm1AOJcNxQWvICw428wwWEr6SRiO + FHTht5UG0oClK88cJSwBnzNSS9Q30q42JfUmua1Dd0PS3FOMibtzMB9aBATeR4uH + pQ1qCGU197er0PVfxWYrm8LEyZFQHRviwiaLNMtMRQuOp2rDF3kV/aZuw+aUYqpk + zz+H3g0lxU3vYp/NmSRvC7y4HFxr7xlu6DECAwEAATANBgkqhkiG9w0BAQsFAAOC + AQEAgpZ0dd+W4v7P6uFZ3R4rbRrHUQEOlFFMUrkf6EyT9xeIk7XjO6+RYbVP6tWX + h4T9sEIFypAtR/47JEhFKYzncPBygUQfzXH5hW0JgviMQ8nNQz6NUJ5vPpeI4Tob + 7uipx46Lq6nF6h9DbMK/03M7ZeybEa+nknDtry5hKTVzi+xSkVQX1/xgOBY0hhUk + xcLCULujN2Lp262aP9hIuI/vaXo5HOh+BavsSauVUsRjScz/8Lgn+q4qRajcgnRa + WvK5nH/Ok4am5F9LDcwZOyUXrV+VB9CcbhnzinMuPwCdhPvMr+F7zQP9YXbOeOlP + NdZiSNvGZAbEnmMnNCEYMO3wVA== + -----END CERTIFICATE----- + dest: /etc/ewww/tls.pem + - name: "Install TLS key" + copy: + content: | + -----BEGIN RSA PRIVATE KEY----- + MIIEpAIBAAKCAQEAuF/LjyDAiyUu3mcINJo9l6DnZPCVnyBai2eimty/dyBOWUMP + +3u4vBGtgUmXYCF5o1E/5k6BdjO5L6k7PtgJ0uDptzV3wO2jr2BDLzjwadO0cg2D + LdkCDQvl3YHz89ykRqAV7bPVwIPPE3GSGNaKxvRGbUA4lw3FBa8gLDjbzDBYSvpJ + GI4UdOG3lQbSgKUrzxwlLAGfM1JL1DfSrjYl9Sa5rUN3Q9LcU4yJu3MwH1oEBN5H + i4elDWoIZTX3t6vQ9V/FZiubwsTJkVAdG+LCJos0y0xFC46nasMXeRX9pm7D5pRi + qmTPP4feDSXFTe9in82ZJG8LvLgcXGvvGW7oMQIDAQABAoIBAQCTKyP441PNvahj + ripGkreHSNBrKf7EPbcIf3iz1HCgThE7/uPLAT68IAA2qt9BxHarfjdbRl7gUvkG + qja4OwncYdssemlUfluhqVz3XKPKVUo7n72N4yJX959L6GcpyHz4QuA+FMYSHSQ1 + iPntCZNMq79rhU+mgz85AkjUA66ulKzkFwYRL6oRJ+fxwYKTCcnRAUbUaihDXb5T + AV4wDPMKLse70KL42SPTrQFzTqguDlXzPlKvqOEi2lZkNkiMr8wdN/xZlzLre89K + EM/mczCnYnI17dkFrdF+9Wsr63o24H+vUQ3IWIDnVP+dgMXonvCz2Z8mawlb5tt7 + vuY4b9KBAoGBAOczO740Q/mDk2iQI4Kt+o1unRwz34AEge0hm7kVUb7g2iV9sqNU + PovFjIvfCpWTmxVj6NQHyHbKDUfnnYzrpYHuMu2mL5E/1w+WqO1xPgoS287Xs/0I + E6N/BozDW4kMgBID0U2qz0JBrDMDFlL/yoziec6kv8f8uvRlQKtSdVSFAoGBAMwm + uDCShE4RcCr0PgAhiCSllJF03AVbLioTqdXwiHbIVvu5XvUClgOuI0eUDzU0Dsco + eWVaMQYx2Gt26sPPE52duZQNZ8JOZVq8/eSoycxYBn+hxYsjWqR9VvAZ4UMQvQ9g + T8La/NJTmzGVqpSD6XA176umCmgB/oeEaNZvchq9AoGAUfmbdDxJ4b1iVc/Nl3ci + gGU49Zf65gQzISYqdbx2aIyHLIXeAgVLy/k2dR2XPiPA+BudoRhFXsETZmxcM2wW + GfSgQB0Nfp25HkDYEqB1U9MN9tAKdGwZsn3Gj8Bwwy4Ydsq9uqEWrbJlYQz2LGWf + psZiU/+cNEeK7j68aEJrcZUCgYAu7zvrVtP6CsJJ7csPRqZBHpwwcLhgtty/KbQj + DmChRl/REYYGOCj7AZ70xtJUPfqjyOdX6MtajD0gP7+rcsEkvG0833QaVOGyYb7R + Qgja5OXhk/SRj3g4VuSU4K5MN93vWgocVzJGvJfyZ2FHMaiKdqv6P3sm/EZjK4ra + udZ21QKBgQDXmMP5sPHBtpHyXybIHk+nJICOtsKAJklXA1msgCk8OqDyPXX3qh8e + 4vFU4tgRN1nBMmEG5ROTtING1dQ5+X3aqXOJIO+asE1FkQA1kUhFKg2OSo15liPI + cB5//DSHki2Mh1iZxPfZnvFYpEOl9pmedSJ4tlltzKQSY//6kGJ49g== + -----END RSA PRIVATE KEY----- + dest: /etc/ewww/tls.key + - name: "Install systemd service" + copy: + content: | + [Unit] + Description=ewww web server + + [Service] + ExecStart=/usr/bin/ewww /etc/ewww/ewww.yaml + dest: /lib/systemd/system/ewww.service + - name: "Enable and start ewww service" + systemd: + name: ewww + state: restarted + enabled: yes + daemon_reload: yes + vars: + sane_debian_system_version: 2 + unix_users_version: 2 + + sane_debian_system_hostname: ewww + sane_debian_system_codename: buster + sane_debian_system_mirror: deb.debian.org + + sane_debian_system_sources_lists: + - repo: deb http://ci-prod-controller.vm.liw.fi/debian unstable-ci main + signing_key: "{{ ci_prod_signing_key }}" + + unix_users: + - username: static + comment: Static web site content + authorized_keys: | + {{ static_ssh_pub }} diff --git a/hosts b/hosts new file mode 100644 index 0000000..1166a32 --- /dev/null +++ b/hosts @@ -0,0 +1 @@ +ewww \ No newline at end of file -- cgit v1.2.1