From 315d427689dd5d5e9289cf45d2b17120035a11b6 Mon Sep 17 00:00:00 2001 From: pieckwilhelm Date: Sat, 16 Aug 2025 01:25:45 +0200 Subject: [PATCH 1/3] chore: Update database configuration to use PostgreSQL --- pwd.yml | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/pwd.yml b/pwd.yml index 8fd88c9a..63be2751 100644 --- a/pwd.yml +++ b/pwd.yml @@ -1,5 +1,3 @@ -version: "3" - services: backend: image: frappe/erpnext:v15.75.1 @@ -13,9 +11,8 @@ services: - logs:/home/frappe/frappe-bench/logs environment: DB_HOST: db - DB_PORT: "3306" - MYSQL_ROOT_PASSWORD: admin - MARIADB_ROOT_PASSWORD: admin + # MYSQL_ROOT_PASSWORD: admin + # MARIADB_ROOT_PASSWORD: admin configurator: image: frappe/erpnext:v15.75.1 @@ -38,10 +35,12 @@ services: bench set-config -gp socketio_port $$SOCKETIO_PORT; environment: DB_HOST: db - DB_PORT: "3306" + DB_PORT: "5432" REDIS_CACHE: redis-cache:6379 REDIS_QUEUE: redis-queue:6379 SOCKETIO_PORT: "9000" + depends_on: + - db volumes: - sites:/home/frappe/frappe-bench/sites - logs:/home/frappe/frappe-bench/logs @@ -61,8 +60,7 @@ services: - -c command: - > - wait-for-it -t 120 db:3306; - wait-for-it -t 120 redis-cache:6379; + wait-for-it -t 120 db:5432; wait-for-it -t 120 redis-queue:6379; export start=`date +%s`; until [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".db_host // empty"` ]] && \ @@ -77,10 +75,11 @@ services: fi done; echo "sites/common_site_config.json found"; - bench new-site --mariadb-user-host-login-scope='%' --admin-password=admin --db-root-username=root --db-root-password=admin --install-app erpnext --set-default frontend; + bench new-site --db-type postgres --db-host db --db-password=123 --admin-password=123 --db-root-username=postgres --db-root-password=123 --install-app erpnext --set-default frontend; db: - image: mariadb:10.6 + image: pgvector/pgvector:pg17 + command: [] networks: - frappe_network healthcheck: @@ -90,16 +89,14 @@ services: deploy: restart_policy: condition: on-failure - command: - - --character-set-server=utf8mb4 - - --collation-server=utf8mb4_unicode_ci - - --skip-character-set-client-handshake - - --skip-innodb-read-only-compressed # Temporary fix for MariaDB 10.6 environment: - MYSQL_ROOT_PASSWORD: admin - MARIADB_ROOT_PASSWORD: admin + # MYSQL_ROOT_PASSWORD: admin + # MARIADB_ROOT_PASSWORD: admin + # POSTGRES_USER: admin + POSTGRES_PASSWORD: 123 + POSTGRES_DB: sin volumes: - - db-data:/var/lib/mysql + - pg-data:/var/lib/postgresql/data frontend: image: frappe/erpnext:v15.75.1 @@ -206,7 +203,7 @@ services: - logs:/home/frappe/frappe-bench/logs volumes: - db-data: + pg-data: redis-queue-data: sites: logs: From 7fc66c115944b02e7e9dea676f9aad7f8c09daec Mon Sep 17 00:00:00 2001 From: SINeV Date: Sat, 16 Aug 2025 20:43:30 +0000 Subject: [PATCH 2/3] chore: Update default database settings and remove unused VSCode configurations --- .DS_Store | Bin 0 -> 8196 bytes development/installer.py | 12 ++-- development/vscode-example/launch.json | 77 ----------------------- development/vscode-example/settings.json | 3 - development/vscode-example/tasks.json | 22 ------- 5 files changed, 6 insertions(+), 108 deletions(-) create mode 100644 .DS_Store delete mode 100644 development/vscode-example/launch.json delete mode 100644 development/vscode-example/settings.json delete mode 100644 development/vscode-example/tasks.json diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..7ca38724e0d434adba95d7debbcdef6e4c128d12 GIT binary patch literal 8196 zcmeI1+fGwK6o&t)RUmkZV#4K)-e?R>c!L5hripkeTq8XQ#Fk|N?=;XE z{X-2w{?^>m2K@?_#*N;f-Rccmc(6mc$)WuE(-$AcJ+wL?FL_@u&M__Bv%}3$B73?erJ6&`K~cO6tXpiC1(flcMcrZT`^0mIcEN*Z zF{}I7?-Sd52jt&l{YP5ov+r3sWj!m@qr6AYVb;n5JG;SZ)>*x#>UnL?T~>RE+%Ji3 z$miJmDMab{$|4q6mn$@FXHD-bI}P_UtSzyh>YSaLc964nFpT98PyD(2q6^}&6BzaY znXkbNEYen}qvF0WK693qJpPOfFX-9ZyFzZpT>)Wd<{bS~e6;mRhtvG!5Vx;mD%dvO zGMe%GpMw!gWZ(uExRv@?wfld4{`>zMh$Om*3`7S076YzaYu4;%oSPFtiSdN`k!r>C oCaLrg8dI@xe;r3&|HF`e66UHwPEyGXCB6voG{hz{aH9h($ literal 0 HcmV?d00001 diff --git a/development/installer.py b/development/installer.py index edd62147..49917346 100755 --- a/development/installer.py +++ b/development/installer.py @@ -103,7 +103,7 @@ def get_args_parser(): action="store", type=str, help="admin password for site, default: admin", # noqa: E501 - default="admin", + default="123", ) parser.add_argument( "-d", @@ -111,7 +111,7 @@ def get_args_parser(): action="store", type=str, help="Database type to use (e.g., mariadb or postgres)", - default="mariadb", # Set your default database type here + default="postgres", # Set your default database type here ) return parser @@ -208,7 +208,7 @@ def create_site_in_bench(args): "bench", "new-site", f"--db-root-username=root", - f"--db-host=mariadb", # Should match the compose service name + f"--db-host=db", # Should match the compose service name f"--db-type={args.db_type}", # Add the selected database type f"--mariadb-user-host-login-scope=%", f"--db-root-password=123", # Replace with your MariaDB password @@ -217,14 +217,14 @@ def create_site_in_bench(args): else: cprint("Set db_host", level=3) subprocess.call( - ["bench", "set-config", "-g", "db_host", "postgresql"], + ["bench", "set-config", "-g", "db_host", "db"], cwd=os.getcwd() + "/" + args.bench_name, ) new_site_cmd = [ "bench", "new-site", - f"--db-root-username=root", - f"--db-host=postgresql", # Should match the compose service name + f"--db-root-username=postgres", + f"--db-host=db", # Should match the compose service name f"--db-type={args.db_type}", # Add the selected database type f"--db-root-password=123", # Replace with your PostgreSQL password f"--admin-password={args.admin_password}", diff --git a/development/vscode-example/launch.json b/development/vscode-example/launch.json deleted file mode 100644 index 7267fcf3..00000000 --- a/development/vscode-example/launch.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Bench Web", - "type": "debugpy", - "request": "launch", - "program": "${workspaceFolder}/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", - "args": [ - "frappe", - "serve", - "--port", - "8000", - "--noreload", - "--nothreading" - ], - "cwd": "${workspaceFolder}/frappe-bench/sites", - "env": { - "DEV_SERVER": "1" - } - }, - { - "name": "Bench Short Worker", - "type": "debugpy", - "request": "launch", - "program": "${workspaceFolder}/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", - "args": ["frappe", "worker", "--queue", "short"], - "cwd": "${workspaceFolder}/frappe-bench/sites", - "env": { - "DEV_SERVER": "1" - } - }, - { - "name": "Bench Default Worker", - "type": "debugpy", - "request": "launch", - "program": "${workspaceFolder}/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", - "args": ["frappe", "worker", "--queue", "default"], - "cwd": "${workspaceFolder}/frappe-bench/sites", - "env": { - "DEV_SERVER": "1" - } - }, - { - "name": "Bench Long Worker", - "type": "debugpy", - "request": "launch", - "program": "${workspaceFolder}/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", - "args": ["frappe", "worker", "--queue", "long"], - "cwd": "${workspaceFolder}/frappe-bench/sites", - "env": { - "DEV_SERVER": "1" - } - }, - { - "name": "Honcho SocketIO Watch Schedule Worker", - "type": "debugpy", - "request": "launch", - "python": "/home/frappe/.pyenv/shims/python", - "program": "/home/frappe/.local/bin/honcho", - "cwd": "${workspaceFolder}/frappe-bench", - "console": "internalConsole", - "args": ["start", "socketio", "watch", "schedule", "worker"], - "postDebugTask": "Clean Honcho SocketIO Watch Schedule Worker" - } - ], - "compounds": [ - { - "name": "Honcho + Web debug", - "configurations": ["Bench Web", "Honcho SocketIO Watch Schedule Worker"], - "stopAll": true - } - ] -} diff --git a/development/vscode-example/settings.json b/development/vscode-example/settings.json deleted file mode 100644 index 1490b727..00000000 --- a/development/vscode-example/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "python.defaultInterpreterPath": "${workspaceFolder}/frappe-bench/env/bin/python" -} diff --git a/development/vscode-example/tasks.json b/development/vscode-example/tasks.json deleted file mode 100644 index 7c0e6739..00000000 --- a/development/vscode-example/tasks.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [ - { - "label": "Clean Honcho SocketIO Watch Schedule Worker", - "detail": "When stopping the debug process from vscode window, the honcho won't receive the SIGINT signal. This task will send the SIGINT signal to the honcho processes.", - "type": "shell", - "command": "pkill -SIGINT -f bench; pkill -SIGINT -f socketio", - "isBackground": false, - "presentation": { - "echo": true, - "reveal": "silent", - "focus": false, - "panel": "shared", - "showReuseMessage": false, - "close": true - } - } - ] -} From 903103236002fa842183b1fe10f4fb37676f001b Mon Sep 17 00:00:00 2001 From: SINeV Date: Wed, 27 Aug 2025 20:23:17 +0200 Subject: [PATCH 3/3] chore: Enhance database connection handling and configuration in installer.py --- .DS_Store | Bin 8196 -> 8196 bytes development/apps-example.json | 6 - development/installer.py | 264 +++++++++++++++++++++++++++++----- pwd.yml | 11 +- 4 files changed, 234 insertions(+), 47 deletions(-) delete mode 100644 development/apps-example.json diff --git a/.DS_Store b/.DS_Store index 7ca38724e0d434adba95d7debbcdef6e4c128d12..85241c6c6e5e4ebdffc10e638ceb7c988bb0f964 100644 GIT binary patch delta 64 zcmV-G0Kfl)K!iY$SqozTZvbupbO2!hX|ZvZ2a$jcvj+$W2(yI{asiXU5f=$$b7O2` WZ*Ob?v-A None: + """Load environment variables from a .env file if it exists.""" + if os.path.exists(env_file_path): + cprint(f"Loading environment variables from {env_file_path}", level=3) + with open(env_file_path, 'r') as f: + for line in f: + line = line.strip() + if line and not line.startswith('#') and '=' in line: + key, value = line.split('=', 1) + # Only set if not already in environment + if key not in os.environ: + os.environ[key] = value def cprint(*args, level: int = 1): @@ -26,11 +43,101 @@ def cprint(*args, level: int = 1): print(CYLW, message, reset) # noqa: T001, T201 +def check_database_connection(host, port, timeout=30): + """ + Check if database service is reachable + """ + cprint(f"Checking database connection to {host}:{port}...", level=3) + start_time = time.time() + + while time.time() - start_time < timeout: + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(2) + result = sock.connect_ex((host, port)) + sock.close() + + if result == 0: + cprint(f"✓ Database is reachable at {host}:{port}", level=2) + return True + + except Exception as e: + pass + + cprint(f"→ Database not reachable. Waiting... ({int(time.time() - start_time)}s)", level=3) + time.sleep(2) + + cprint(f"✗ Database connection timeout after {timeout}s", level=1) + return False + + +def normalize_db_type(db_type: str) -> str: + """ + Normalize database type to match Frappe's expected values. + Frappe expects 'postgres' not 'postgresql'. + """ + db_type = db_type.lower().strip() + if db_type in ["postgresql", "postgres", "pg"]: + return "postgres" + elif db_type in ["mariadb", "mysql"]: + return "mariadb" + else: + cprint(f"Warning: Unknown database type '{db_type}', defaulting to 'mariadb'", level=3) + return "mariadb" + + +def get_database_config(args) -> Tuple[str, int, str, str]: + """ + Get database configuration from args or environment variables. + Returns: (host, port, username, password) + """ + # Normalize database type to ensure compatibility with Frappe + normalized_db_type = normalize_db_type(args.db_type) + args.db_type = normalized_db_type + + # Set defaults based on database type + if normalized_db_type == "postgres": + default_host = os.getenv("POSTGRES_HOST", "db") + default_port = int(os.getenv("POSTGRES_PORT", "5432")) + default_username = os.getenv("POSTGRES_USER", "postgres") + default_password = os.getenv("POSTGRES_PASSWORD", "123") + else: # mariadb/mysql + default_host = os.getenv("MYSQL_HOST", "db") + default_port = int(os.getenv("MYSQL_PORT", "3306")) + default_username = os.getenv("MYSQL_USER", "root") + default_password = os.getenv("MYSQL_ROOT_PASSWORD", "123") + + # Use command line args if provided, otherwise use defaults + host = args.db_host or default_host + port = args.db_port or default_port + username = args.db_username or default_username + password = args.db_password or default_password + + return host, port, username, password + + def main(): + # Load environment variables from .env file if it exists + load_env_file() + parser = get_args_parser() args = parser.parse_args() + + # Display configuration summary + cprint("=== Frappe Bench Setup Configuration ===", level=2) + db_host, db_port, db_username, _ = get_database_config(args) + cprint(f"Database Type: {args.db_type}", level=3) + cprint(f"Database Host: {db_host}:{db_port}", level=3) + cprint(f"Database User: {db_username}", level=3) + cprint(f"Site Name: {args.site_name}", level=3) + cprint(f"Bench Name: {args.bench_name}", level=3) + cprint("=========================================", level=2) + init_bench_if_not_exist(args) - create_site_in_bench(args) + success = create_site_in_bench(args) + if not success: + cprint("Site creation failed. Please check the database connection and try again.", level=1) + exit(1) def get_args_parser(): @@ -111,7 +218,42 @@ def get_args_parser(): action="store", type=str, help="Database type to use (e.g., mariadb or postgres)", - default="postgres", # Set your default database type here + default="postgres", # Changed to postgres for PostgreSQL setup + ) + parser.add_argument( + "--db-host", + action="store", + type=str, + help="Database host, default: db (for Docker) or localhost", + default=None, + ) + parser.add_argument( + "--db-port", + action="store", + type=int, + help="Database port, default: 5432 for postgres, 3306 for mariadb", + default=None, + ) + parser.add_argument( + "--db-username", + action="store", + type=str, + help="Database username, default: postgres for postgres, root for mariadb", + default=None, + ) + parser.add_argument( + "--db-password", + action="store", + type=str, + help="Database password, default: 123", + default=None, + ) + parser.add_argument( + "--db-name", + action="store", + type=str, + help="Database name for the site (optional)", + default=None, ) return parser @@ -193,52 +335,100 @@ def init_bench_if_not_exist(args): ["bench", "set-config", "-gp", "developer_mode", "1"], cwd=os.getcwd() + "/" + args.bench_name, ) + + # Configure additional PostgreSQL-specific settings if needed + if args.db_type == "postgres": + configure_postgres_settings(args) + except subprocess.CalledProcessError as e: cprint(e.output, level=1) +def configure_postgres_settings(args): + """Configure PostgreSQL-specific settings for the bench.""" + cprint("Configuring PostgreSQL-specific settings...", level=3) + + # Get database configuration + db_host, db_port, db_username, db_password = get_database_config(args) + + # Set PostgreSQL connection parameters in common_site_config.json + postgres_configs = [ + ("db_host", db_host), + ("db_type", "postgres"), + ] + + # Add port configuration if non-standard + if db_port != 5432: + postgres_configs.append(("db_port", str(db_port))) + + for config_key, config_value in postgres_configs: + cprint(f"Setting {config_key} to {config_value}", level=3) + subprocess.call( + ["bench", "set-config", "-g", config_key, config_value], + cwd=os.getcwd() + "/" + args.bench_name, + ) + + def create_site_in_bench(args): - if "mariadb" == args.db_type: - cprint("Set db_host", level=3) - subprocess.call( - ["bench", "set-config", "-g", "db_host", "mariadb"], - cwd=os.getcwd() + "/" + args.bench_name, - ) - new_site_cmd = [ - "bench", - "new-site", - f"--db-root-username=root", - f"--db-host=db", # Should match the compose service name - f"--db-type={args.db_type}", # Add the selected database type - f"--mariadb-user-host-login-scope=%", - f"--db-root-password=123", # Replace with your MariaDB password - f"--admin-password={args.admin_password}", - ] - else: - cprint("Set db_host", level=3) - subprocess.call( - ["bench", "set-config", "-g", "db_host", "db"], - cwd=os.getcwd() + "/" + args.bench_name, - ) - new_site_cmd = [ - "bench", - "new-site", - f"--db-root-username=postgres", - f"--db-host=db", # Should match the compose service name - f"--db-type={args.db_type}", # Add the selected database type - f"--db-root-password=123", # Replace with your PostgreSQL password - f"--admin-password={args.admin_password}", - ] + # Get database configuration + db_host, db_port, db_username, db_password = get_database_config(args) + + # Check database connectivity before proceeding + if not check_database_connection(db_host, db_port): + db_type_name = "PostgreSQL" if args.db_type == "postgres" else "MariaDB" + cprint(f"Cannot connect to {db_type_name} database at {db_host}:{db_port}. Please ensure the database service is running.", level=1) + cprint("If using Docker, run: docker-compose up -d db", level=3) + return False + + # Set database host configuration + cprint(f"Setting db_host to {db_host}", level=3) + subprocess.call( + ["bench", "set-config", "-g", "db_host", db_host], + cwd=os.getcwd() + "/" + args.bench_name, + ) + + # Build new site command + new_site_cmd = [ + "bench", + "new-site", + f"--db-root-username={db_username}", + f"--db-host={db_host}", + f"--db-type={args.db_type}", + f"--db-root-password={db_password}", + f"--admin-password={args.admin_password}", + ] + + # Add database-specific options + if args.db_type == "mariadb": + new_site_cmd.append("--mariadb-user-host-login-scope=%") + + # Add custom database name if specified + if args.db_name: + new_site_cmd.append(f"--db-name={args.db_name}") + + # Add database port if non-standard + if (args.db_type == "postgres" and db_port != 5432) or (args.db_type == "mariadb" and db_port != 3306): + new_site_cmd.append(f"--db-port={db_port}") apps = os.listdir(f"{os.getcwd()}/{args.bench_name}/apps") apps.remove("frappe") for app in apps: new_site_cmd.append(f"--install-app={app}") new_site_cmd.append(args.site_name) cprint(f"Creating Site {args.site_name} ...", level=2) - subprocess.call( - new_site_cmd, - cwd=os.getcwd() + "/" + args.bench_name, - ) + try: + result = subprocess.call( + new_site_cmd, + cwd=os.getcwd() + "/" + args.bench_name, + ) + if result == 0: + cprint(f"✓ Site {args.site_name} created successfully!", level=2) + return True + else: + cprint(f"✗ Site creation failed with exit code {result}", level=1) + return False + except subprocess.CalledProcessError as e: + cprint(f"✗ Site creation failed: {e}", level=1) + return False if __name__ == "__main__": diff --git a/pwd.yml b/pwd.yml index 63be2751..d67eafe1 100644 --- a/pwd.yml +++ b/pwd.yml @@ -35,10 +35,10 @@ services: bench set-config -gp socketio_port $$SOCKETIO_PORT; environment: DB_HOST: db - DB_PORT: "5432" + DB_PORT: '5432' REDIS_CACHE: redis-cache:6379 REDIS_QUEUE: redis-queue:6379 - SOCKETIO_PORT: "9000" + SOCKETIO_PORT: '9000' depends_on: - db volumes: @@ -115,14 +115,14 @@ services: SOCKETIO: websocket:9000 UPSTREAM_REAL_IP_ADDRESS: 127.0.0.1 UPSTREAM_REAL_IP_HEADER: X-Forwarded-For - UPSTREAM_REAL_IP_RECURSIVE: "off" + UPSTREAM_REAL_IP_RECURSIVE: 'off' PROXY_READ_TIMEOUT: 120 CLIENT_MAX_BODY_SIZE: 50m volumes: - sites:/home/frappe/frappe-bench/sites - logs:/home/frappe/frappe-bench/logs ports: - - "8080:8080" + - '8080:8080' queue-long: image: frappe/erpnext:v15.75.1 @@ -192,6 +192,9 @@ services: image: frappe/erpnext:v15.75.1 networks: - frappe_network + depends_on: + - redis_cache + - redis_queue deploy: restart_policy: condition: on-failure