diff options
author | ms <ms@taler.net> | 2021-11-28 18:16:44 +0100 |
---|---|---|
committer | ms <ms@taler.net> | 2021-11-28 18:16:44 +0100 |
commit | 3341cdfa5915725ae5a2059abab4444c94af437a (patch) | |
tree | ced052e45bfd3868e52860d39556dd20a8b7fe36 | |
parent | 503cb67bdc52a6337830717bc8ffecaf066b94c5 (diff) | |
download | deployment-3341cdfa5915725ae5a2059abab4444c94af437a.tar.gz deployment-3341cdfa5915725ae5a2059abab4444c94af437a.tar.bz2 deployment-3341cdfa5915725ae5a2059abab4444c94af437a.zip |
taler-local
HTTP proxying and process management done only with
Nginx and SystemD.
-rwxr-xr-x | bin/WIP/taler-local | 662 |
1 files changed, 236 insertions, 426 deletions
diff --git a/bin/WIP/taler-local b/bin/WIP/taler-local index a777ac7..e38a58d 100755 --- a/bin/WIP/taler-local +++ b/bin/WIP/taler-local @@ -434,141 +434,11 @@ def bootstrap(list_repos, repos) -> None: reposList = split_repos_list(repos) checkout_repos(load_repos(reposList)) -class TalerReverseProxy(Flask): - def __init__( - self, - log_dir, - unix_sockets_dir, - proxy_proto, - proxy_netloc - ): - super().__init__("taler-proxy") - all_methods = [ - "GET", "POST", "HEAD", - "DELETE", "OPTIONS", "PUT" - ] - self.log_dir = log_dir - self.unix_sockets_dir = unix_sockets_dir - self.proxy_proto = proxy_proto - self.proxy_netloc = proxy_netloc - self.add_url_rule("/", view_func=self.index) - self.add_url_rule("/<component>", view_func=self.proxy, methods=all_methods) - self.add_url_rule("/<component>/", view_func=self.proxy, methods=all_methods) - self.add_url_rule("/<component>/<path:path>", view_func=self.proxy, methods=all_methods) - - def stop(self): - self.proc.terminate() - self.proc.join() - - def get_log_filename(self): - return self.logger.root.handlers[0].baseFilename - - def start(self): - if not self.log_dir.is_dir(): - os.makedirs(self.log_dir) - logging.basicConfig(filename=self.log_dir / "reverse-proxy.log", filemode="a") - self.logger = logging.getLogger("werkzeug") - self.logger.setLevel(logging.DEBUG) - os.environ["WERKZEUG_RUN_MAIN"] = "true" - self.proc = Process( - target=self.run, - kwargs=dict(debug=False, port=8080, host="localhost") - ) - - # This proxy does set Content-Length, as it often - # reassembles chunked responses. Future versions - # will echo back chunks as they arrive. - # Response.automatically_set_content_length = False - - self.proc.start() - atexit.register(self.stop) - - def index(self): - return "I'm the Taler reverse proxy." - - def iter_response(self, r): - for line in r.iter_lines(): - self.logger.debug("Responding chunk " + line.decode("utf-8")) - yield line - - def proxy(self, component, path=""): - s = Session() - try: - if request.method == "GET": - method = s.get - if request.method == "POST": - method = s.post - if request.method == "PUT": - method = s.put - if request.method == "DELETE": - method = s.delete - proxied_headers = { - "X-Forwarded-Host": self.proxy_netloc, - "X-Forwarded-Proto": self.proxy_proto, - "X-Forwarded-Prefix": f"/{component}" - } - for k, v in request.headers.items(): - proxied_headers[k] = v - - socket_path = f"{self.unix_sockets_dir}/{component}.sock" - self.logger.debug("Proxying to: " + socket_path + "/" + path) - uri = f"http+unix://{quote(socket_path, safe='')}/{path.replace('?', '%3F')}" - if len(request.args) > 0: - uri += f"?{request.query_string.decode()}" - resp = method( - uri, - headers=proxied_headers, - data=request.get_data(), - allow_redirects=False - ) - except Exception as error: - self.logger.error(error) - self.logger.error(f"Failing request was: {request.get_data()}") - return "Could not connect to upstream", 500 - - self.logger.debug(f"Upstream responds: {resp.text}") - headers = Headers() - for k in resp.headers.keys(): - # This version does not send chunked responses, so - # remove that header when it's found. Content-Length - # will be added before sending the response. - if k == "Transfer-Encoding" and resp.headers[k] == "chunked": - continue - # The content was already decompressed by this proxy, therefore - # the following header would confuse the client. - if k == "Content-Encoding" and (resp.headers[k] in ["deflate", "gzip"]): - continue - # 'requests' collapses multiple Set-Cookies response headers - # into one (comma-separated list of cookie definitions). That - # breaks browsers' cookie acceptance, resulting in HTTP sessions - # being lost. A typical example is the blog shop not functioning - # for this reason. - # - # Skipping here, as it appears to _still_ collapse them, even if - # each one is individually set. Trying below via the "final" flask - # Response object. - if k == "Set-Cookie": - continue - headers.set(k, resp.headers[k]) - - Resp = Response( - response=resp.text, - status=resp.status_code, - headers=headers, - ) - if "Set-Cookie" in resp.headers: - cookies = resp.headers["Set-Cookie"].split(",") - for cookie in cookies: - Resp.headers.add("Set-Cookie", cookie.strip()) - return Resp - - def get_app(self): - return self - - # Globals sharead accross multiple sub-commands: # needed to configure and launch the reverse proxy. -REV_PROXY_NETLOC = "localhost:8080" +REV_PROXY_HOSTNAME = "localhost" +REV_PROXY_PORT = "8080" +REV_PROXY_NETLOC = REV_PROXY_HOSTNAME + ":" + REV_PROXY_PORT REV_PROXY_PROTO = "http" REV_PROXY_URL = f"{REV_PROXY_PROTO}://{REV_PROXY_NETLOC}" UNIX_SOCKETS_DIR = TALER_ROOT_DIR / "sockets" @@ -586,11 +456,33 @@ def prepare(): """Generate configuration, run-time blobs, instances, euFin accounts.""" - def fail(reason=None, proxy_proc=None): + def is_serving(check_url, tries=10): + for i in range(tries): + try: + print_nn(".") + # Raises if the service is not reachable. + response = requests.get( + check_url, + timeout=1 + ) + # The reverse proxy may return 500 if the + # end service is not ready, therefore this + # case should be tolerated. + response.raise_for_status() + except: + time.sleep(0.5) + if i == tries - 1: + return False + continue + break + return True + + + + def fail(reason=None): if reason: - print("ERROR: " + reason) - if proxy_proc: - print(f"Proxy logs in: {proxy_proc.get_log_filename()}") + print("ERROR:", reason) + print(f"Logs in {LOG_DIR}") exit(1) def kill(proc): @@ -810,7 +702,7 @@ def prepare(): FRONTENDS_API_TOKEN = "secret-token:secret" TALER_MERCHANT_TOKEN = "secret-token:secret" ALL_INSTANCES_BANK_PASSWORD = "secret" - EXCHANGE_BANK_ACCOUNT_SANDBOX = "exchange-account-sandbox" + EXCHANGE_BANK_ACCOUNT_SANDBOX = "sandbox-account-exchange" EXCHANGE_BANK_ACCOUNT_PASSWORD = "secret" # EBICS @@ -841,28 +733,6 @@ def prepare(): self.log_dir = log_dir self.env = env - @staticmethod - def is_serving(check_url, tries=10): - for i in range(tries): - try: - print_nn(".") - # Raises if the service is not reachable. - response = requests.get( - check_url, - timeout=1 - ) - # The reverse proxy may return 500 if the - # end service is not ready, therefore this - # case should be tolerated. - response.raise_for_status() - except: - time.sleep(0.5) - if i == tries - 1: - return False - continue - break - return True - def run(self): self.do() return_code = self.handle.wait() @@ -872,15 +742,6 @@ def prepare(): if self.capture_stdout: return self.handle.communicate()[0].decode("utf-8").rstrip() - def launch(self): - self.do() - return self - - def stop(self): - self.cleanup() - self.handle.terminate() - self.handle.wait() - def get_log_filename(self): return self.log_file.name @@ -907,7 +768,6 @@ def prepare(): ) except Exception as error: fail(f"Could not execute: {' '.join(self.cmd)}: {error}") - atexit.register(self.stop) class ConfigFile: def __init__(self, filename): @@ -1090,7 +950,7 @@ def prepare(): obj.cfg_put("exchange-account-1", "enable_debit", "yes") obj.cfg_put("exchange-account-1", "enable_credit", "yes") obj.cfg_put("merchant-account-merchant", "payto_uri", - f"payto://{wire_method}/{rev_proxy_url + '/bank'}/{merchant_wire_address}" + f"payto://{wire_method}/{rev_proxy_url + '/sandbox'}/{merchant_wire_address}" ) obj.cfg_put("merchant-account-merchant", "wire_response", @@ -1141,9 +1001,24 @@ def prepare(): obj.cfg_put("authorization-question", "cost", f"{currency}:0") obj.cfg_put("authorization-question", "enabled", "yes") obj.cfg_write(outdir) + + def unit_file_content(description, cmd, env=None): + executable_name = cmd.split(" ")[0].split("/")[-1] + content = ( + "[Unit]\n" + f"Description={description}\n" + "[Service]\n" + f"ExecStart={cmd}\n" + f"StandardOutput=append:{LOG_DIR / executable_name}.log\n" + f"StandardError=append:{LOG_DIR / executable_name}.log" + ) + if env: + content += f"\nEnvironmentFile={env}" + return content + print_nn("Ensure no service is running...") - if Command.is_serving(REV_PROXY_URL + "/", tries=3): + if is_serving(REV_PROXY_URL + "/", tries=3): fail("Reverse proxy is unexpectedly running!") if UNIX_SOCKETS_DIR.is_dir(): for left_socket in os.listdir(UNIX_SOCKETS_DIR): @@ -1177,6 +1052,128 @@ def prepare(): taler_runtime_dir=TALER_RUNTIME_DIR ) print(" OK") + + print_nn("Installing SystemD unit files...") + if not systemd_user_dir.exists(): + systemd_user_dir.mkdir(parents=True, exist_ok=True) + + if not TALER_UNIT_FILES_DIR.exists(): + TALER_UNIT_FILES_DIR.mkdir(parents=True, exist_ok=True) + + # Exchange HTTPD unit file. + with open(TALER_UNIT_FILES_DIR / "taler-local-exchange-httpd.service", "w") as exchange_unit: + exchange_unit.write(unit_file_content( + description = "Taler Exchange HTTP daemon", + cmd = f"{TALER_PREFIX}/bin/taler-exchange-httpd -L DEBUG -c {CFG_OUTDIR / 'taler.conf'}", + env = TALER_UNIT_FILES_DIR / "taler-local-postgres.env" if os.environ.get("PGPORT") else None + )) + with open(TALER_UNIT_FILES_DIR / "taler-local-exchange-wirewatch.service", "w") as exchange_wirewatch_unit: + exchange_wirewatch_unit.write(unit_file_content( + description = "Taler Exchange Wirewatch", + cmd = f"{TALER_PREFIX}/bin/taler-exchange-wirewatch -L DEBUG -c {CFG_OUTDIR / 'taler.conf'}", + env = TALER_UNIT_FILES_DIR / "taler-local-postgres.env" if os.environ.get("PGPORT") else None + )) + with open(TALER_UNIT_FILES_DIR / "taler-local-exchange-aggregator.service", "w") as exchange_aggregator_unit: + exchange_aggregator_unit.write(unit_file_content( + description = "Taler Exchange Aggregator", + cmd = f"{TALER_PREFIX}/bin/taler-exchange-aggregator -L DEBUG -c {CFG_OUTDIR / 'taler.conf'}", + env = TALER_UNIT_FILES_DIR / "taler-local-postgres.env" if os.environ.get("PGPORT") else None + )) + with open(TALER_UNIT_FILES_DIR / "taler-local-exchange-secmod-rsa.service", "w") as exchange_rsa_unit: + exchange_rsa_unit.write(unit_file_content( + description = "Taler Exchange RSA security module", + cmd = f"{TALER_PREFIX}/bin/taler-exchange-secmod-rsa -L DEBUG -c {CFG_OUTDIR / 'taler.conf'}" + )) + with open(TALER_UNIT_FILES_DIR / "taler-local-exchange-secmod-eddsa.service", "w") as exchange_eddsa_unit: + exchange_eddsa_unit.write(unit_file_content( + description = "Taler Exchange EDDSA security module", + cmd = f"{TALER_PREFIX}/bin/taler-exchange-secmod-eddsa -L DEBUG -c {CFG_OUTDIR / 'taler.conf'}" + )) + with open(TALER_UNIT_FILES_DIR / "taler-local-merchant-backend.service", "w") as merchant_unit: + merchant_unit.write(unit_file_content( + description = "Taler Merchant backend", + cmd = f"{TALER_PREFIX}/bin/taler-merchant-httpd -L DEBUG -c {CFG_OUTDIR / 'taler.conf'}", + env = TALER_UNIT_FILES_DIR / "taler-local-postgres.env" if os.environ.get("PGPORT") else None + )) + with open(TALER_UNIT_FILES_DIR / "taler-local-merchant-backend-token.service", "w") as merchant_token_unit: + merchant_token_unit.write(unit_file_content( + description = "Taler Merchant backend with auth token to allow default instance creation.", + cmd = f"{TALER_PREFIX}/bin/taler-merchant-httpd -a {TALER_MERCHANT_TOKEN} -L DEBUG -c {CFG_OUTDIR / 'taler.conf'}", + env = TALER_UNIT_FILES_DIR / "taler-local-postgres.env" if os.environ.get("PGPORT") else None + )) + # Custom Postgres connection. + if os.environ.get("PGPORT"): + with open(TALER_UNIT_FILES_DIR / "taler-local-postgres.env", "w") as postgres_env: + postgres_env.write(f"PGPORT={os.environ.get('PGPORT')}") + + # euFin unit files. + with open(TALER_UNIT_FILES_DIR / "taler-local-sandbox.service", "w") as sandbox_unit: + sandbox_unit.write(unit_file_content( + description = "euFin Sandbox", + cmd = f"{TALER_PREFIX}/bin/libeufin-sandbox serve --with-unix-socket {UNIX_SOCKETS_DIR / 'sandbox.sock'}", + env = TALER_UNIT_FILES_DIR / "taler-local-sandbox.env" + )) + with open(TALER_UNIT_FILES_DIR / "taler-local-nexus.service", "w") as nexus_unit: + nexus_unit.write(unit_file_content( + description = "euFin Nexus", + cmd = f"{TALER_PREFIX}/bin/libeufin-nexus serve --with-unix-socket {UNIX_SOCKETS_DIR / 'nexus.sock'}", + env = TALER_UNIT_FILES_DIR / "taler-local-nexus.env" + )) + # euFin env files. + with open(TALER_UNIT_FILES_DIR / "taler-local-sandbox.env", "w") as sandbox_env: + sandbox_env.write(f"LIBEUFIN_SANDBOX_DB_CONNECTION=jdbc:sqlite:{SANDBOX_DB_FILE}\n") + sandbox_env.write(f"LIBEUFIN_SANDBOX_ADMIN_PASSWORD={SANDBOX_ADMIN_PASSWORD}") + with open(TALER_UNIT_FILES_DIR / "taler-local-nexus.env", "w") as nexus_env: + nexus_env.write(f"LIBEUFIN_NEXUS_DB_CONNECTION=jdbc:sqlite:{NEXUS_DB_FILE}\n") + + with open(TALER_UNIT_FILES_DIR / "taler-local-donations.service", "w") as donations_unit: + donations_unit.write(unit_file_content( + description = "Donation Website that accepts Taler payments.", + cmd = f"{TALER_PREFIX}/bin/taler-merchant-demos donations -c {CFG_OUTDIR / 'taler.conf'}", + env = TALER_UNIT_FILES_DIR / "taler-frontends-local.env" + )) + with open(TALER_UNIT_FILES_DIR / "taler-local-blog.service", "w") as blog_unit: + blog_unit.write(unit_file_content( + description = "Blog that accepts Taler payments.", + cmd = f"{TALER_PREFIX}/bin/taler-merchant-demos blog -c {CFG_OUTDIR / 'taler.conf'}", + env = TALER_UNIT_FILES_DIR / "taler-frontends-local.env" + )) + with open(TALER_UNIT_FILES_DIR / "taler-local-survey.service", "w") as survey_unit: + survey_unit.write(unit_file_content( + description = "Survey Website awarding tips via Taler.", + cmd = f"{TALER_PREFIX}/bin/taler-merchant-demos survey -c {CFG_OUTDIR / 'taler.conf'}", + env = TALER_UNIT_FILES_DIR / "taler-frontends-local.env" + )) + with open(TALER_UNIT_FILES_DIR / "taler-local-landing.service", "w") as landing_unit: + landing_unit.write(unit_file_content( + description = "Landing Website of Taler demo.", + cmd = f"{TALER_PREFIX}/bin/taler-merchant-demos landing -c {CFG_OUTDIR / 'taler.conf'}", + env = TALER_UNIT_FILES_DIR / "taler-frontends-local.env" + )) + with open(TALER_UNIT_FILES_DIR / "taler-local-frontends.env", "w") as frontends_env: + frontends_env.write(( + f"PATH={os.environ.get('PATH')}\n" + f"TALER_CONFIG_FILE={CFG_OUTDIR / 'taler.conf'}\n" + f"TALER_ENV_URL_INTRO={REV_PROXY_URL + '/landing/'}\n" + f"TALER_ENV_URL_BANK={SANDBOX_URL + '/'}\n" + f"TALER_ENV_URL_MERCHANT_BLOG={REV_PROXY_URL + '/blog/'}\n" + f"TALER_ENV_URL_MERCHANT_DONATIONS={REV_PROXY_URL + '/donations/'}\n" + f"TALER_ENV_URL_MERCHANT_SURVEY={REV_PROXY_URL + '/survey/'}\n" + )) + with open(TALER_UNIT_FILES_DIR / "taler-local-nginx.service", "w") as nginx_unit: + nginx_unit.write(unit_file_content( + description = "Nginx: reverse proxy for taler-local.", + cmd = f"nginx -c {CFG_OUTDIR / 'nginx.conf'}", + )) + print(" OK") + print_nn("Reload SystemD...") + Command(["systemctl", "--user", "daemon-reload"]).run() + atexit.register(lambda: subprocess.run( + ["systemctl", "--user", "stop", "taler-local-*.service"], + check=True + ) + ) + print(" OK") print_nn("Generate exchange's master key...") EXCHANGE_MASTER_PUB = Command( [ @@ -1221,42 +1218,46 @@ def prepare(): "--reset"] ).run() print(" OK") + print_nn("Launching the reverse proxy...") - rev_proxy = TalerReverseProxy( - LOG_DIR, - UNIX_SOCKETS_DIR, - REV_PROXY_PROTO, - REV_PROXY_NETLOC - ) - rev_proxy.start() - if not Command.is_serving(REV_PROXY_URL + "/"): - fail(f"Reverse proxy did not start correctly. \ -Logs: {rev_proxy.get_log_filename()}" - ) + with open(CFG_OUTDIR / "nginx.conf", "w") as nginx_conf: + nginx_conf.write(( + f"error_log {LOG_DIR / 'nginx.log'};\n" + f"pid {TALER_ROOT_DIR / 'nginx.pid'};\n" + "daemon off;\n" + "events {}\n" + "http {\n" + f"access_log {LOG_DIR / 'nginx.log'};\n" + "server {\n" + f"listen {REV_PROXY_PORT};\n" + "location / {\n" + "return 200 'Hello, I am Nginx - proxying taler-local';\n" + "}\n" + "location ~* ^/(?<component>[a-z\-]+)(/(?<taler_uri>.*))? {\n" + "proxy_pass http://unix:/home/job/.taler/sockets/$component.sock:/$taler_uri?$args;\n" + "proxy_redirect off;\n" + "proxy_set_header X-Forwarded-Prefix /$component;\n" + f"proxy_set_header X-Forwarded-Host {REV_PROXY_NETLOC};\n" + f"proxy_set_header X-Forwarded-Proto {REV_PROXY_PROTO};\n" + "}\n" + "}\n" + "}\n" + )) + subprocess.run(["systemctl", "--user", "start", "taler-local-nginx.service"], check=True) + if not is_serving(REV_PROXY_URL + "/"): + fail(f"Reverse proxy did not start correctly") # Do check. print(" OK") print_nn("Launching the exchange RSA helper...") - exchange_rsa_handle = Command([ - "taler-exchange-secmod-rsa", - "-c", CFG_OUTDIR / "taler.conf" - ]).launch() + subprocess.run(["systemctl", "--user", "start", "taler-local-exchange-secmod-rsa.service"]) print(" OK") print_nn("Launching the exchange EDDSA helper...") - exchange_eddsa_handle = Command([ - "taler-exchange-secmod-eddsa", - "-c", CFG_OUTDIR / "taler.conf" - ]).launch() + subprocess.run(["systemctl", "--user", "start", "taler-local-exchange-secmod-eddsa.service"]) print(" OK") print_nn("Launching the exchange...") - exchange_handle = Command([ - "taler-exchange-httpd", - "-c", CFG_OUTDIR / "taler.conf" - ]).launch() - if not Command.is_serving(REV_PROXY_URL + "/exchange/"): - fail( - f"Exchange did not start correctly. Logs: {exchange_handle.get_log_filename()}", - rev_proxy - ) + subprocess.run(["systemctl", "--user", "start", "taler-local-exchange-httpd.service"]) + if not is_serving(REV_PROXY_URL + "/exchange/"): + fail(f"Exchange did not start correctly.") print(" OK") print_nn("exchange-offline: signing key material...") Command([ @@ -1313,22 +1314,9 @@ Logs: {rev_proxy.get_log_filename()}" # This step transparantly creates a default demobank. print_nn("Launching Sandbox...") - sandbox_handle = Command( - [ - "libeufin-sandbox", "serve", - "--with-unix-socket", UNIX_SOCKETS_DIR / "sandbox.sock", - ], - env=get_sandbox_server_env( - SANDBOX_DB_FILE, - SANDBOX_URL, - SANDBOX_ADMIN_PASSWORD - ) - ).launch() - if not Command.is_serving(SANDBOX_URL): - fail( - f"Sandbox did not start correctly. Logs: {sandbox_handle.get_log_filename()}", - rev_proxy - ) + subprocess.run(["systemctl", "--user", "start", "taler-local-sandbox.service"]) + if not is_serving(SANDBOX_URL): + fail(f"Sandbox did not start correctly.") print(" OK") print_nn("Make Sandbox EBICS host...") Command( @@ -1365,24 +1353,20 @@ Logs: {rev_proxy.get_log_filename()}" ) EXCHANGE_PAYTO = exchange_bank_account_info["paytoUri"] print(" OK") - print_nn("Specify own payto-URI to exchange's configuration.") + print_nn("Specify own payto-URI to exchange's configuration..") Command([ - "taler-config", "-s", "exchange-account-1", - "-o", "payto_uri", "-V", EXCHANGE_PAYTO + "taler-config", "-c", CFG_OUTDIR / 'taler.conf', + "-s", "exchange-account-1", "-o", "payto_uri", "-V", + EXCHANGE_PAYTO ]).run() print(" OK") print_nn(f"exchange-offline: enabling {EXCHANGE_PAYTO}...") Command([ "taler-exchange-offline", "-c", CFG_OUTDIR / "taler.conf", - "enable-account", EXCHANGE_PAYTO, "upload"] - ).run() + "enable-account", EXCHANGE_PAYTO, "upload" + ]).run() print(" OK") - print_nn("Stopping exchange HTTP daemon and crypto helpers...") - exchange_rsa_handle.stop() - exchange_eddsa_handle.stop() - exchange_handle.stop() - print(" OK") # Give each instance a Sandbox account (note: 'default') # won't have one, as it should typically only manage other @@ -1426,18 +1410,9 @@ Logs: {rev_proxy.get_log_filename()}" print(" OK") print_nn("Launching Nexus...") - nexus_handle = Command( - [ - "libeufin-nexus", "serve", - "--with-unix-socket", UNIX_SOCKETS_DIR / "nexus.sock" - ], - env=get_nexus_server_env(NEXUS_DB_FILE, NEXUS_URL) - ).launch() - if not Command.is_serving(NEXUS_URL): - fail( - f"Nexus did not start correctly. Logs: {nexus_handle.get_log_filename()}", - rev_proxy - ) + subprocess.run(["systemctl", "--user", "start", "taler-local-nexus.service"]) + if not is_serving(NEXUS_URL): + fail(f"Nexus did not start correctly") print(" OK") print_nn("Create Exchange account at Nexus...") @@ -1485,12 +1460,9 @@ Logs: {rev_proxy.get_log_filename()}" ) response.raise_for_status() except Exception as error: - fail(error, rev_proxy) + fail(error) FACADE_URL=response.json().get("facades")[0].get("baseUrl") - print_nn("Terminating Nexus...") - nexus_handle.stop() - print(" OK") print_nn("Set suggested exchange at Sandbox...") Command([ "libeufin-sandbox", @@ -1599,21 +1571,14 @@ Logs: {rev_proxy.get_log_filename()}" headers = auth_header ) if resp.status_code < 200 or resp.status_code >= 300: - print(f"Could not create (or patch) instance '{instance_id}'") print(f"Backend responds: {resp.status_code}/{resp.text}") - fail(proxy_proc=rev_proxy) + fail(f"Could not create (or patch) instance '{instance_id}'") print_nn(f"Start merchant (with TALER_MERCHANT_TOKEN into the env)...") - auth_env = os.environ.copy() - auth_env["TALER_MERCHANT_TOKEN"] = TALER_MERCHANT_TOKEN - merchant_handle = Command( - ["taler-merchant-httpd", "-c", CFG_OUTDIR / "taler.conf"], - env=auth_env - ).launch() - if not Command.is_serving(REV_PROXY_URL + "/merchant-backend/config"): + subprocess.run(["systemctl", "--user", "start", "taler-local-merchant-backend-token.service"], check=True) + if not is_serving(REV_PROXY_URL + "/merchant-backend/config"): fail( - f"Merchant backend did not start correctly. Logs: {merchant_handle.get_log_filename()}", - rev_proxy + f"Merchant backend did not start correctly.", ) print(" OK") print_nn("Give default instance a bank account...") @@ -1636,18 +1601,12 @@ Logs: {rev_proxy.get_log_filename()}" merchant_wire_address = IBAN_MERCHANT_DEFAULT, auth_token=FRONTENDS_API_TOKEN ) - print_nn("Stopping the merchant...") - merchant_handle.stop() - print(" OK") print_nn("Restarting the merchant WITHOUT the auth-token in the env...") - merchant_handle.launch() - if not Command.is_serving(REV_PROXY_URL + "/merchant-backend/config"): + subprocess.run(["systemctl", "--user", "start", "taler-local-merchant-backend.service"], check=True) + if not is_serving(REV_PROXY_URL + "/merchant-backend/config"): # check_running logs errors already. - fail( - f"Merchant backend did not re start correctly. Logs: {merchant_handle.get_log_filename()}", - rev_proxy - ) + fail(f"Merchant backend did not re start correctly.") print(" OK") for instance_id, iban in INSTANCES.items(): @@ -1662,174 +1621,25 @@ Logs: {rev_proxy.get_log_filename()}" auth_token=FRONTENDS_API_TOKEN ) print(" OK") - print_nn("Terminating Sandbox...") - sandbox_handle.stop() - print(" OK") - print_nn("Stopping the merchant backend...") - merchant_handle.stop() - print(" OK") - print_nn("Stopping the reverse proxy...") - rev_proxy.stop() - print(" OK") - - print_nn("Installing SystemD unit files...") - - if not systemd_user_dir.exists(): - systemd_user_dir.mkdir(parents=True, exist_ok=True) - - if not TALER_UNIT_FILES_DIR.exists(): - TALER_UNIT_FILES_DIR.mkdir(parents=True, exist_ok=True) - - def unit_file_content(description, cmd, env=None): - executable_name = cmd.split(" ")[0].split("/")[-1] - content = ( - "[Unit]\n" - f"Description={description}\n" - "[Service]\n" - f"ExecStart={cmd}\n" - f"StandardOutput=append:{LOG_DIR / executable_name}.log\n" - f"StandardError=append:{LOG_DIR / executable_name}.log" - ) - if env: - content += f"\nEnvironmentFile={env}" - return content - - # Exchange HTTPD unit file. - with open(TALER_UNIT_FILES_DIR / "taler-exchange-httpd-local.service", "w") as exchange_unit: - exchange_unit.write(unit_file_content( - description = "Taler Exchange HTTP daemon", - cmd = f"{TALER_PREFIX}/bin/taler-exchange-httpd -L DEBUG -c {CFG_OUTDIR / 'taler.conf'}", - env = TALER_UNIT_FILES_DIR / "taler-postgres-local.env" if os.environ.get("PGPORT") else None - )) - with open(TALER_UNIT_FILES_DIR / "taler-exchange-wirewatch-local.service", "w") as exchange_wirewatch_unit: - exchange_wirewatch_unit.write(unit_file_content( - description = "Taler Exchange Wirewatch", - cmd = f"{TALER_PREFIX}/bin/taler-exchange-wirewatch -L DEBUG -c {CFG_OUTDIR / 'taler.conf'}", - env = TALER_UNIT_FILES_DIR / "taler-postgres-local.env" if os.environ.get("PGPORT") else None - )) - with open(TALER_UNIT_FILES_DIR / "taler-exchange-secmod-rsa-local.service", "w") as exchange_rsa_unit: - exchange_rsa_unit.write(unit_file_content( - description = "Taler Exchange RSA security module", - cmd = f"{TALER_PREFIX}/bin/taler-exchange-secmod-rsa -L DEBUG -c {CFG_OUTDIR / 'taler.conf'}" - )) - with open(TALER_UNIT_FILES_DIR / "taler-exchange-secmod-eddsa-local.service", "w") as exchange_eddsa_unit: - exchange_eddsa_unit.write(unit_file_content( - description = "Taler Exchange EDDSA security module", - cmd = f"{TALER_PREFIX}/bin/taler-exchange-secmod-eddsa -L DEBUG -c {CFG_OUTDIR / 'taler.conf'}" - )) - with open(TALER_UNIT_FILES_DIR / "taler-merchant-httpd-local.service", "w") as merchant_unit: - merchant_unit.write(unit_file_content( - description = "Taler Merchant backend", - cmd = f"{TALER_PREFIX}/bin/taler-merchant-httpd -L DEBUG -c {CFG_OUTDIR / 'taler.conf'}", - env = TALER_UNIT_FILES_DIR / "taler-postgres-local.env" if os.environ.get("PGPORT") else None - )) - # Custom Postgres connection. - if os.environ.get("PGPORT"): - with open(TALER_UNIT_FILES_DIR / "taler-postgres-local.env", "w") as postgres_env: - postgres_env.write(f"PGPORT={os.environ.get('PGPORT')}") - - # euFin unit files. - with open(TALER_UNIT_FILES_DIR / "libeufin-sandbox-local.service", "w") as sandbox_unit: - sandbox_unit.write(unit_file_content( - description = "euFin Sandbox", - cmd = f"{TALER_PREFIX}/bin/libeufin-sandbox serve --with-unix-socket {UNIX_SOCKETS_DIR / 'sandbox.sock'}", - env = TALER_UNIT_FILES_DIR / "libeufin-sandbox-local.env" - )) - with open(TALER_UNIT_FILES_DIR / "libeufin-nexus-local.service", "w") as nexus_unit: - nexus_unit.write(unit_file_content( - description = "euFin Nexus", - cmd = f"{TALER_PREFIX}/bin/libeufin-nexus serve --with-unix-socket {UNIX_SOCKETS_DIR / 'nexus.sock'}", - env = TALER_UNIT_FILES_DIR / "libeufin-nexus-local.env" - )) - # euFin env files. - with open(TALER_UNIT_FILES_DIR / "libeufin-sandbox-local.env", "w") as sandbox_env: - sandbox_env.write(f"LIBEUFIN_SANDBOX_DB_CONNECTION=jdbc:sqlite:{SANDBOX_DB_FILE}\n") - sandbox_env.write(f"LIBEUFIN_SANDBOX_ADMIN_PASSWORD={SANDBOX_ADMIN_PASSWORD}") - with open(TALER_UNIT_FILES_DIR / "libeufin-nexus-local.env", "w") as nexus_env: - nexus_env.write(f"LIBEUFIN_NEXUS_DB_CONNECTION=jdbc:sqlite:{NEXUS_DB_FILE}\n") - - with open(TALER_UNIT_FILES_DIR / "taler-donations-local.service", "w") as donations_unit: - donations_unit.write(unit_file_content( - description = "Donation Website that accepts Taler payments.", - cmd = f"{TALER_PREFIX}/bin/taler-merchant-demos donations -c {CFG_OUTDIR / 'taler.conf'}", - env = TALER_UNIT_FILES_DIR / "taler-frontends-local.env" - )) - with open(TALER_UNIT_FILES_DIR / "taler-blog-local.service", "w") as blog_unit: - blog_unit.write(unit_file_content( - description = "Blog that accepts Taler payments.", - cmd = f"{TALER_PREFIX}/bin/taler-merchant-demos blog -c {CFG_OUTDIR / 'taler.conf'}", - env = TALER_UNIT_FILES_DIR / "taler-frontends-local.env" - )) - with open(TALER_UNIT_FILES_DIR / "taler-survey-local.service", "w") as survey_unit: - survey_unit.write(unit_file_content( - description = "Survey Website awarding tips via Taler.", - cmd = f"{TALER_PREFIX}/bin/taler-merchant-demos survey -c {CFG_OUTDIR / 'taler.conf'}", - env = TALER_UNIT_FILES_DIR / "taler-frontends-local.env" - )) - with open(TALER_UNIT_FILES_DIR / "taler-landing-local.service", "w") as landing_unit: - landing_unit.write(unit_file_content( - description = "Landing Website of Taler demo.", - cmd = f"{TALER_PREFIX}/bin/taler-merchant-demos landing -c {CFG_OUTDIR / 'taler.conf'}", - env = TALER_UNIT_FILES_DIR / "taler-frontends-local.env" - )) - with open(TALER_UNIT_FILES_DIR / "taler-frontends-local.env", "w") as frontends_env: - frontends_env.write(( - f"PATH={os.environ.get('PATH')}\n" - f"TALER_CONFIG_FILE={CFG_OUTDIR / 'taler.conf'}\n" - f"TALER_ENV_URL_INTRO={REV_PROXY_URL + '/landing/'}\n" - f"TALER_ENV_URL_BANK={SANDBOX_URL + '/'}\n" - f"TALER_ENV_URL_MERCHANT_BLOG={REV_PROXY_URL + '/blog/'}\n" - f"TALER_ENV_URL_MERCHANT_DONATIONS={REV_PROXY_URL + '/donations/'}\n" - f"TALER_ENV_URL_MERCHANT_SURVEY={REV_PROXY_URL + '/survey/'}\n" - )) - print(" OK") - - # more units here.. - print_nn("Reload SystemD...") - Command(["systemctl", "--user", "daemon-reload"]).run() - print(" OK") @cli.command() def launch(): + subprocess.run(["systemctl", "--user", "start", "taler-local-nginx.service"], check=True) + subprocess.run(["systemctl", "--user", "start", "taler-local-exchange-secmod-rsa.service"], check=True) + subprocess.run(["systemctl", "--user", "start", "taler-local-exchange-secmod-eddsa.service"], check=True) + subprocess.run(["systemctl", "--user", "start", "taler-local-exchange-httpd.service"], check=True) + subprocess.run(["systemctl", "--user", "start", "taler-local-exchange-wirewatch.service"], check=True) + subprocess.run(["systemctl", "--user", "start", "taler-local-exchange-aggregator.service"], check=True) + subprocess.run(["systemctl", "--user", "start", "taler-local-merchant-backend.service"], check=True) + subprocess.run(["systemctl", "--user", "start", "taler-local-sandbox.service"], check=True) + subprocess.run(["systemctl", "--user", "start", "taler-local-nexus.service"], check=True) + subprocess.run(["systemctl", "--user", "start", "taler-local-donations.service"], check=True) + subprocess.run(["systemctl", "--user", "start", "taler-local-blog.service"], check=True) + subprocess.run(["systemctl", "--user", "start", "taler-local-survey.service"], check=True) - subprocess.run(["systemctl", "--user", "start", "taler-exchange-httpd-local.service"], check=True) - subprocess.run(["systemctl", "--user", "start", "taler-exchange-wirewatch-local.service"], check=True) - subprocess.run(["systemctl", "--user", "start", "taler-exchange-secmod-rsa-local.service"], check=True) - subprocess.run(["systemctl", "--user", "start", "taler-exchange-secmod-eddsa-local.service"], check=True) - subprocess.run(["systemctl", "--user", "start", "taler-merchant-httpd-local.service"], check=True) - subprocess.run(["systemctl", "--user", "start", "libeufin-nexus-local.service"], check=True) - subprocess.run(["systemctl", "--user", "start", "libeufin-sandbox-local.service"], check=True) - subprocess.run(["systemctl", "--user", "start", "taler-donations-local.service"], check=True) - subprocess.run(["systemctl", "--user", "start", "taler-blog-local.service"], check=True) - subprocess.run(["systemctl", "--user", "start", "taler-survey-local.service"], check=True) - subprocess.run(["systemctl", "--user", "start", "taler-landing-local.service"], check=True) - - rev_proxy = TalerReverseProxy( - LOG_DIR, - UNIX_SOCKETS_DIR, - REV_PROXY_PROTO, - REV_PROXY_NETLOC - ) - netloc_parts = REV_PROXY_NETLOC.split(":") - rev_proxy.run( - host=netloc_parts[0], - port=netloc_parts[1], - debug=False - ) - # Stop with CTRL+C - print_nn("Stopping the services...") - subprocess.run(["systemctl", "--user", "stop", "taler-landing-local.service"], check=True) - subprocess.run(["systemctl", "--user", "stop", "taler-survey-local.service"], check=True) - subprocess.run(["systemctl", "--user", "stop", "taler-blog-local.service"], check=True) - subprocess.run(["systemctl", "--user", "stop", "taler-donations-local.service"], check=True) - subprocess.run(["systemctl", "--user", "stop", "libeufin-sandbox-local.service"], check=True) - subprocess.run(["systemctl", "--user", "stop", "libeufin-nexus-local.service"], check=True) - subprocess.run(["systemctl", "--user", "stop", "taler-merchant-httpd-local.service"], check=True) - subprocess.run(["systemctl", "--user", "stop", "taler-exchange-secmod-eddsa-local.service"], check=True) - subprocess.run(["systemctl", "--user", "stop", "taler-exchange-secmod-rsa-local.service"], check=True) - subprocess.run(["systemctl", "--user", "stop", "taler-exchange-wirewatch-local.service"], check=True) - subprocess.run(["systemctl", "--user", "stop", "taler-exchange-httpd-local.service"], check=True) - print(" OK") +@cli.command() +def stop(): + subprocess.run(["systemctl", "--user", "stop", "taler-local-*.service"], check=True) @cli.command() def withdraw(): |