diff options
author | ms <ms@taler.net> | 2021-09-27 18:15:30 +0200 |
---|---|---|
committer | ms <ms@taler.net> | 2021-09-27 18:15:30 +0200 |
commit | 1a41de419330ab450ff524583eebe758a3b39672 (patch) | |
tree | cfba2968bdffcaf6b2d65ba820dbbc5cce5120d2 | |
parent | 78a499ecc87544b5ca95acf1d6addd05c7153cf5 (diff) | |
download | deployment-1a41de419330ab450ff524583eebe758a3b39672.tar.gz deployment-1a41de419330ab450ff524583eebe758a3b39672.tar.bz2 deployment-1a41de419330ab450ff524583eebe758a3b39672.zip |
taler-local: arranging code, check state before starting
-rwxr-xr-x | bin/WIP/taler-local | 620 |
1 files changed, 365 insertions, 255 deletions
diff --git a/bin/WIP/taler-local b/bin/WIP/taler-local index af7d633..6bfcbca 100755 --- a/bin/WIP/taler-local +++ b/bin/WIP/taler-local @@ -15,6 +15,8 @@ # You should have received a copy of the GNU General Public License # along with GNU Taler. If not, see <https://www.gnu.org/licenses/>. +import signal +import socket import shutil import atexit import click @@ -35,7 +37,7 @@ from shutil import copy from multiprocessing import Process from string import ascii_letters, ascii_uppercase from sys import exit -from urllib.parse import urljoin +from urllib.parse import urljoin, quote from os import remove import requests from collections import OrderedDict @@ -48,6 +50,12 @@ from flask import Flask, request, Response from werkzeug.datastructures import Headers from werkzeug.exceptions import HTTPException + +TALER_ROOT_DIR = Path.home() / ".taler" +# Print No Newline. +def print_nn(msg): + print(msg, end="") + @dataclass class Repo: name: str @@ -295,7 +303,7 @@ repos = { } def get_repos_names() -> List[str]: - r_dir = Path.home() / ".taler-sources" + r_dir = TALER_ROOT_DIR / "sources" return [el for el in listdir(r_dir) if isdir(join(r_dir, el)) and repos.get(el)] # Get the installed repositories from the sources directory. @@ -304,7 +312,7 @@ def load_repos(reposNames) -> List[Repo]: def update_repos(repos: List[Repo]) -> None: for r in repos: - r_dir = Path.home() / ".taler-sources" / r.name + r_dir = TALER_ROOT_DIR / "sources" / r.name subprocess.run(["git", "-C", str(r_dir), "fetch"], check=True) res = subprocess.run( ["git", "-C", str(r_dir), "status", "-sb"], @@ -322,7 +330,7 @@ def get_stale_repos(repos: List[Repo]) -> List[Repo]: timestamps = {} stale = [] for r in repos: - r_dir = Path.home() / ".taler-sources" / r.name + r_dir = TALER_ROOT_DIR / "sources" / r.name s = r_dir / "taler-buildstamp" if not s.exists(): timestamps[r.name] = time.time() @@ -367,23 +375,10 @@ def build(without_repos) -> None: diff = set(r.deps) - set(repos_names) if len(diff) > 0: print(f"WARNING: those dependencies are not being built: {diff}") - p = Path.home() / ".taler-sources" / r.name + p = TALER_ROOT_DIR / "sources" / r.name os.chdir(str(p)) r.builder(r, p) -# Download the repository. -def checkout_repos(repos: List[Repo]): - if len(repos) == 0: - print("No repositories can be checked out. Spelled correctly?") - return - home = Path.home() - sources = home / ".taler-sources" - for r in repos: - r_dir = home / ".taler-sources" / r.name - if not r_dir.exists(): - r_dir.mkdir(parents=True, exist_ok=True) - subprocess.run(["git", "-C", str(sources), "clone", r.url], check=True) - @cli.command() @click.option( "--repos", "-r", @@ -395,20 +390,50 @@ def checkout_repos(repos: List[Repo]): def bootstrap(repos) -> None: """Clone all the specified repositories.""" - home = Path.home() + + # Download the repository. + def checkout_repos(repos: List[Repo]): + if len(repos) == 0: + print("No repositories can be checked out. Spelled correctly?") + return + sources = TALER_ROOT_DIR / "sources" + for r in repos: + r_dir = sources / r.name + if not r_dir.exists(): + r_dir.mkdir(parents=True, exist_ok=True) + subprocess.run(["git", "-C", str(sources), "clone", r.url], check=True) + reposList = split_repos_list(repos) checkout_repos(load_repos(reposList)) class TalerReverseProxy(Flask): + def __init__(self, log_dir, unix_sockets_dir): + 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.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() del os.environ["WERKZEUG_RUN_MAIN"] + def get_log_filename(self): + return self.logger.handlers[0].baseFilename + def start(self): - logging.basicConfig(filename="/tmp/reverse-proxy.log", filemode="a") - logger = logging.getLogger("werkzeug") - logger.setLevel(logging.DEBUG) + 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) self.proc = Process( target=self.run, kwargs=dict(debug=False, port=8080, host="localhost") @@ -424,7 +449,8 @@ class TalerReverseProxy(Flask): logger = logging.getLogger("werkzeug") logger.setLevel(logging.DEBUG) s = Session() - uri = f"http+unix://%2Ftmp%2F{component}.sock/{path}" + sockets_dir_urlenc = quote(str(self.unix_sockets_dir), safe="") + uri = f"http+unix://%2F{sockets_dir_urlenc}%2F{component}.sock/{path}" raw_data = request.get_data() if len(request.args) > 0: uri += f"?{request.query_string.decode()}" @@ -455,17 +481,6 @@ class TalerReverseProxy(Flask): def get_app(self): return self - def __init__(self): - super().__init__("taler-proxy") - all_methods = [ - "GET", "POST", "HEAD", - "DELETE", "OPTIONS", "PUT" - ] - 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) - @cli.command() def prepare(): @@ -474,69 +489,12 @@ def prepare(): def fail(reason=None): if reason: print("ERROR: " + reason) - print("See logs in /tmp/$component.log") exit(1) - - # Print No Newline. - def print_nn(msg): - print(msg, end="") - - # Runs a command synchronously. - def cmd( - args, env=os.environ, - custom_name=None, return_stdout=False - ): - handle = launch( - args, env=env, - custom_name=custom_name, - return_stdout=return_stdout - ) - return_code = handle.wait() - if return_code != 0: - print("\nCommand: " + " ".join(args) + " failed, return code: " + str(return_code)) - name = custom_name if custom_name else args[0] - print(f"See logs in /tmp/{name}.log") - exit(return_code) - return handle def kill(proc): proc.terminate() proc.wait() - - # Runs a command in the background. - def launch(cmd, env=os.environ, custom_name=None, return_stdout=False): - name = custom_name if custom_name else cmd[0] - log_file = open(f"/tmp/{name}.log", "a+") - try: - handle = Popen( - cmd, - stdin=DEVNULL, - stdout=log_file if not return_stdout else PIPE, - stderr=log_file, - env=env - ) - except Exception as error: - fail(f"Could not launch: {name}: {error}") - atexit.register(lambda: kill(handle)) - return handle - - def check_running(check_url): - for i in range(10): - print_nn(".") - try: - # Raises if the service is not reachable. - response = requests.get(check_url) - # Raises if the request gets a non 200 OK. - response.raise_for_status() - except: - if i == 9: - print("FAIL") - return False - time.sleep(0.5) - continue - break - return True - + def get_nexus_cli_env( username, password, nexus_url @@ -571,7 +529,7 @@ def prepare(): env ): # make connection - cmd( + Command( [ "libeufin-cli", "connections", "new-ebics-connection", @@ -582,25 +540,26 @@ def prepare(): bank_connection_name ], env - ) + ).run() + # connect - cmd( + Command( [ "libeufin-cli", "connections", "connect", bank_connection_name ], env - ) + ).run() # Import bank account - cmd( + Command( [ "libeufin-cli", "connections", "download-bank-accounts", bank_connection_name ], env - ) - cmd( + ).run() + Command( [ "libeufin-cli", "connections", "import-bank-account", @@ -611,9 +570,9 @@ def prepare(): bank_connection_name ], env - ) + ).run() # Set background tasks. - cmd( + Command( [ "libeufin-cli", "accounts", "task-schedule", bank_account_name_nexus, @@ -622,8 +581,8 @@ def prepare(): "--task-cronspec", "* * *" ], env - ) - cmd( + ).run() + Command( [ "libeufin-cli", "accounts", "task-schedule", bank_account_name_nexus, @@ -634,7 +593,7 @@ def prepare(): "--task-param-range-type", "latest" ], env - ) + ).run() def prepare_sandbox_account( currency, @@ -647,7 +606,7 @@ def prepare(): bank_account_iban, env ): - cmd( + Command( [ "libeufin-cli", "sandbox", "--sandbox-url", sandbox_url, @@ -657,8 +616,8 @@ def prepare(): "--user-id", ebics_user_id ], env - ) - cmd( + ).run() + Command( [ "libeufin-cli", "sandbox", "--sandbox-url", sandbox_url, @@ -673,8 +632,120 @@ def prepare(): "--currency", currency ], env - ) + ).run() + + CURRENCY = "EUR" + WIRE_METHOD = "sepa" + + # Filesystem's paths + CFG_OUTDIR = TALER_ROOT_DIR / "config" + UNIX_SOCKETS_DIR = TALER_ROOT_DIR / "sockets" + TALER_RUNTIME_DIR = TALER_ROOT_DIR / "runtime" + TALER_DATA_DIR = TALER_ROOT_DIR / "data" + LOG_DIR = TALER_ROOT_DIR / "logs" + # IBANs + IBAN_EXCHANGE = "EX00000000000000000000" + IBAN_MERCHANT = "ME00000000000000000001" + IBAN_CUSTOMER = "WA00000000000000000000" + + # Credentials / API keys + SANDBOX_ADMIN_USERNAME = "admin" + SANDBOX_ADMIN_PASSWORD = "secret" + EXCHANGE_NEXUS_USERNAME = "exchange-nexus-user" + EXCHANGE_NEXUS_PASSWORD = "exchange-nexus-password" + FRONTENDS_API_TOKEN = "secret:secret" + TALER_MERCHANT_TOKEN = "secret:secret" # same as above? + + # URLs + REV_PROXY = "http://localhost:8080" + SANDBOX_URL = REV_PROXY + "/sandbox" + NEXUS_URL = REV_PROXY + "/nexus" + + # EBICS + EBICS_HOST_ID = "ebicsDeployedHost" + EXCHANGE_EBICS_USER_ID = "exchangeEbicsUserId" + EXCHANGE_EBICS_PARTNER_ID = "exchangeEbicsPartnerId" + EBICS_URL = REV_PROXY + "/sandbox/ebicsweb" + + # euFin + NEXUS_DB_FILE = "/tmp/nexus.sqlite" + SANDBOX_DB_FILE = "/tmp/sandbox.sqlite" + EXCHANGE_BANK_ACCOUNT_NEXUS = "exchange-imported-account-nexus" + EXCHANGE_BANK_ACCOUNT_SANDBOX = "exchange-account-sandbox" + EXCHANGE_BANK_CONNECTION = "exchange-ebics-connection" + EXCHANGE_FACADE_NAME = "exchange-taler-facade" + + class Command: + def __init__( + self, cmd, env=os.environ, log_dir=LOG_DIR, + custom_name=None, capture_stdout=False + ): + if len(cmd) == 0: + fail("Could not find a command to execute") + self.name = custom_name if custom_name else cmd[0] + self.cmd = cmd + self.env=env + self.capture_stdout=capture_stdout + self.log_dir = log_dir + + @staticmethod + def is_serving(check_url): + for i in range(10): + print_nn(".") + try: + # Raises if the service is not reachable. + response = requests.get(check_url) + # Raises if the request gets a non 200 OK. + response.raise_for_status() + except: + if i == 9: + return False + time.sleep(0.5) + continue + break + return True + + def run(self): + self.do() + return_code = self.handle.wait() + if return_code != 0: + fail(f"Command {self.name} failed. Logs in {self.get_log_filename()}") + self.cleanup() + 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 + + def cleanup(self): + if not self.log_file.closed: + self.log_file.close() + def do(self): + if not self.log_dir.is_dir(): + os.makedirs(self.log_dir) + self.log_file = open(self.log_dir / (self.name + ".log"), "a+") + try: + self.handle = Popen( + self.cmd, + stdin=DEVNULL, + stdout=self.log_file if not self.capture_stdout else PIPE, + stderr=self.log_file, + env=self.env + ) + except Exception as error: + fail(f"Could not launch: {self.name}: {error}") + atexit.register(self.stop) + class ConfigFile: def __init__(self, filename): self.sections = OrderedDict() @@ -689,8 +760,9 @@ def prepare(): s[key] = value def cfg_write(self, outdir): - if outdir: + if not os.path.isdir(outdir): + os.makedirs(outdir) fstream = open(os.path.join(outdir, self.filename), "w") else: fstream = open(sys.stdout) @@ -701,14 +773,36 @@ def prepare(): fstream.write(key + " = " + value + "\n") fstream.write("\n") fstream.close() - # Writes on disk too, like the other config_* functions. + + def config_specify_master_pub( + filename, + currency, + exchange_master_pub + ): + Command([ + "taler-config", "-c", filename, + "-s", "exchange", "-o", "master_public_key", + "-V", exchange_master_pub + ]).run() + Command([ + "taler-config", "-c", filename, + "-s", f"merchant-exchange-{currency}", + "-o", "master_key", + "-V", exchange_master_pub + ]).run() + + # When called, there is no exchange master pub yet. + # taler-exchange-offline will prouce the key _after_ + # taler.conf is generated. Only after that, we'll + # specify the master key where it is missing; namely + # in the merchant backend and exchange HTTP daemon sections. def config_main( filename, outdir, + unix_sockets_dir, currency, rev_proxy_url, wire_method, - exchange_master_pub, exchange_wire_address, merchant_wire_address, exchange_wire_gateway_username, @@ -742,8 +836,8 @@ def prepare(): obj.cfg_put(sec, "rsa_keysize", rsa_keysize) obj = ConfigFile("taler.conf") - obj.cfg_put("paths", "TALER_DATA_HOME", "${HOME}/.taler-data") - if not os.path.isdir(taler_runtime_dir): + obj.cfg_put("paths", "TALER_DATA_HOME", str(TALER_DATA_DIR)) + if not taler_runtime_dir.is_dir(): os.makedirs(taler_runtime_dir) obj.cfg_put("paths", "TALER_RUNTIME_DIR", str(taler_runtime_dir)) obj.cfg_put("taler", "CURRENCY", currency) @@ -751,7 +845,7 @@ def prepare(): obj.cfg_put("bank", "serve", "uwsgi") obj.cfg_put("bank", "uwsgi_serve", "unix") - obj.cfg_put("bank", "uwsgi_unixpath", "/tmp/bank.sock") + obj.cfg_put("bank", "uwsgi_unixpath", str(unix_sockets_dir / "bank.sock")) obj.cfg_put("bank", "uwsgi_unixpath_mode", "660") obj.cfg_put("bank", "database", "taler") obj.cfg_put("bank", "max_debt", "%s:500.0" % currency) @@ -763,27 +857,27 @@ def prepare(): obj.cfg_put("donations", "serve", "uwsgi") obj.cfg_put("donations", "uwsgi_serve", "unix") - obj.cfg_put("donations", "uwsgi_unixpath", "/tmp/donations.sock") + obj.cfg_put("donations", "uwsgi_unixpath", str(unix_sockets_dir / "DONATIONS.Sock")) obj.cfg_put("donations", "uwsgi_unixpath_mode", "660") obj.cfg_put("landing", "serve", "uwsgi") obj.cfg_put("landing", "uwsgi_serve", "unix") - obj.cfg_put("landing", "uwsgi_unixpath", "/tmp/landing.sock") + obj.cfg_put("landing", "uwsgi_unixpath", str(unix_sockets_dir / "landing.sock")) obj.cfg_put("landing", "uwsgi_unixpath_mode", "660") obj.cfg_put("blog", "serve", "uwsgi") obj.cfg_put("blog", "uwsgi_serve", "unix") - obj.cfg_put("blog", "uwsgi_unixpath", "/tmp/blog.sock") + obj.cfg_put("blog", "uwsgi_unixpath", str(unix_sockets_dir / "blog.sock")) obj.cfg_put("blog", "uwsgi_unixpath_mode", "660") obj.cfg_put("survey", "serve", "uwsgi") obj.cfg_put("survey", "uwsgi_serve", "unix") - obj.cfg_put("survey", "uwsgi_unixpath", "/tmp/survey.sock") + obj.cfg_put("survey", "uwsgi_unixpath", str(unix_sockets_dir / "survey.sock")) obj.cfg_put("survey", "uwsgi_unixpath_mode", "660") obj.cfg_put("survey", "bank_password", "x") obj.cfg_put("merchant", "serve", "unix") - obj.cfg_put("merchant", "unixpath", "/tmp/merchant-backend.sock") + obj.cfg_put("merchant", "unixpath", str(unix_sockets_dir / "merchant-backend.sock")) obj.cfg_put("merchant", "wire_transfer_delay", "0 s") obj.cfg_put("merchant", "default_max_wire_fee", currency + ":" + "0.01") obj.cfg_put("merchant", "default_max_deposit_fee", currency + ":" + "0.05") @@ -794,35 +888,34 @@ def prepare(): "merchant-exchange-{}".format(currency), "exchange_base_url", rev_proxy_url + "/exchange/", ) - obj.cfg_put( - "merchant-exchange-{}".format(currency), - "master_key", exchange_master_pub, - ) - obj.cfg_put("auditor", "serve", "unix") # FIXME: both below used? obj.cfg_put("auditor", "base_url", rev_proxy_url + "/auditor") obj.cfg_put("auditor", "auditor_url", rev_proxy_url + "/auditor") - obj.cfg_put("auditor", "unixpath", "/tmp/auditor.sock") + obj.cfg_put("auditor", "unixpath", str(unix_sockets_dir / "auditor.sock")) obj.cfg_put("auditor", "tiny_amount", currency + ":0.01") - obj.cfg_put("taler-exchange-secmod-eddsa", "unixpath", "/tmp/exchange-secmod-eddsa.sock") - obj.cfg_put("taler-exchange-secmod-rsa", "unixpath", "/tmp/exchange-secmod-rsa.sock") + obj.cfg_put( + "taler-exchange-secmod-eddsa", + "unixpath", + str(unix_sockets_dir / "exchange-secmod-eddsa.sock") + ) + obj.cfg_put( + "taler-exchange-secmod-rsa", + "unixpath", + str(unix_sockets_dir / "exchange-secmod-rsa.sock") + ) obj.cfg_put("taler-exchange-secmod-rsa", "sm_priv_key", - "/tmp/.taler-data/taler-exchange-secmod-rsa/secmod-private-key" + "${TALER_DATA_HOME}/taler-exchange-secmod-rsa/secmod-private-key" ) obj.cfg_put("exchange", "base_url", rev_proxy_url + "/exchange/") - obj.cfg_put("exchange", "master_public_key", exchange_master_pub) - obj.cfg_put("exchange", "serve", "unix") - obj.cfg_put("exchange", "unixpath", "/tmp/exchange.sock") - + obj.cfg_put("exchange", "unixpath", str(unix_sockets_dir / "exchange.sock")) obj.cfg_put("exchange", "terms_etag", "0") obj.cfg_put("exchange", "terms_dir", "$HOME/.local/share/taler-exchange/tos") obj.cfg_put("exchange", "privacy_etag", "0") obj.cfg_put("exchange", "privacy_dir", "$HOME/.local/share/taler-exchange/pp") - obj.cfg_put("exchangedb-postgres", "db_conn_str", "postgres:///taler") obj.cfg_put("exchangedb-postgres", "config", "postgres:///taler") obj.cfg_put("auditordb-postgres", "db_conn_str", "postgres:///taler") @@ -854,11 +947,11 @@ def prepare(): obj.cfg_write(outdir) return obj - def config_sync(filename, outdir, currency, api_key, rev_proxy_url): + def config_sync(filename, outdir, unix_sockets_dir, currency, api_key, rev_proxy_url): obj = ConfigFile(filename) obj.cfg_put("taler", "currency", currency) obj.cfg_put("sync", "serve", "unix") - obj.cfg_put("sync", "unixpath", "$HOME/sockets/sync.http") + obj.cfg_put("sync", "unixpath", str(unix_sockets_dir / "sync.sock")) obj.cfg_put("sync", "apikey", f"Bearer {api_key}") obj.cfg_put("sync", "annual_fee", f"{currency}:0.1") obj.cfg_put("sync", "fulfillment_url", "taler://fulfillment-success/") @@ -866,12 +959,12 @@ def prepare(): obj.cfg_put("syncdb-postgres", "config", f"postgres:///taler") obj.cfg_write(outdir) - def config_anastasis(filename, outdir, currency, rev_proxy_url, api_key): + def config_anastasis(filename, outdir, unix_sockets_dir, currency, rev_proxy_url, api_key): obj = ConfigFile(filename) obj.cfg_put("taler", "currency", currency) obj.cfg_put("anastasis", "serve", "unix") obj.cfg_put("anastasis", "business_name", f"GNU Taler Demo Anastasis Provider") - obj.cfg_put("anastasis", "unixpath", "/tmp/anastasis.sock") + obj.cfg_put("anastasis", "unixpath", str(unix_sockets_dir / "anastasis.sock")) obj.cfg_put("anastasis", "annual_fee", f"{currency}:0") obj.cfg_put("anastasis", "question_cost", f"{currency}:0") obj.cfg_put("anastasis", "insurance", f"{currency}:0") @@ -887,68 +980,35 @@ def prepare(): obj.cfg_put("authorization-question", "cost", f"{currency}:0") obj.cfg_put("authorization-question", "enabled", "yes") obj.cfg_write(outdir) - - CURRENCY = "EUR" - WIRE_METHOD = "sepa" - - # Directories - CFG_OUTDIR = Path.home() / ".config" - TALER_RUNTIME_DIR = Path.home() / ".taler-runtime" - TALER_DATA_DIR = Path.home() / ".taler-data" - - # IBANs - IBAN_EXCHANGE = "EX00000000000000000000" - IBAN_MERCHANT = "ME00000000000000000001" - IBAN_CUSTOMER = "WA00000000000000000000" - - # Credentials / API keys - SANDBOX_ADMIN_USERNAME = "admin" - SANDBOX_ADMIN_PASSWORD = "secret" - EXCHANGE_NEXUS_USERNAME = "exchange-nexus-user" - EXCHANGE_NEXUS_PASSWORD = "exchange-nexus-password" - FRONTENDS_API_TOKEN = "secret:secret" - TALER_MERCHANT_TOKEN = "secret:secret" # same as above? - # URLs - REV_PROXY = "http://localhost:8080" - SANDBOX_URL = REV_PROXY + "/sandbox" - NEXUS_URL = REV_PROXY + "/nexus" - - # EBICS - EBICS_HOST_ID = "ebicsDeployedHost" - EXCHANGE_EBICS_USER_ID = "exchangeEbicsUserId" - EXCHANGE_EBICS_PARTNER_ID = "exchangeEbicsPartnerId" - EBICS_URL = REV_PROXY + "/sandbox/ebicsweb" + print_nn("Ensure no service is running...") + if Command.is_serving(REV_PROXY + "/"): + fail("Reverse proxy is unexpectedly running!") + if UNIX_SOCKETS_DIR.is_dir(): + for left_socket in os.listdir(UNIX_SOCKETS_DIR): + s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + socket_file = str(UNIX_SOCKETS_DIR / left_socket) + if s.connect_ex(socket_file.encode("utf-8")) == 0: + fail(f"A service is unexpectedly running and bound to {socket_file}!") + print(" OK") - # euFin - NEXUS_DB_FILE = "/tmp/nexus.sqlite" - SANDBOX_DB_FILE = "/tmp/sandbox.sqlite" - EXCHANGE_BANK_ACCOUNT_NEXUS = "exchange-imported-account-nexus" - EXCHANGE_BANK_ACCOUNT_SANDBOX = "exchange-account-sandbox" - EXCHANGE_BANK_CONNECTION = "exchange-ebics-connection" - EXCHANGE_FACADE_NAME = "exchange-taler-facade" - - print_nn("Remove stale data..") + print_nn("Remove stale data and config...") if TALER_DATA_DIR.exists(): shutil.rmtree(TALER_DATA_DIR) if TALER_RUNTIME_DIR.exists(): shutil.rmtree(TALER_RUNTIME_DIR) + if CFG_OUTDIR.exists(): + shutil.rmtree(CFG_OUTDIR) print(" OK") - print_nn("Generate exchange's master key...") - res = cmd( - ["taler-exchange-offline", "setup"], - return_stdout=True - ) - EXCHANGE_MASTER_PUB = res.communicate()[0].decode("utf-8").rstrip() - print(" OK") - + + print_nn("Generate preliminary taler.conf...") mc = config_main( "taler.conf", outdir=CFG_OUTDIR, + unix_sockets_dir=UNIX_SOCKETS_DIR, currency=CURRENCY, rev_proxy_url=REV_PROXY, wire_method=WIRE_METHOD, - exchange_master_pub=EXCHANGE_MASTER_PUB, exchange_wire_address=IBAN_EXCHANGE, merchant_wire_address=IBAN_MERCHANT, exchange_wire_gateway_username=EXCHANGE_NEXUS_USERNAME, @@ -956,65 +1016,104 @@ def prepare(): frontend_api_key=FRONTENDS_API_TOKEN, taler_runtime_dir=TALER_RUNTIME_DIR ) + print(" OK") + print_nn("Generate exchange's master key...") + EXCHANGE_MASTER_PUB = Command( + [ + "taler-exchange-offline", + "-c", CFG_OUTDIR / "taler.conf", + "setup" + ], + capture_stdout=True + ).run() + print(" OK") + print_nn("Specify exchange master pub in taler.conf...") + config_specify_master_pub( + CFG_OUTDIR / "taler.conf", + CURRENCY, + EXCHANGE_MASTER_PUB + ) + print(" OK") + print_nn("Generating sync.conf...") config_sync( "sync.conf", outdir=CFG_OUTDIR, + unix_sockets_dir=UNIX_SOCKETS_DIR, currency=CURRENCY, api_key=FRONTENDS_API_TOKEN, rev_proxy_url=REV_PROXY ) + print(" OK") + print_nn("Generating anastasis.conf...") config_anastasis( "anastasis.conf", outdir=CFG_OUTDIR, + unix_sockets_dir=UNIX_SOCKETS_DIR, currency=CURRENCY, rev_proxy_url=REV_PROXY, api_key=FRONTENDS_API_TOKEN ) - - print_nn("Reset and init exchange DB..") - cmd(["taler-exchange-dbinit", "--reset"]) print(" OK") - - print_nn("Remove previous key and data files..") - cmd( - ["rm", "-fr", Path.home() / ".taler-data" / "*"], - custom_name="remove-taler-data" - ) + print_nn("Reset and init exchange DB..") + Command([ + "taler-exchange-dbinit", + "-c", CFG_OUTDIR / "taler.conf", + "--reset"] + ).run() print(" OK") - print_nn("Launching the reverse proxy...") - rev_proxy = TalerReverseProxy() + rev_proxy = TalerReverseProxy(LOG_DIR, UNIX_SOCKETS_DIR) rev_proxy.start() - if not check_running(REV_PROXY + "/"): - fail("Reverse proxy did not start correctly.") + if not Command.is_serving(REV_PROXY + "/"): + fail(f"Reverse proxy did not start correctly. \ +Logs: {rev_proxy.get_log_filename()}" + ) # Do check. print(" OK") print_nn("Launching the exchange RSA helper...") - exchange_rsa_handle = launch(["taler-exchange-secmod-rsa"]) + exchange_rsa_handle = Command([ + "taler-exchange-secmod-rsa", + "-c", CFG_OUTDIR / "taler.conf" + ]).launch() print(" OK") print_nn("Launching the exchange EDDSA helper...") - exchange_eddsa_handle = launch(["taler-exchange-secmod-eddsa"]) + exchange_eddsa_handle = Command([ + "taler-exchange-secmod-eddsa", + "-c", CFG_OUTDIR / "taler.conf" + ]).launch() print(" OK") print_nn("Launching the exchange...") - exchange_handle = launch(["taler-exchange-httpd"]) - if not check_running(REV_PROXY + "/exchange/"): - fail("Exchange did not start correctly.") + exchange_handle = Command([ + "taler-exchange-httpd", + "-c", CFG_OUTDIR / "taler.conf" + ]).launch() + if not Command.is_serving(REV_PROXY + "/exchange/"): + fail(f"Exchange did not start correctly. Logs: {exchange_handle.get_log_filename()}") print(" OK") print_nn("exchange-offline: signing key material...") - cmd(["taler-exchange-offline", "download", "sign", "upload"]) + Command([ + "taler-exchange-offline", + "-c", CFG_OUTDIR / "taler.conf", + "download", "sign", "upload" + ]).run() print(" OK") PAYTO_URI=mc.sections["exchange-account-1"]["payto_uri"] print_nn(f"exchange-offline: enabling {PAYTO_URI}...") - cmd(["taler-exchange-offline", "enable-account", PAYTO_URI, "upload"]) + Command([ + "taler-exchange-offline", + "-c", CFG_OUTDIR / "taler.conf", + "enable-account", PAYTO_URI, "upload"] + ).run() print(" OK") # Set up wire fees for next 5 years NOW = datetime.now() YEAR = NOW.year print_nn("Setting wire fees for the next 5 years...") for year in range(YEAR, YEAR+5): - cmd( + Command( [ "taler-exchange-offline", + "-c", CFG_OUTDIR / "taler.conf", "wire-fee", str(year), WIRE_METHOD, @@ -1023,21 +1122,22 @@ def prepare(): "upload" ], custom_name="set-wire-fee" - ) + ).run() print(" OK") print_nn("Stopping exchange HTTP daemon and crypto helpers...") - kill(exchange_rsa_handle) - kill(exchange_eddsa_handle) - kill(exchange_handle) + exchange_rsa_handle.stop() + exchange_eddsa_handle.stop() + exchange_handle.stop() print(" OK") print_nn("Add this exchange to the auditor...") - cmd( + Command( [ "taler-auditor-exchange", + "-c", CFG_OUTDIR / "taler.conf", "-m", EXCHANGE_MASTER_PUB, "-u", REV_PROXY + "/exchange/" ], - ) + ).run() print(" OK") ## Step 4: Set up euFin print_nn("Resetting euFin databases...") @@ -1050,7 +1150,7 @@ def prepare(): print(" OK") print_nn("Create Sandbox superuser...") - cmd( + Command( [ "libeufin-sandbox", "superuser", SANDBOX_ADMIN_USERNAME, @@ -1058,23 +1158,26 @@ def prepare(): ], custom_name="sandbox-superuser", env=get_sandbox_server_env(SANDBOX_DB_FILE) - ) + ).run() print(" OK") + # FIXME: tested until here. To proceed, euFin needs to + # bind to Unix domain sockets. + exit(1) + print_nn("Launching Sandbox...") - handle_sandbox = launch( + sandbox_handle = Command( [ "libeufin-sandbox", "serve", - "--with-unix-socket", "/tmp/sandbox.sock", + "--with-unix-socket", UNIX_SOCKETS_DIR / "sandbox.sock", ], env=get_sandbox_server_env(SANDBOX_DB_FILE) - ) - if not check_running(SANDBOX_URL): - fail("Sandbox did not start correctly") + ).launch() + if not Command.is_serving(SANDBOX_URL): + fail(f"Sandbox did not start correctly. Logs: {sandbox_handle.get_log_filename()}") print(" OK") - exit(22) print_nn("Make Sandbox EBICS host...") - cmd( + Command( [ "libeufin-cli", "sandbox", "--sandbox-url", SANDBOX_URL, @@ -1086,7 +1189,7 @@ def prepare(): SANDBOX_ADMIN_PASSWORD ), custom_name="sandbox-create-ebicshost", - ) + ).run() print(" OK") prepare_sandbox_account( @@ -1132,22 +1235,22 @@ def prepare(): ) ) print_nn("Make Nexus superuser ...") - cmd( + Command( [ "libeufin-nexus", "superuser", EXCHANGE_NEXUS_USERNAME, "--password", EXCHANGE_NEXUS_PASSWORD ], custom_name="nexus-superuser", - ) + ).run() print(" OK") print_nn("Launching Nexus...") - handle_nexus = launch("nexus", [ + nexus_handle = Command("nexus", [ "libeufin-nexus", "serve", - "--with-unix-socket", "/tmp/nexus.sock" - ]) - if not check_running(NEXUS_URL): - fail("Nexus did not start correctly") + "--with-unix-socket", UNIX_SOCKETS_DIR / "nexus.sock" + ]).launch() + if not Command.is_serving(NEXUS_URL): + fail(f"Nexus did not start correctly. Logs: {nexus_handle.get_log_filename()}") print(" OK") prepare_nexus_account( @@ -1165,7 +1268,7 @@ def prepare(): ) ) print_nn("Create Taler facade ...") - cmd( + Command( [ "libeufin-cli", "facades", "new-taler-wire-gateway-facade", @@ -1180,7 +1283,7 @@ def prepare(): NEXUS_URL ), custom_name="create-taler-facade", - ) + ).run() print(" OK") try: response = requests.get( @@ -1197,45 +1300,52 @@ def prepare(): FACADE_URL=response.json().get("facade")[0].get("baseUrl") print_nn("Terminating Nexus...") - kill(handle_nexus) + nexus_handle.stop() print(" OK") print_nn("Terminating Sandbox...") - kill(handle_sandbox) + sandbox_handle.stop() print(" OK") # Point the exchange to the facade. - cmd( + Command( [ - "taler-config", "-s" + "taler-config", "-s", + "-c", CFG_OUTDIR / "taler.conf", f"exchange-account-credentials-1", "-o" "wire_gateway_url", "-V", FACADE_URL ], custom_name="specify-facade-url", - ) - cmd( + ).run() + Command( [ - "taler-config", "-s" - f"exchange-account-credentials-1", + "taler-config", "-s", + "-c", CFG_OUTDIR / "taler.conf", + "exchange-account-credentials-1", "-o" "username", "-V", EXCHANGE_NEXUS_USERNAME ], custom_name="specify-username-for-facade", - ) - cmd( + ).run() + Command( [ - "taler-config", "-s" - f"exchange-account-credentials-1", + "taler-config", "-s", + "-c", CFG_OUTDIR / "taler.conf", + "exchange-account-credentials-1", "-o" "password", "-V", EXCHANGE_NEXUS_PASSWORD ], custom_name="specify-password-for-facade", - ) + ).run() ## Step 6: Set up merchant print_nn("Reset and init merchant database...") - cmd(["taler-merchant-dbinit", "--reset"]) + Command([ + "taler-merchant-dbinit", + "-c", CFG_OUTDIR / "taler.conf", + "--reset" + ]).run() print(" OK") def ensure_instance( @@ -1282,12 +1392,12 @@ def prepare(): print_nn("Start merchant (with TALER_MERCHANT_TOKEN into the env)...") auth_env = os.environ.copy() auth_env["TALER_MERCHANT_TOKEN"] = TALER_MERCHANT_TOKEN - merchant_handle = launch( - ["taler-merchant-httpd"], + merchant_handle = Command( + ["taler-merchant-httpd", "-c", CFG_OUTDIR / "taler.conf"], env=auth_env - ) - if not check_running("/merchant-backend"): - fail("Merchant backend did not start correctly") + ).launch() + if not Command.is_serving(REV_PROXY + "/merchant-backend"): + fail(f"Merchant backend did not start correctly. Logs: {merchant_handle.get_log_filename()}") print(" OK") ensure_instance( @@ -1300,13 +1410,13 @@ def prepare(): auth_token=FRONTENDS_API_TOKEN ) print_nn("Stopping the merchant...") - kill(merchant_handle) + merchant_handle.stop() print(" OK") print_nn("Restarting the merchant WITHOUT the auth-token in the env...") - merchant_handle = launch(["taler-merchant-httpd"]) - if not check_running("/merchant-backend"): + merchant_handle.launch() + if not Command.is_serving(REV_PROXY + "/merchant-backend"): # check_running logs errors already. - fail("Merchant backend did not start correctly") + fail(f"Merchant backend did not re start correctly. Logs: {merchant_handle.get_log_filename()}") print(" OK") print_nn("Creating the 'donations' instance...") ensure_instance( |