mirror of
https://github.com/frappe/bench.git
synced 2024-11-17 02:25:16 +00:00
Merge branch 'develop' of github.com:frappe/bench into declarative-setup-bench
This commit is contained in:
commit
1e56d04e94
13
.github/semantic.yml
vendored
Normal file
13
.github/semantic.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Always validate the PR title AND all the commits
|
||||||
|
titleAndCommits: true
|
||||||
|
|
||||||
|
# Allow use of Merge commits (eg on github: "Merge branch 'master' into feature/ride-unicorns")
|
||||||
|
# this is only relevant when using commitsOnly: true (or titleAndCommits: true)
|
||||||
|
allowMergeCommits: true
|
||||||
|
|
||||||
|
# Allow use of Revert commits (eg on github: "Revert "feat: ride unicorns"")
|
||||||
|
# this is only relevant when using commitsOnly: true (or titleAndCommits: true)
|
||||||
|
allowRevertCommits: true
|
||||||
|
|
||||||
|
# For allowed PR types: https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json
|
||||||
|
# Tool Reference: https://github.com/zeke/semantic-pull-requests
|
28
.github/workflows/release.yml
vendored
Normal file
28
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
name: Generate Semantic Release and publish on PyPI
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- v5.x
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
name: Release
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
steps:
|
||||||
|
- name: Checkout Entire Repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Setup Node.js v12
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 12
|
||||||
|
- name: Setup dependencies
|
||||||
|
run: |
|
||||||
|
npm install @semantic-release/git @semantic-release/exec --no-save
|
||||||
|
pip install wheel twine
|
||||||
|
- name: Create Release
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
|
||||||
|
PYPI_USERNAME: ${{ secrets.PYPI_USERNAME }}
|
||||||
|
run: npx semantic-release
|
35
.releaserc
Normal file
35
.releaserc
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"branches": ["v5.x"],
|
||||||
|
"plugins": [
|
||||||
|
"@semantic-release/commit-analyzer",
|
||||||
|
"@semantic-release/release-notes-generator",
|
||||||
|
[
|
||||||
|
"@semantic-release/exec", {
|
||||||
|
"prepareCmd": 'sed -ir "s/[0-9]*\.[0-9]*\.[0-9]*/${nextRelease.version}/" bench/__init__.py'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@semantic-release/exec", {
|
||||||
|
"prepareCmd": "python setup.py bdist_wheel --universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@semantic-release/git", {
|
||||||
|
"assets": ["bench/__init__.py"],
|
||||||
|
"message": "chore(release): Bumped to Version ${nextRelease.version}\n\n${nextRelease.notes}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@semantic-release/github", {
|
||||||
|
"assets": [
|
||||||
|
{"path": "dist/*"},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@semantic-release/exec", {
|
||||||
|
"publishCmd": "python -m twine upload dist/* -u $PYPI_USERNAME -p $PYPI_PASSWORD"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
@ -13,7 +13,7 @@ Bench is a command-line utility that helps you to install, update, and manage mu
|
|||||||
- [Production Setup](#docker-installation-for-production)
|
- [Production Setup](#docker-installation-for-production)
|
||||||
- [Easy Install Script](#easy-install-script)
|
- [Easy Install Script](#easy-install-script)
|
||||||
- [Manual Installation](#manual-installation)
|
- [Manual Installation](#manual-installation)
|
||||||
- [Usage](#usage)
|
- [Usage](#basic-usage)
|
||||||
- [Custom Bench commands](#custom-bench-commands)
|
- [Custom Bench commands](#custom-bench-commands)
|
||||||
- [Bench Manager](#bench-manager)
|
- [Bench Manager](#bench-manager)
|
||||||
- [Guides](#guides)
|
- [Guides](#guides)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
VERSION = "5.2.1"
|
VERSION = "5.0.0-dev"
|
||||||
PROJECT_NAME = "frappe-bench"
|
PROJECT_NAME = "frappe-bench"
|
||||||
FRAPPE_VERSION = None
|
FRAPPE_VERSION = None
|
||||||
|
|
||||||
|
28
bench/app.py
28
bench/app.py
@ -6,21 +6,15 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import shutil
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
# imports - third party imports
|
# imports - third party imports
|
||||||
import click
|
import click
|
||||||
import git
|
|
||||||
import requests
|
|
||||||
import semantic_version
|
|
||||||
from six.moves import reload_module
|
|
||||||
from setuptools.config import read_configuration
|
from setuptools.config import read_configuration
|
||||||
|
|
||||||
# imports - module imports
|
# imports - module imports
|
||||||
import bench
|
import bench
|
||||||
from bench.config.common_site_config import get_config
|
|
||||||
from bench.utils import color, CommandFailedError, build_assets, check_git_for_shallow_clone, exec_cmd, get_cmd_output, get_frappe, restart_supervisor_processes, restart_systemd_processes, run_frappe_cmd
|
from bench.utils import color, CommandFailedError, build_assets, check_git_for_shallow_clone, exec_cmd, get_cmd_output, get_frappe, restart_supervisor_processes, restart_systemd_processes, run_frappe_cmd
|
||||||
|
|
||||||
|
|
||||||
@ -92,6 +86,9 @@ def remove_from_excluded_apps_txt(app, bench_path='.'):
|
|||||||
return write_excluded_apps_txt(apps, bench_path=bench_path)
|
return write_excluded_apps_txt(apps, bench_path=bench_path)
|
||||||
|
|
||||||
def get_app(git_url, branch=None, bench_path='.', skip_assets=False, verbose=False, restart_bench=True, overwrite=False):
|
def get_app(git_url, branch=None, bench_path='.', skip_assets=False, verbose=False, restart_bench=True, overwrite=False):
|
||||||
|
import requests
|
||||||
|
import shutil
|
||||||
|
|
||||||
if not os.path.exists(git_url):
|
if not os.path.exists(git_url):
|
||||||
if not is_git_url(git_url):
|
if not is_git_url(git_url):
|
||||||
orgs = ['frappe', 'erpnext']
|
orgs = ['frappe', 'erpnext']
|
||||||
@ -166,17 +163,13 @@ def new_app(app, bench_path='.'):
|
|||||||
app = app.lower().replace(" ", "_").replace("-", "_")
|
app = app.lower().replace(" ", "_").replace("-", "_")
|
||||||
logger.log('creating new app {}'.format(app))
|
logger.log('creating new app {}'.format(app))
|
||||||
apps = os.path.abspath(os.path.join(bench_path, 'apps'))
|
apps = os.path.abspath(os.path.join(bench_path, 'apps'))
|
||||||
bench.set_frappe_version(bench_path=bench_path)
|
|
||||||
|
|
||||||
if bench.FRAPPE_VERSION == 4:
|
|
||||||
exec_cmd("{frappe} --make_app {apps} {app}".format(frappe=get_frappe(bench_path=bench_path),
|
|
||||||
apps=apps, app=app))
|
|
||||||
else:
|
|
||||||
run_frappe_cmd('make-app', apps, app, bench_path=bench_path)
|
run_frappe_cmd('make-app', apps, app, bench_path=bench_path)
|
||||||
install_app(app, bench_path=bench_path)
|
install_app(app, bench_path=bench_path)
|
||||||
|
|
||||||
|
|
||||||
def install_app(app, bench_path=".", verbose=False, no_cache=False, restart_bench=True, skip_assets=False):
|
def install_app(app, bench_path=".", verbose=False, no_cache=False, restart_bench=True, skip_assets=False):
|
||||||
|
from bench.config.common_site_config import get_config
|
||||||
|
|
||||||
print('\n{0}Installing {1}{2}'.format(color.yellow, app, color.nc))
|
print('\n{0}Installing {1}{2}'.format(color.yellow, app, color.nc))
|
||||||
logger.log("installing {}".format(app))
|
logger.log("installing {}".format(app))
|
||||||
|
|
||||||
@ -205,6 +198,9 @@ def install_app(app, bench_path=".", verbose=False, no_cache=False, restart_benc
|
|||||||
|
|
||||||
|
|
||||||
def remove_app(app, bench_path='.'):
|
def remove_app(app, bench_path='.'):
|
||||||
|
import shutil
|
||||||
|
from bench.config.common_site_config import get_config
|
||||||
|
|
||||||
if app not in get_apps(bench_path):
|
if app not in get_apps(bench_path):
|
||||||
print("No app named {0}".format(app))
|
print("No app named {0}".format(app))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@ -232,6 +228,8 @@ def remove_app(app, bench_path='.'):
|
|||||||
|
|
||||||
def pull_apps(apps=None, bench_path='.', reset=False):
|
def pull_apps(apps=None, bench_path='.', reset=False):
|
||||||
'''Check all apps if there no local changes, pull'''
|
'''Check all apps if there no local changes, pull'''
|
||||||
|
from bench.config.common_site_config import get_config
|
||||||
|
|
||||||
rebase = '--rebase' if get_config(bench_path).get('rebase_on_pull') else ''
|
rebase = '--rebase' if get_config(bench_path).get('rebase_on_pull') else ''
|
||||||
|
|
||||||
apps = apps or get_apps(bench_path=bench_path)
|
apps = apps or get_apps(bench_path=bench_path)
|
||||||
@ -380,6 +378,8 @@ def get_repo_dir(app, bench_path='.'):
|
|||||||
return os.path.join(bench_path, 'apps', app)
|
return os.path.join(bench_path, 'apps', app)
|
||||||
|
|
||||||
def switch_branch(branch, apps=None, bench_path='.', upgrade=False, check_upgrade=True):
|
def switch_branch(branch, apps=None, bench_path='.', upgrade=False, check_upgrade=True):
|
||||||
|
import git
|
||||||
|
from six.moves import reload_module
|
||||||
from bench.utils import update_requirements, update_node_packages, backup_all_sites, patch_sites, build_assets, post_upgrade
|
from bench.utils import update_requirements, update_node_packages, backup_all_sites, patch_sites, build_assets, post_upgrade
|
||||||
apps_dir = os.path.join(bench_path, 'apps')
|
apps_dir = os.path.join(bench_path, 'apps')
|
||||||
version_upgrade = (False,)
|
version_upgrade = (False,)
|
||||||
@ -447,6 +447,8 @@ def get_version_from_string(contents, field='__version__'):
|
|||||||
return match.group(2)
|
return match.group(2)
|
||||||
|
|
||||||
def get_major_version(version):
|
def get_major_version(version):
|
||||||
|
import semantic_version
|
||||||
|
|
||||||
return semantic_version.Version(version).major
|
return semantic_version.Version(version).major
|
||||||
|
|
||||||
def install_apps_from_path(path, bench_path='.'):
|
def install_apps_from_path(path, bench_path='.'):
|
||||||
@ -455,6 +457,8 @@ def install_apps_from_path(path, bench_path='.'):
|
|||||||
get_app(app['url'], branch=app.get('branch'), bench_path=bench_path, skip_assets=True)
|
get_app(app['url'], branch=app.get('branch'), bench_path=bench_path, skip_assets=True)
|
||||||
|
|
||||||
def get_apps_json(path):
|
def get_apps_json(path):
|
||||||
|
import requests
|
||||||
|
|
||||||
if path.startswith('http'):
|
if path.startswith('http'):
|
||||||
r = requests.get(path)
|
r = requests.get(path)
|
||||||
return r.json()
|
return r.json()
|
||||||
|
@ -30,10 +30,9 @@ def cli():
|
|||||||
logger = setup_logging()
|
logger = setup_logging()
|
||||||
logger.info(command)
|
logger.info(command)
|
||||||
|
|
||||||
if sys.argv[1] not in ("src", ):
|
if len(sys.argv) > 1 and sys.argv[1] not in ("src", ):
|
||||||
check_uid()
|
check_uid()
|
||||||
change_uid()
|
change_uid()
|
||||||
|
|
||||||
change_dir()
|
change_dir()
|
||||||
|
|
||||||
if is_dist_editable(bench.PROJECT_NAME) and len(sys.argv) > 1 and sys.argv[1] != "src" and not get_config(".").get("developer_mode"):
|
if is_dist_editable(bench.PROJECT_NAME) and len(sys.argv) > 1 and sys.argv[1] != "src" and not get_config(".").get("developer_mode"):
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
# imports - standard imports
|
|
||||||
import ast
|
|
||||||
|
|
||||||
# imports - module imports
|
# imports - module imports
|
||||||
from bench.config.common_site_config import update_config, get_config, put_config
|
from bench.config.common_site_config import update_config, get_config, put_config
|
||||||
|
|
||||||
@ -52,6 +49,8 @@ def config_http_timeout(seconds):
|
|||||||
@click.command('set-common-config', help='Set value in common config')
|
@click.command('set-common-config', help='Set value in common config')
|
||||||
@click.option('configs', '-c', '--config', multiple=True, type=(str, str))
|
@click.option('configs', '-c', '--config', multiple=True, type=(str, str))
|
||||||
def set_common_config(configs):
|
def set_common_config(configs):
|
||||||
|
import ast
|
||||||
|
|
||||||
common_site_config = {}
|
common_site_config = {}
|
||||||
for key, value in configs:
|
for key, value in configs:
|
||||||
if value in ('true', 'false'):
|
if value in ('true', 'false'):
|
||||||
|
@ -8,11 +8,11 @@ import click
|
|||||||
@click.option('--ignore-exist', is_flag = True, default = False, help = "Ignore if Bench instance exists.")
|
@click.option('--ignore-exist', is_flag = True, default = False, help = "Ignore if Bench instance exists.")
|
||||||
@click.option('--apps_path', default=None, help="path to json files with apps to install after init")
|
@click.option('--apps_path', default=None, help="path to json files with apps to install after init")
|
||||||
@click.option('--frappe-path', default=None, help="path to frappe repo")
|
@click.option('--frappe-path', default=None, help="path to frappe repo")
|
||||||
@click.option('--frappe-branch', default=None, help="path to frappe repo")
|
@click.option('--frappe-branch', default=None, help="Clone a particular branch of frappe")
|
||||||
@click.option('--clone-from', default=None, help="copy repos from path")
|
@click.option('--clone-from', default=None, help="copy repos from path")
|
||||||
@click.option('--clone-without-update', is_flag=True, help="copy repos from path without update")
|
@click.option('--clone-without-update', is_flag=True, help="copy repos from path without update")
|
||||||
@click.option('--no-procfile', is_flag=True, help="Pull changes in all the apps in bench")
|
@click.option('--no-procfile', is_flag=True, help="Do not create a Procfile")
|
||||||
@click.option('--no-backups',is_flag=True, help="Run migrations for all sites in the bench")
|
@click.option('--no-backups',is_flag=True, help="Do not set up automatic periodic backups for all sites on this bench")
|
||||||
@click.option('--skip-redis-config-generation', is_flag=True, help="Skip redis config generation if already specifying the common-site-config file")
|
@click.option('--skip-redis-config-generation', is_flag=True, help="Skip redis config generation if already specifying the common-site-config file")
|
||||||
@click.option('--skip-assets',is_flag=True, default=False, help="Do not build assets")
|
@click.option('--skip-assets',is_flag=True, default=False, help="Do not build assets")
|
||||||
@click.option('--verbose',is_flag=True, help="Verbose output during install")
|
@click.option('--verbose',is_flag=True, help="Verbose output during install")
|
||||||
|
@ -6,10 +6,7 @@ import sys
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
# imports - module imports
|
# imports - module imports
|
||||||
import bench.config.lets_encrypt
|
|
||||||
import bench.config.nginx
|
|
||||||
import bench.config.procfile
|
import bench.config.procfile
|
||||||
import bench.config.production_setup
|
|
||||||
import bench.config.redis
|
import bench.config.redis
|
||||||
import bench.config.site_config
|
import bench.config.site_config
|
||||||
import bench.config.supervisor
|
import bench.config.supervisor
|
||||||
@ -31,20 +28,25 @@ def setup_sudoers(user):
|
|||||||
@click.command("nginx", help="Generate configuration files for NGINX")
|
@click.command("nginx", help="Generate configuration files for NGINX")
|
||||||
@click.option("--yes", help="Yes to regeneration of nginx config file", default=False, is_flag=True)
|
@click.option("--yes", help="Yes to regeneration of nginx config file", default=False, is_flag=True)
|
||||||
def setup_nginx(yes=False):
|
def setup_nginx(yes=False):
|
||||||
|
import bench.config.nginx
|
||||||
|
|
||||||
bench.config.nginx.make_nginx_conf(bench_path=".", yes=yes)
|
bench.config.nginx.make_nginx_conf(bench_path=".", yes=yes)
|
||||||
|
|
||||||
|
|
||||||
@click.command("reload-nginx", help="Checks NGINX config file and reloads service")
|
@click.command("reload-nginx", help="Checks NGINX config file and reloads service")
|
||||||
def reload_nginx():
|
def reload_nginx():
|
||||||
|
import bench.config.production_setup
|
||||||
|
|
||||||
bench.config.production_setup.reload_nginx()
|
bench.config.production_setup.reload_nginx()
|
||||||
|
|
||||||
|
|
||||||
@click.command("supervisor", help="Generate configuration for supervisor")
|
@click.command("supervisor", help="Generate configuration for supervisor")
|
||||||
@click.option("--user", help="optional user argument")
|
@click.option("--user", help="optional user argument")
|
||||||
@click.option("--yes", help="Yes to regeneration of supervisor config", is_flag=True, default=False)
|
@click.option("--yes", help="Yes to regeneration of supervisor config", is_flag=True, default=False)
|
||||||
def setup_supervisor(user=None, yes=False):
|
@click.option("--skip-redis", help="Skip redis configuration", is_flag=True, default=False)
|
||||||
|
def setup_supervisor(user=None, yes=False, skip_redis=False):
|
||||||
bench.config.supervisor.update_supervisord_config(user=user, yes=yes)
|
bench.config.supervisor.update_supervisord_config(user=user, yes=yes)
|
||||||
bench.config.supervisor.generate_supervisor_config(bench_path=".", user=user, yes=yes)
|
bench.config.supervisor.generate_supervisor_config(bench_path=".", user=user, yes=yes, skip_redis=skip_redis)
|
||||||
|
|
||||||
|
|
||||||
@click.command("redis", help="Generates configuration for Redis")
|
@click.command("redis", help="Generates configuration for Redis")
|
||||||
@ -61,6 +63,8 @@ def setup_fonts():
|
|||||||
@click.argument("user")
|
@click.argument("user")
|
||||||
@click.option("--yes", help="Yes to regeneration config", is_flag=True, default=False)
|
@click.option("--yes", help="Yes to regeneration config", is_flag=True, default=False)
|
||||||
def setup_production(user, yes=False):
|
def setup_production(user, yes=False):
|
||||||
|
import bench.config.production_setup
|
||||||
|
|
||||||
bench.config.production_setup.setup_production(user=user, yes=yes)
|
bench.config.production_setup.setup_production(user=user, yes=yes)
|
||||||
|
|
||||||
|
|
||||||
@ -103,6 +107,8 @@ def set_ssh_port(port, force=False):
|
|||||||
@click.option("--custom-domain")
|
@click.option("--custom-domain")
|
||||||
@click.option('-n', '--non-interactive', default=False, is_flag=True, help="Run command non-interactively. This flag restarts nginx and runs certbot non interactively. Shouldn't be used on 1'st attempt")
|
@click.option('-n', '--non-interactive', default=False, is_flag=True, help="Run command non-interactively. This flag restarts nginx and runs certbot non interactively. Shouldn't be used on 1'st attempt")
|
||||||
def setup_letsencrypt(site, custom_domain, non_interactive):
|
def setup_letsencrypt(site, custom_domain, non_interactive):
|
||||||
|
import bench.config.lets_encrypt
|
||||||
|
|
||||||
bench.config.lets_encrypt.setup_letsencrypt(site, custom_domain, bench_path=".", interactive=not non_interactive)
|
bench.config.lets_encrypt.setup_letsencrypt(site, custom_domain, bench_path=".", interactive=not non_interactive)
|
||||||
|
|
||||||
|
|
||||||
@ -111,6 +117,8 @@ def setup_letsencrypt(site, custom_domain, non_interactive):
|
|||||||
@click.option("--email")
|
@click.option("--email")
|
||||||
@click.option("--exclude-base-domain", default=False, is_flag=True, help="SSL Certificate not applicable for base domain")
|
@click.option("--exclude-base-domain", default=False, is_flag=True, help="SSL Certificate not applicable for base domain")
|
||||||
def setup_wildcard_ssl(domain, email, exclude_base_domain):
|
def setup_wildcard_ssl(domain, email, exclude_base_domain):
|
||||||
|
import bench.config.lets_encrypt
|
||||||
|
|
||||||
bench.config.lets_encrypt.setup_wildcard_ssl(domain, email, bench_path=".", exclude_base_domain=exclude_base_domain)
|
bench.config.lets_encrypt.setup_wildcard_ssl(domain, email, bench_path=".", exclude_base_domain=exclude_base_domain)
|
||||||
|
|
||||||
|
|
||||||
@ -253,8 +261,8 @@ def setup_roles(role, **kwargs):
|
|||||||
|
|
||||||
@click.command("fail2ban", help="Setup fail2ban, an intrusion prevention software framework that protects computer servers from brute-force attacks")
|
@click.command("fail2ban", help="Setup fail2ban, an intrusion prevention software framework that protects computer servers from brute-force attacks")
|
||||||
@click.option("--maxretry", default=6, help="Number of matches (i.e. value of the counter) which triggers ban action on the IP. Default is 6 seconds" )
|
@click.option("--maxretry", default=6, help="Number of matches (i.e. value of the counter) which triggers ban action on the IP. Default is 6 seconds" )
|
||||||
@click.option("--bantime", default=600, help="The counter is set to zero if no match is found within 'findtime' seconds. Default is 600 seconds")
|
@click.option("--bantime", default=600, help="Duration (in seconds) for IP to be banned for. Negative number for 'permanent' ban. Default is 600 seconds")
|
||||||
@click.option("--findtime", default=600, help="Duration (in seconds) for IP to be banned for. Negative number for 'permanent' ban. Default is 600 seconds")
|
@click.option("--findtime", default=600, help="The counter is set to zero if match found within 'findtime' seconds doesn't exceed 'maxretry'. Default is 600 seconds")
|
||||||
def setup_nginx_proxy_jail(**kwargs):
|
def setup_nginx_proxy_jail(**kwargs):
|
||||||
run_playbook("roles/fail2ban/tasks/configure_nginx_jail.yml", extra_vars=kwargs)
|
run_playbook("roles/fail2ban/tasks/configure_nginx_jail.yml", extra_vars=kwargs)
|
||||||
|
|
||||||
|
@ -15,11 +15,12 @@ from bench.utils import post_upgrade, patch_sites, build_assets
|
|||||||
@click.option('--restart-supervisor', is_flag=True, help="Restart supervisor processes after update")
|
@click.option('--restart-supervisor', is_flag=True, help="Restart supervisor processes after update")
|
||||||
@click.option('--restart-systemd', is_flag=True, help="Restart systemd units after update")
|
@click.option('--restart-systemd', is_flag=True, help="Restart systemd units after update")
|
||||||
@click.option('--no-backup', is_flag=True, help="If this flag is set, sites won't be backed up prior to updates. Note: This is not recommended in production.")
|
@click.option('--no-backup', is_flag=True, help="If this flag is set, sites won't be backed up prior to updates. Note: This is not recommended in production.")
|
||||||
|
@click.option('--no-compile', is_flag=True, help="If set, Python bytecode won't be compiled before restarting the processes")
|
||||||
@click.option('--force', is_flag=True, help="Forces major version upgrades")
|
@click.option('--force', is_flag=True, help="Forces major version upgrades")
|
||||||
@click.option('--reset', is_flag=True, help="Hard resets git branch's to their new states overriding any changes and overriding rebase on pull")
|
@click.option('--reset', is_flag=True, help="Hard resets git branch's to their new states overriding any changes and overriding rebase on pull")
|
||||||
def update(pull, apps, patch, build, requirements, restart_supervisor, restart_systemd, no_backup, force, reset):
|
def update(pull, apps, patch, build, requirements, restart_supervisor, restart_systemd, no_backup, no_compile, force, reset):
|
||||||
from bench.utils import update
|
from bench.utils import update
|
||||||
update(pull=pull, apps=apps, patch=patch, build=build, requirements=requirements, restart_supervisor=restart_supervisor, restart_systemd=restart_systemd, backup=not no_backup, force=force, reset=reset)
|
update(pull=pull, apps=apps, patch=patch, build=build, requirements=requirements, restart_supervisor=restart_supervisor, restart_systemd=restart_systemd, backup=not no_backup, compile=not no_compile, force=force, reset=reset)
|
||||||
|
|
||||||
|
|
||||||
@click.command('retry-upgrade', help="Retry a failed upgrade")
|
@click.command('retry-upgrade', help="Retry a failed upgrade")
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"""Module for setting up system and respective bench configurations"""
|
"""Module for setting up system and respective bench configurations"""
|
||||||
|
|
||||||
# imports - third party imports
|
|
||||||
from jinja2 import Environment, PackageLoader
|
|
||||||
|
|
||||||
env = Environment(loader=PackageLoader('bench.config'))
|
def env():
|
||||||
|
from jinja2 import Environment, PackageLoader
|
||||||
|
return Environment(loader=PackageLoader('bench.config'))
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
# imports - standard imports
|
# imports - standard imports
|
||||||
import getpass
|
import getpass
|
||||||
import json
|
import json
|
||||||
import multiprocessing
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
# imports - third party imports
|
|
||||||
from six.moves.urllib.parse import urlparse
|
|
||||||
|
|
||||||
|
|
||||||
default_config = {
|
default_config = {
|
||||||
@ -54,8 +51,10 @@ def get_config_path(bench_path):
|
|||||||
def get_gunicorn_workers():
|
def get_gunicorn_workers():
|
||||||
'''This function will return the maximum workers that can be started depending upon
|
'''This function will return the maximum workers that can be started depending upon
|
||||||
number of cpu's present on the machine'''
|
number of cpu's present on the machine'''
|
||||||
|
import multiprocessing
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"gunicorn_workers": multiprocessing.cpu_count()
|
"gunicorn_workers": multiprocessing.cpu_count() * 2 + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
def update_config_for_frappe(config, bench_path):
|
def update_config_for_frappe(config, bench_path):
|
||||||
@ -73,6 +72,8 @@ def update_config_for_frappe(config, bench_path):
|
|||||||
# TODO Optionally we need to add the host or domain name in case dns_multitenant is false
|
# TODO Optionally we need to add the host or domain name in case dns_multitenant is false
|
||||||
|
|
||||||
def make_ports(bench_path):
|
def make_ports(bench_path):
|
||||||
|
from six.moves.urllib.parse import urlparse
|
||||||
|
|
||||||
benches_path = os.path.dirname(os.path.abspath(bench_path))
|
benches_path = os.path.dirname(os.path.abspath(bench_path))
|
||||||
|
|
||||||
default_ports = {
|
default_ports = {
|
||||||
|
@ -3,8 +3,6 @@ import os
|
|||||||
|
|
||||||
# imports - third party imports
|
# imports - third party imports
|
||||||
import click
|
import click
|
||||||
from crontab import CronTab
|
|
||||||
from six.moves.urllib.request import urlretrieve
|
|
||||||
|
|
||||||
# imports - module imports
|
# imports - module imports
|
||||||
import bench
|
import bench
|
||||||
@ -48,7 +46,7 @@ def setup_letsencrypt(site, custom_domain, bench_path, interactive):
|
|||||||
|
|
||||||
|
|
||||||
def create_config(site, custom_domain):
|
def create_config(site, custom_domain):
|
||||||
config = bench.config.env.get_template('letsencrypt.cfg').render(domain=custom_domain or site)
|
config = bench.config.env().get_template('letsencrypt.cfg').render(domain=custom_domain or site)
|
||||||
config_path = '/etc/letsencrypt/configs/{site}.cfg'.format(site=custom_domain or site)
|
config_path = '/etc/letsencrypt/configs/{site}.cfg'.format(site=custom_domain or site)
|
||||||
create_dir_if_missing(config_path)
|
create_dir_if_missing(config_path)
|
||||||
|
|
||||||
@ -86,6 +84,8 @@ def run_certbot_and_setup_ssl(site, custom_domain, bench_path, interactive=True)
|
|||||||
|
|
||||||
|
|
||||||
def setup_crontab():
|
def setup_crontab():
|
||||||
|
from crontab import CronTab
|
||||||
|
|
||||||
job_command = '/opt/certbot-auto renew -a nginx --post-hook "systemctl reload nginx"'
|
job_command = '/opt/certbot-auto renew -a nginx --post-hook "systemctl reload nginx"'
|
||||||
job_comment = 'Renew lets-encrypt every month'
|
job_comment = 'Renew lets-encrypt every month'
|
||||||
print("Setting Up cron job to {0}".format(job_comment))
|
print("Setting Up cron job to {0}".format(job_comment))
|
||||||
@ -106,6 +106,8 @@ def create_dir_if_missing(path):
|
|||||||
|
|
||||||
|
|
||||||
def get_certbot():
|
def get_certbot():
|
||||||
|
from six.moves.urllib.request import urlretrieve
|
||||||
|
|
||||||
certbot_path = get_certbot_path()
|
certbot_path = get_certbot_path()
|
||||||
create_dir_if_missing(certbot_path)
|
create_dir_if_missing(certbot_path)
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ def make_nginx_conf(bench_path, yes=False):
|
|||||||
if not click.confirm('nginx.conf already exists and this will overwrite it. Do you want to continue?'):
|
if not click.confirm('nginx.conf already exists and this will overwrite it. Do you want to continue?'):
|
||||||
return
|
return
|
||||||
|
|
||||||
template = bench.config.env.get_template('nginx.conf')
|
template = bench.config.env().get_template('nginx.conf')
|
||||||
bench_path = os.path.abspath(bench_path)
|
bench_path = os.path.abspath(bench_path)
|
||||||
sites_path = os.path.join(bench_path, "sites")
|
sites_path = os.path.join(bench_path, "sites")
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ def make_bench_manager_nginx_conf(bench_path, yes=False, port=23624, domain=None
|
|||||||
from bench.config.site_config import get_site_config
|
from bench.config.site_config import get_site_config
|
||||||
from bench.config.common_site_config import get_config
|
from bench.config.common_site_config import get_config
|
||||||
|
|
||||||
template = bench.config.env.get_template('bench_manager_nginx.conf')
|
template = bench.config.env().get_template('bench_manager_nginx.conf')
|
||||||
bench_path = os.path.abspath(bench_path)
|
bench_path = os.path.abspath(bench_path)
|
||||||
sites_path = os.path.join(bench_path, "sites")
|
sites_path = os.path.join(bench_path, "sites")
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ def setup_procfile(bench_path, yes=False, skip_redis=False):
|
|||||||
click.confirm('A Procfile already exists and this will overwrite it. Do you want to continue?',
|
click.confirm('A Procfile already exists and this will overwrite it. Do you want to continue?',
|
||||||
abort=True)
|
abort=True)
|
||||||
|
|
||||||
procfile = bench.config.env.get_template('Procfile').render(
|
procfile = bench.config.env().get_template('Procfile').render(
|
||||||
node=find_executable("node") or find_executable("nodejs"),
|
node=find_executable("node") or find_executable("nodejs"),
|
||||||
use_rq=use_rq(bench_path),
|
use_rq=use_rq(bench_path),
|
||||||
webserver_port=config.get('webserver_port'),
|
webserver_port=config.get('webserver_port'),
|
||||||
|
@ -3,16 +3,14 @@ import os
|
|||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
# imports - third party imports
|
|
||||||
import semantic_version
|
|
||||||
from six.moves.urllib.parse import urlparse
|
|
||||||
|
|
||||||
# imports - module imports
|
# imports - module imports
|
||||||
import bench
|
import bench
|
||||||
from bench.config.common_site_config import get_config
|
from bench.config.common_site_config import get_config
|
||||||
|
|
||||||
|
|
||||||
def generate_config(bench_path):
|
def generate_config(bench_path):
|
||||||
|
from six.moves.urllib.parse import urlparse
|
||||||
|
|
||||||
config = get_config(bench_path)
|
config = get_config(bench_path)
|
||||||
|
|
||||||
ports = {}
|
ports = {}
|
||||||
@ -52,7 +50,7 @@ def generate_config(bench_path):
|
|||||||
os.makedirs(pid_path)
|
os.makedirs(pid_path)
|
||||||
|
|
||||||
def write_redis_config(template_name, context, bench_path):
|
def write_redis_config(template_name, context, bench_path):
|
||||||
template = bench.config.env.get_template(template_name)
|
template = bench.config.env().get_template(template_name)
|
||||||
|
|
||||||
if "pid_path" not in context:
|
if "pid_path" not in context:
|
||||||
context["pid_path"] = os.path.abspath(os.path.join(bench_path, "config", "pids"))
|
context["pid_path"] = os.path.abspath(os.path.join(bench_path, "config", "pids"))
|
||||||
@ -61,6 +59,8 @@ def write_redis_config(template_name, context, bench_path):
|
|||||||
f.write(template.render(**context))
|
f.write(template.render(**context))
|
||||||
|
|
||||||
def get_redis_version():
|
def get_redis_version():
|
||||||
|
import semantic_version
|
||||||
|
|
||||||
version_string = subprocess.check_output('redis-server --version', shell=True)
|
version_string = subprocess.check_output('redis-server --version', shell=True)
|
||||||
version_string = version_string.decode('utf-8').strip()
|
version_string = version_string.decode('utf-8').strip()
|
||||||
# extract version number from string
|
# extract version number from string
|
||||||
|
@ -4,7 +4,6 @@ import os
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
# imports - module imports
|
# imports - module imports
|
||||||
from bench.config.nginx import make_nginx_conf
|
|
||||||
from bench.utils import get_sites
|
from bench.utils import get_sites
|
||||||
|
|
||||||
|
|
||||||
@ -35,6 +34,8 @@ def set_ssl_certificate_key(site, ssl_certificate_key, bench_path='.', gen_confi
|
|||||||
set_site_config_nginx_property(site, {"ssl_certificate_key": ssl_certificate_key}, bench_path=bench_path, gen_config=gen_config)
|
set_site_config_nginx_property(site, {"ssl_certificate_key": ssl_certificate_key}, bench_path=bench_path, gen_config=gen_config)
|
||||||
|
|
||||||
def set_site_config_nginx_property(site, config, bench_path='.', gen_config=True):
|
def set_site_config_nginx_property(site, config, bench_path='.', gen_config=True):
|
||||||
|
from bench.config.nginx import make_nginx_conf
|
||||||
|
|
||||||
if site not in get_sites(bench_path=bench_path):
|
if site not in get_sites(bench_path=bench_path):
|
||||||
raise Exception("No such site")
|
raise Exception("No such site")
|
||||||
update_site_config(site, config, bench_path=bench_path)
|
update_site_config(site, config, bench_path=bench_path)
|
||||||
|
@ -5,24 +5,23 @@ import os
|
|||||||
|
|
||||||
# imports - module imports
|
# imports - module imports
|
||||||
import bench
|
import bench
|
||||||
from bench.app import get_current_frappe_version, use_rq
|
from bench.app import use_rq
|
||||||
from bench.utils import get_bench_name, find_executable
|
from bench.utils import get_bench_name, find_executable
|
||||||
from bench.config.common_site_config import get_config, update_config, get_gunicorn_workers
|
from bench.config.common_site_config import get_config, update_config, get_gunicorn_workers
|
||||||
|
|
||||||
# imports - third party imports
|
# imports - third party imports
|
||||||
import click
|
import click
|
||||||
from six.moves import configparser
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(bench.PROJECT_NAME)
|
logger = logging.getLogger(bench.PROJECT_NAME)
|
||||||
|
|
||||||
|
|
||||||
def generate_supervisor_config(bench_path, user=None, yes=False):
|
def generate_supervisor_config(bench_path, user=None, yes=False, skip_redis=False):
|
||||||
"""Generate supervisor config for respective bench path"""
|
"""Generate supervisor config for respective bench path"""
|
||||||
if not user:
|
if not user:
|
||||||
user = getpass.getuser()
|
user = getpass.getuser()
|
||||||
|
|
||||||
template = bench.config.env.get_template('supervisor.conf')
|
template = bench.config.env().get_template('supervisor.conf')
|
||||||
config = get_config(bench_path=bench_path)
|
config = get_config(bench_path=bench_path)
|
||||||
bench_dir = os.path.abspath(bench_path)
|
bench_dir = os.path.abspath(bench_path)
|
||||||
|
|
||||||
@ -30,7 +29,6 @@ def generate_supervisor_config(bench_path, user=None, yes=False):
|
|||||||
"bench_dir": bench_dir,
|
"bench_dir": bench_dir,
|
||||||
"sites_dir": os.path.join(bench_dir, 'sites'),
|
"sites_dir": os.path.join(bench_dir, 'sites'),
|
||||||
"user": user,
|
"user": user,
|
||||||
"frappe_version": get_current_frappe_version(bench_path),
|
|
||||||
"use_rq": use_rq(bench_path),
|
"use_rq": use_rq(bench_path),
|
||||||
"http_timeout": config.get("http_timeout", 120),
|
"http_timeout": config.get("http_timeout", 120),
|
||||||
"redis_server": find_executable('redis-server'),
|
"redis_server": find_executable('redis-server'),
|
||||||
@ -42,7 +40,8 @@ def generate_supervisor_config(bench_path, user=None, yes=False):
|
|||||||
"gunicorn_workers": config.get('gunicorn_workers', get_gunicorn_workers()["gunicorn_workers"]),
|
"gunicorn_workers": config.get('gunicorn_workers', get_gunicorn_workers()["gunicorn_workers"]),
|
||||||
"bench_name": get_bench_name(bench_path),
|
"bench_name": get_bench_name(bench_path),
|
||||||
"background_workers": config.get('background_workers') or 1,
|
"background_workers": config.get('background_workers') or 1,
|
||||||
"bench_cmd": find_executable('bench')
|
"bench_cmd": find_executable('bench'),
|
||||||
|
"skip_redis": skip_redis,
|
||||||
})
|
})
|
||||||
|
|
||||||
conf_path = os.path.join(bench_path, 'config', 'supervisor.conf')
|
conf_path = os.path.join(bench_path, 'config', 'supervisor.conf')
|
||||||
@ -68,6 +67,8 @@ def get_supervisord_conf():
|
|||||||
|
|
||||||
def update_supervisord_config(user=None, yes=False):
|
def update_supervisord_config(user=None, yes=False):
|
||||||
"""From bench v5.x, we're moving to supervisor running as user"""
|
"""From bench v5.x, we're moving to supervisor running as user"""
|
||||||
|
from six.moves import configparser
|
||||||
|
|
||||||
from bench.config.production_setup import service
|
from bench.config.production_setup import service
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
|
@ -7,7 +7,7 @@ import click
|
|||||||
|
|
||||||
# imports - module imports
|
# imports - module imports
|
||||||
import bench
|
import bench
|
||||||
from bench.app import get_current_frappe_version, use_rq
|
from bench.app import use_rq
|
||||||
from bench.config.common_site_config import get_config, get_gunicorn_workers, update_config
|
from bench.config.common_site_config import get_config, get_gunicorn_workers, update_config
|
||||||
from bench.utils import exec_cmd, find_executable, get_bench_name
|
from bench.utils import exec_cmd, find_executable, get_bench_name
|
||||||
|
|
||||||
@ -51,7 +51,6 @@ def generate_systemd_config(bench_path, user=None, yes=False,
|
|||||||
"bench_dir": bench_dir,
|
"bench_dir": bench_dir,
|
||||||
"sites_dir": os.path.join(bench_dir, 'sites'),
|
"sites_dir": os.path.join(bench_dir, 'sites'),
|
||||||
"user": user,
|
"user": user,
|
||||||
"frappe_version": get_current_frappe_version(bench_path),
|
|
||||||
"use_rq": use_rq(bench_path),
|
"use_rq": use_rq(bench_path),
|
||||||
"http_timeout": config.get("http_timeout", 120),
|
"http_timeout": config.get("http_timeout", 120),
|
||||||
"redis_server": find_executable('redis-server'),
|
"redis_server": find_executable('redis-server'),
|
||||||
@ -85,7 +84,7 @@ def setup_systemd_directory(bench_path):
|
|||||||
|
|
||||||
def setup_main_config(bench_info, bench_path):
|
def setup_main_config(bench_info, bench_path):
|
||||||
# Main config
|
# Main config
|
||||||
bench_template = bench.config.env.get_template('systemd/frappe-bench.target')
|
bench_template = bench.config.env().get_template('systemd/frappe-bench.target')
|
||||||
bench_config = bench_template.render(**bench_info)
|
bench_config = bench_template.render(**bench_info)
|
||||||
bench_config_path = os.path.join(bench_path, 'config', 'systemd' , bench_info.get("bench_name") + '.target')
|
bench_config_path = os.path.join(bench_path, 'config', 'systemd' , bench_info.get("bench_name") + '.target')
|
||||||
|
|
||||||
@ -94,11 +93,11 @@ def setup_main_config(bench_info, bench_path):
|
|||||||
|
|
||||||
def setup_workers_config(bench_info, bench_path):
|
def setup_workers_config(bench_info, bench_path):
|
||||||
# Worker Group
|
# Worker Group
|
||||||
bench_workers_target_template = bench.config.env.get_template('systemd/frappe-bench-workers.target')
|
bench_workers_target_template = bench.config.env().get_template('systemd/frappe-bench-workers.target')
|
||||||
bench_default_worker_template = bench.config.env.get_template('systemd/frappe-bench-frappe-default-worker.service')
|
bench_default_worker_template = bench.config.env().get_template('systemd/frappe-bench-frappe-default-worker.service')
|
||||||
bench_short_worker_template = bench.config.env.get_template('systemd/frappe-bench-frappe-short-worker.service')
|
bench_short_worker_template = bench.config.env().get_template('systemd/frappe-bench-frappe-short-worker.service')
|
||||||
bench_long_worker_template = bench.config.env.get_template('systemd/frappe-bench-frappe-long-worker.service')
|
bench_long_worker_template = bench.config.env().get_template('systemd/frappe-bench-frappe-long-worker.service')
|
||||||
bench_schedule_worker_template = bench.config.env.get_template('systemd/frappe-bench-frappe-schedule.service')
|
bench_schedule_worker_template = bench.config.env().get_template('systemd/frappe-bench-frappe-schedule.service')
|
||||||
|
|
||||||
bench_workers_target_config = bench_workers_target_template.render(**bench_info)
|
bench_workers_target_config = bench_workers_target_template.render(**bench_info)
|
||||||
bench_default_worker_config = bench_default_worker_template.render(**bench_info)
|
bench_default_worker_config = bench_default_worker_template.render(**bench_info)
|
||||||
@ -129,9 +128,9 @@ def setup_workers_config(bench_info, bench_path):
|
|||||||
|
|
||||||
def setup_web_config(bench_info, bench_path):
|
def setup_web_config(bench_info, bench_path):
|
||||||
# Web Group
|
# Web Group
|
||||||
bench_web_target_template = bench.config.env.get_template('systemd/frappe-bench-web.target')
|
bench_web_target_template = bench.config.env().get_template('systemd/frappe-bench-web.target')
|
||||||
bench_web_service_template = bench.config.env.get_template('systemd/frappe-bench-frappe-web.service')
|
bench_web_service_template = bench.config.env().get_template('systemd/frappe-bench-frappe-web.service')
|
||||||
bench_node_socketio_template = bench.config.env.get_template('systemd/frappe-bench-node-socketio.service')
|
bench_node_socketio_template = bench.config.env().get_template('systemd/frappe-bench-node-socketio.service')
|
||||||
|
|
||||||
bench_web_target_config = bench_web_target_template.render(**bench_info)
|
bench_web_target_config = bench_web_target_template.render(**bench_info)
|
||||||
bench_web_service_config = bench_web_service_template.render(**bench_info)
|
bench_web_service_config = bench_web_service_template.render(**bench_info)
|
||||||
@ -152,10 +151,10 @@ def setup_web_config(bench_info, bench_path):
|
|||||||
|
|
||||||
def setup_redis_config(bench_info, bench_path):
|
def setup_redis_config(bench_info, bench_path):
|
||||||
# Redis Group
|
# Redis Group
|
||||||
bench_redis_target_template = bench.config.env.get_template('systemd/frappe-bench-redis.target')
|
bench_redis_target_template = bench.config.env().get_template('systemd/frappe-bench-redis.target')
|
||||||
bench_redis_cache_template = bench.config.env.get_template('systemd/frappe-bench-redis-cache.service')
|
bench_redis_cache_template = bench.config.env().get_template('systemd/frappe-bench-redis-cache.service')
|
||||||
bench_redis_queue_template = bench.config.env.get_template('systemd/frappe-bench-redis-queue.service')
|
bench_redis_queue_template = bench.config.env().get_template('systemd/frappe-bench-redis-queue.service')
|
||||||
bench_redis_socketio_template = bench.config.env.get_template('systemd/frappe-bench-redis-socketio.service')
|
bench_redis_socketio_template = bench.config.env().get_template('systemd/frappe-bench-redis-socketio.service')
|
||||||
|
|
||||||
bench_redis_target_config = bench_redis_target_template.render(**bench_info)
|
bench_redis_target_config = bench_redis_target_template.render(**bench_info)
|
||||||
bench_redis_cache_config = bench_redis_cache_template.render(**bench_info)
|
bench_redis_cache_config = bench_redis_cache_template.render(**bench_info)
|
||||||
|
@ -30,6 +30,10 @@ server {
|
|||||||
limit_conn per_host_{{ bench_name_hash }} 8;
|
limit_conn per_host_{{ bench_name_hash }} 8;
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
proxy_buffer_size 128k;
|
||||||
|
proxy_buffers 4 256k;
|
||||||
|
proxy_busy_buffers_size 256k;
|
||||||
|
|
||||||
{% if ssl_certificate and ssl_certificate_key %}
|
{% if ssl_certificate and ssl_certificate_key %}
|
||||||
ssl on;
|
ssl on;
|
||||||
ssl_certificate {{ ssl_certificate }};
|
ssl_certificate {{ ssl_certificate }};
|
||||||
|
@ -114,6 +114,7 @@ killasgroup=true
|
|||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if not skip_redis %}
|
||||||
[program:{{ bench_name }}-redis-cache]
|
[program:{{ bench_name }}-redis-cache]
|
||||||
command={{ redis_server }} {{ redis_cache_config }}
|
command={{ redis_server }} {{ redis_cache_config }}
|
||||||
priority=1
|
priority=1
|
||||||
@ -133,8 +134,9 @@ stdout_logfile={{ bench_dir }}/logs/redis-queue.log
|
|||||||
stderr_logfile={{ bench_dir }}/logs/redis-queue.error.log
|
stderr_logfile={{ bench_dir }}/logs/redis-queue.error.log
|
||||||
user={{ user }}
|
user={{ user }}
|
||||||
directory={{ sites_dir }}
|
directory={{ sites_dir }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if frappe_version > 5 %}
|
{% if not skip_redis %}
|
||||||
[program:{{ bench_name }}-redis-socketio]
|
[program:{{ bench_name }}-redis-socketio]
|
||||||
command={{ redis_server }} {{ redis_socketio_config }}
|
command={{ redis_server }} {{ redis_socketio_config }}
|
||||||
priority=1
|
priority=1
|
||||||
@ -144,6 +146,7 @@ stdout_logfile={{ bench_dir }}/logs/redis-socketio.log
|
|||||||
stderr_logfile={{ bench_dir }}/logs/redis-socketio.error.log
|
stderr_logfile={{ bench_dir }}/logs/redis-socketio.error.log
|
||||||
user={{ user }}
|
user={{ user }}
|
||||||
directory={{ sites_dir }}
|
directory={{ sites_dir }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if node %}
|
{% if node %}
|
||||||
[program:{{ bench_name }}-node-socketio]
|
[program:{{ bench_name }}-node-socketio]
|
||||||
@ -157,8 +160,6 @@ user={{ user }}
|
|||||||
directory={{ bench_dir }}
|
directory={{ bench_dir }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
[group:{{ bench_name }}-web]
|
[group:{{ bench_name }}-web]
|
||||||
programs={{ bench_name }}-frappe-web {%- if node -%} ,{{ bench_name }}-node-socketio {%- endif%}
|
programs={{ bench_name }}-frappe-web {%- if node -%} ,{{ bench_name }}-node-socketio {%- endif%}
|
||||||
|
|
||||||
@ -174,5 +175,7 @@ programs={{ bench_name }}-frappe-workerbeat,{{ bench_name }}-frappe-worker,{{ be
|
|||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if not skip_redis %}
|
||||||
[group:{{ bench_name }}-redis]
|
[group:{{ bench_name }}-redis]
|
||||||
programs={{ bench_name }}-redis-cache,{{ bench_name }}-redis-queue {%- if frappe_version > 5 -%} ,{{ bench_name }}-redis-socketio {%- endif %}
|
programs={{ bench_name }}-redis-cache,{{ bench_name }}-redis-queue,{{ bench_name }}-redis-socketio
|
||||||
|
{% endif %}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
- name: Set home folder perms
|
- name: Set home folder perms
|
||||||
file:
|
file:
|
||||||
path: '/home/{{ frappe_user }}'
|
path: '{{ user_directory }}'
|
||||||
mode: 'o+rx'
|
mode: 'o+rx'
|
||||||
owner: '{{ frappe_user }}'
|
owner: '{{ frappe_user }}'
|
||||||
group: '{{ frappe_user }}'
|
group: '{{ frappe_user }}'
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
- name: Fix permissions
|
- name: Fix permissions
|
||||||
become_user: root
|
become_user: root
|
||||||
command: chown {{ frappe_user }} -R /home/{{ frappe_user }}
|
command: chown {{ frappe_user }} -R {{ user_directory }}
|
||||||
|
|
||||||
- name: python3 bench init for develop
|
- name: python3 bench init for develop
|
||||||
command: bench init {{ bench_path }} --frappe-path {{ frappe_repo_url }} --frappe-branch {{ frappe_branch }} --python {{ python }}
|
command: bench init {{ bench_path }} --frappe-path {{ frappe_repo_url }} --frappe-branch {{ frappe_branch }} --python {{ python }}
|
||||||
@ -77,6 +77,6 @@
|
|||||||
# Setup Bench for production environment
|
# Setup Bench for production environment
|
||||||
- include_tasks: setup_bench_production.yml
|
- include_tasks: setup_bench_production.yml
|
||||||
vars:
|
vars:
|
||||||
bench_path: "/home/{{ frappe_user }}/{{ bench_name }}"
|
bench_path: "{{ user_directory }}/{{ bench_name }}"
|
||||||
when: not run_travis and production
|
when: not run_travis and production
|
||||||
...
|
...
|
||||||
|
@ -13,16 +13,17 @@
|
|||||||
- name: Check whether the site already exists
|
- name: Check whether the site already exists
|
||||||
stat: path="{{ bench_path }}/sites/{{ site }}"
|
stat: path="{{ bench_path }}/sites/{{ site }}"
|
||||||
register: site_folder
|
register: site_folder
|
||||||
|
when: not without_site
|
||||||
|
|
||||||
- name: Create a new site
|
- name: Create a new site
|
||||||
command: "bench new-site {{ site }} --admin-password '{{ admin_password }}' --mariadb-root-password '{{ mysql_root_password }}'"
|
command: "bench new-site {{ site }} --admin-password '{{ admin_password }}' --mariadb-root-password '{{ mysql_root_password }}'"
|
||||||
args:
|
args:
|
||||||
chdir: "{{ bench_path }}"
|
chdir: "{{ bench_path }}"
|
||||||
when: not site_folder.stat.exists
|
when: not without_site and not site_folder.stat.exists
|
||||||
|
|
||||||
- name: Install ERPNext to default site
|
- name: Install ERPNext to default site
|
||||||
command: "bench --site {{ site }} install-app erpnext"
|
command: "bench --site {{ site }} install-app erpnext"
|
||||||
args:
|
args:
|
||||||
chdir: "{{ bench_path }}"
|
chdir: "{{ bench_path }}"
|
||||||
when: not without_erpnext
|
when: not without_site and not without_erpnext
|
||||||
...
|
...
|
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
- name: insert/update inputrc for history
|
- name: insert/update inputrc for history
|
||||||
blockinfile:
|
blockinfile:
|
||||||
dest: "/home/{{ frappe_user }}/.inputrc"
|
dest: "{{ user_directory }}/.inputrc"
|
||||||
create: yes
|
create: yes
|
||||||
block: |
|
block: |
|
||||||
## arrow up
|
## arrow up
|
||||||
|
@ -48,6 +48,10 @@
|
|||||||
[mysqld]
|
[mysqld]
|
||||||
pid-file = /var/run/mysqld/mysqld.pid
|
pid-file = /var/run/mysqld/mysqld.pid
|
||||||
socket = /var/run/mysqld/mysqld.sock
|
socket = /var/run/mysqld/mysqld.sock
|
||||||
|
|
||||||
|
# setting appeared inside mysql but overwritten by mariadb inside mariadb.conf.d/xx-server.cnf valued as utf8mb4_general_ci
|
||||||
|
|
||||||
|
collation-server = utf8mb4_unicode_ci
|
||||||
create: yes
|
create: yes
|
||||||
become: yes
|
become: yes
|
||||||
become_user: root
|
become_user: root
|
||||||
|
@ -24,7 +24,14 @@
|
|||||||
get_url:
|
get_url:
|
||||||
url: https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.5/wkhtmltox_0.12.5-1.focal_amd64.deb
|
url: https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.5/wkhtmltox_0.12.5-1.focal_amd64.deb
|
||||||
dest: /tmp/wkhtmltox.deb
|
dest: /tmp/wkhtmltox.deb
|
||||||
when: ansible_distribution == 'Ubuntu' and ansible_distribution_major_version == '20'
|
when: ansible_distribution == 'Ubuntu' and ansible_distribution_major_version == '20' and ansible_architecture != 'aarch64'
|
||||||
|
|
||||||
|
- name: download wkthmltox Ubuntu 20 arm64
|
||||||
|
get_url:
|
||||||
|
# wkhtmltox supports arm64 starting from 0.12.6
|
||||||
|
url: https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_arm64.deb
|
||||||
|
dest: /tmp/wkhtmltox.deb
|
||||||
|
when: ansible_distribution == 'Ubuntu' and ansible_distribution_major_version == '20' and ansible_architecture == 'aarch64'
|
||||||
|
|
||||||
- name: download wkthmltox Ubuntu 18
|
- name: download wkthmltox Ubuntu 18
|
||||||
get_url:
|
get_url:
|
||||||
|
@ -40,8 +40,8 @@
|
|||||||
- name: setup bench and dev environment
|
- name: setup bench and dev environment
|
||||||
hosts: localhost
|
hosts: localhost
|
||||||
vars:
|
vars:
|
||||||
bench_repo_path: "/home/{{ frappe_user }}/.bench"
|
bench_repo_path: "{{ user_directory }}/.bench"
|
||||||
bench_path: "/home/{{ frappe_user }}/{{ bench_name }}"
|
bench_path: "{{ user_directory }}/{{ bench_name }}"
|
||||||
roles:
|
roles:
|
||||||
# setup frappe-bench
|
# setup frappe-bench
|
||||||
- { role: bench, tags: "bench", when: not run_travis and not without_bench_setup }
|
- { role: bench, tags: "bench", when: not run_travis and not without_bench_setup }
|
||||||
|
@ -4,11 +4,8 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import semantic_version
|
import semantic_version
|
||||||
import git
|
import git
|
||||||
import requests
|
|
||||||
import getpass
|
import getpass
|
||||||
import re
|
import re
|
||||||
from requests.auth import HTTPBasicAuth
|
|
||||||
import requests.exceptions
|
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from .config.common_site_config import get_config
|
from .config.common_site_config import get_config
|
||||||
import click
|
import click
|
||||||
@ -47,6 +44,9 @@ def release(bench_path, app, bump_type, from_branch, to_branch,
|
|||||||
repo_name=repo_name, remote=remote, frontport=frontport)
|
repo_name=repo_name, remote=remote, frontport=frontport)
|
||||||
|
|
||||||
def validate(bench_path, config):
|
def validate(bench_path, config):
|
||||||
|
import requests
|
||||||
|
from requests.auth import HTTPBasicAuth
|
||||||
|
|
||||||
global github_username, github_password
|
global github_username, github_password
|
||||||
|
|
||||||
github_username = config.get('github_username')
|
github_username = config.get('github_username')
|
||||||
@ -306,6 +306,9 @@ def push_release(repo_path, from_branch, to_branch, remote='upstream'):
|
|||||||
|
|
||||||
def create_github_release(repo_path, tag_name, message, remote='upstream', owner='frappe', repo_name=None,
|
def create_github_release(repo_path, tag_name, message, remote='upstream', owner='frappe', repo_name=None,
|
||||||
gh_username=None, gh_password=None, prerelease=False):
|
gh_username=None, gh_password=None, prerelease=False):
|
||||||
|
import requests
|
||||||
|
import requests.exceptions
|
||||||
|
from requests.auth import HTTPBasicAuth
|
||||||
|
|
||||||
print('creating release on github')
|
print('creating release on github')
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import git
|
|||||||
|
|
||||||
# imports - module imports
|
# imports - module imports
|
||||||
import bench
|
import bench
|
||||||
|
import bench.cli
|
||||||
import bench.utils
|
import bench.utils
|
||||||
from bench.release import get_bumped_version
|
from bench.release import get_bumped_version
|
||||||
from bench.tests.test_base import FRAPPE_BRANCH, TestBenchBase
|
from bench.tests.test_base import FRAPPE_BRANCH, TestBenchBase
|
||||||
@ -27,6 +28,10 @@ class TestBenchInit(TestBenchBase):
|
|||||||
self.assertEqual( get_bumped_version('11.0.5-beta.22', 'prerelease'), '11.0.5-beta.23' )
|
self.assertEqual( get_bumped_version('11.0.5-beta.22', 'prerelease'), '11.0.5-beta.23' )
|
||||||
|
|
||||||
|
|
||||||
|
def test_utils(self):
|
||||||
|
self.assertEqual(subprocess.call("bench"), 0)
|
||||||
|
|
||||||
|
|
||||||
def test_init(self, bench_name="test-bench", **kwargs):
|
def test_init(self, bench_name="test-bench", **kwargs):
|
||||||
self.init_bench(bench_name, **kwargs)
|
self.init_bench(bench_name, **kwargs)
|
||||||
self.assert_folders(bench_name)
|
self.assert_folders(bench_name)
|
||||||
|
@ -2,18 +2,17 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# imports - standard imports
|
# imports - standard imports
|
||||||
|
import compileall
|
||||||
import errno
|
import errno
|
||||||
import glob
|
import glob
|
||||||
import grp
|
import grp
|
||||||
import itertools
|
import itertools
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import multiprocessing
|
|
||||||
import os
|
import os
|
||||||
import pwd
|
import pwd
|
||||||
import re
|
import re
|
||||||
import select
|
import select
|
||||||
import shutil
|
|
||||||
import site
|
import site
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
@ -22,11 +21,7 @@ from distutils.spawn import find_executable
|
|||||||
|
|
||||||
# imports - third party imports
|
# imports - third party imports
|
||||||
import click
|
import click
|
||||||
from crontab import CronTab
|
|
||||||
import requests
|
|
||||||
from semantic_version import Version
|
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
from six.moves.urllib.parse import urlparse
|
|
||||||
|
|
||||||
# imports - module imports
|
# imports - module imports
|
||||||
import bench
|
import bench
|
||||||
@ -92,6 +87,12 @@ def safe_decode(string, encoding = 'utf-8'):
|
|||||||
|
|
||||||
|
|
||||||
def check_latest_version():
|
def check_latest_version():
|
||||||
|
if bench.VERSION.endswith("dev"):
|
||||||
|
return
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from semantic_version import Version
|
||||||
|
|
||||||
try:
|
try:
|
||||||
pypi_request = requests.get("https://pypi.org/pypi/frappe-bench/json")
|
pypi_request = requests.get("https://pypi.org/pypi/frappe-bench/json")
|
||||||
except Exception:
|
except Exception:
|
||||||
@ -162,9 +163,6 @@ def init(path, apps_path=None, no_procfile=False, no_backups=False,
|
|||||||
if apps_path:
|
if apps_path:
|
||||||
install_apps_from_path(apps_path, bench_path=path)
|
install_apps_from_path(apps_path, bench_path=path)
|
||||||
|
|
||||||
|
|
||||||
bench.set_frappe_version(bench_path=path)
|
|
||||||
if bench.FRAPPE_VERSION > 5:
|
|
||||||
if not skip_assets:
|
if not skip_assets:
|
||||||
update_node_packages(bench_path=path)
|
update_node_packages(bench_path=path)
|
||||||
|
|
||||||
@ -183,8 +181,8 @@ def init(path, apps_path=None, no_procfile=False, no_backups=False,
|
|||||||
copy_patches_txt(path)
|
copy_patches_txt(path)
|
||||||
|
|
||||||
|
|
||||||
def update(pull=False, apps=None, patch=False, build=False, requirements=False, backup=True, force=False, reset=False,
|
def update(pull=False, apps=None, patch=False, build=False, requirements=False, backup=True, compile=True,
|
||||||
restart_supervisor=False, restart_systemd=False):
|
force=False, reset=False, restart_supervisor=False, restart_systemd=False):
|
||||||
"""command: bench update"""
|
"""command: bench update"""
|
||||||
from bench import patches
|
from bench import patches
|
||||||
from bench.app import is_version_upgrade, pull_apps, validate_branch
|
from bench.app import is_version_upgrade, pull_apps, validate_branch
|
||||||
@ -218,7 +216,6 @@ def update(pull=False, apps=None, patch=False, build=False, requirements=False,
|
|||||||
|
|
||||||
if version_upgrade[0] or (not version_upgrade[0] and force):
|
if version_upgrade[0] or (not version_upgrade[0] and force):
|
||||||
validate_upgrade(version_upgrade[1], version_upgrade[2], bench_path=bench_path)
|
validate_upgrade(version_upgrade[1], version_upgrade[2], bench_path=bench_path)
|
||||||
|
|
||||||
conf.update({ "maintenance_mode": 1, "pause_scheduler": 1 })
|
conf.update({ "maintenance_mode": 1, "pause_scheduler": 1 })
|
||||||
update_config(conf, bench_path=bench_path)
|
update_config(conf, bench_path=bench_path)
|
||||||
|
|
||||||
@ -246,6 +243,10 @@ def update(pull=False, apps=None, patch=False, build=False, requirements=False,
|
|||||||
if version_upgrade[0] or (not version_upgrade[0] and force):
|
if version_upgrade[0] or (not version_upgrade[0] and force):
|
||||||
post_upgrade(version_upgrade[1], version_upgrade[2], bench_path=bench_path)
|
post_upgrade(version_upgrade[1], version_upgrade[2], bench_path=bench_path)
|
||||||
|
|
||||||
|
if pull and compile:
|
||||||
|
print("Compiling Python files...")
|
||||||
|
compileall.compile_dir('../apps', quiet=1, rx=re.compile('.*node_modules.*'))
|
||||||
|
|
||||||
if restart_supervisor or conf.get('restart_supervisor_on_update'):
|
if restart_supervisor or conf.get('restart_supervisor_on_update'):
|
||||||
restart_supervisor_processes(bench_path=bench_path)
|
restart_supervisor_processes(bench_path=bench_path)
|
||||||
|
|
||||||
@ -259,6 +260,8 @@ def update(pull=False, apps=None, patch=False, build=False, requirements=False,
|
|||||||
|
|
||||||
|
|
||||||
def copy_patches_txt(bench_path):
|
def copy_patches_txt(bench_path):
|
||||||
|
import shutil
|
||||||
|
|
||||||
shutil.copy(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'patches', 'patches.txt'),
|
shutil.copy(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'patches', 'patches.txt'),
|
||||||
os.path.join(bench_path, 'patches.txt'))
|
os.path.join(bench_path, 'patches.txt'))
|
||||||
|
|
||||||
@ -352,23 +355,13 @@ def setup_socketio(bench_path='.'):
|
|||||||
|
|
||||||
|
|
||||||
def patch_sites(bench_path='.'):
|
def patch_sites(bench_path='.'):
|
||||||
bench.set_frappe_version(bench_path=bench_path)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if bench.FRAPPE_VERSION == 4:
|
|
||||||
exec_cmd("{frappe} --latest all".format(frappe=get_frappe(bench_path=bench_path)), cwd=os.path.join(bench_path, 'sites'))
|
|
||||||
else:
|
|
||||||
run_frappe_cmd('--site', 'all', 'migrate', bench_path=bench_path)
|
run_frappe_cmd('--site', 'all', 'migrate', bench_path=bench_path)
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
raise PatchError
|
raise PatchError
|
||||||
|
|
||||||
|
|
||||||
def build_assets(bench_path='.', app=None):
|
def build_assets(bench_path='.', app=None):
|
||||||
bench.set_frappe_version(bench_path=bench_path)
|
|
||||||
|
|
||||||
if bench.FRAPPE_VERSION == 4:
|
|
||||||
exec_cmd("{frappe} --build".format(frappe=get_frappe(bench_path=bench_path)), cwd=os.path.join(bench_path, 'sites'))
|
|
||||||
else:
|
|
||||||
command = 'bench build'
|
command = 'bench build'
|
||||||
if app:
|
if app:
|
||||||
command += ' --app {}'.format(app)
|
command += ' --app {}'.format(app)
|
||||||
@ -382,20 +375,15 @@ def get_sites(bench_path='.'):
|
|||||||
|
|
||||||
|
|
||||||
def setup_backups(bench_path='.'):
|
def setup_backups(bench_path='.'):
|
||||||
|
from crontab import CronTab
|
||||||
from bench.config.common_site_config import get_config
|
from bench.config.common_site_config import get_config
|
||||||
logger.log('setting up backups')
|
logger.log('setting up backups')
|
||||||
|
|
||||||
bench_dir = os.path.abspath(bench_path)
|
bench_dir = os.path.abspath(bench_path)
|
||||||
user = get_config(bench_path=bench_dir).get('frappe_user')
|
user = get_config(bench_path=bench_dir).get('frappe_user')
|
||||||
logfile = os.path.join(bench_dir, 'logs', 'backup.log')
|
logfile = os.path.join(bench_dir, 'logs', 'backup.log')
|
||||||
bench.set_frappe_version(bench_path=bench_path)
|
|
||||||
system_crontab = CronTab(user=user)
|
system_crontab = CronTab(user=user)
|
||||||
|
|
||||||
if bench.FRAPPE_VERSION == 4:
|
|
||||||
backup_command = "cd {sites_dir} && {frappe} --backup all".format(frappe=get_frappe(bench_path=bench_path),)
|
|
||||||
else:
|
|
||||||
backup_command = "cd {bench_dir} && {bench} --verbose --site all backup".format(bench_dir=bench_dir, bench=sys.argv[0])
|
backup_command = "cd {bench_dir} && {bench} --verbose --site all backup".format(bench_dir=bench_dir, bench=sys.argv[0])
|
||||||
|
|
||||||
job_command = "{backup_command} >> {logfile} 2>&1".format(backup_command=backup_command, logfile=logfile)
|
job_command = "{backup_command} >> {logfile} 2>&1".format(backup_command=backup_command, logfile=logfile)
|
||||||
|
|
||||||
if job_command not in str(system_crontab):
|
if job_command not in str(system_crontab):
|
||||||
@ -418,7 +406,7 @@ def setup_sudoers(user):
|
|||||||
if set_permissions:
|
if set_permissions:
|
||||||
os.chmod('/etc/sudoers', 0o440)
|
os.chmod('/etc/sudoers', 0o440)
|
||||||
|
|
||||||
template = bench.config.env.get_template('frappe_sudoers')
|
template = bench.config.env().get_template('frappe_sudoers')
|
||||||
frappe_sudoers = template.render(**{
|
frappe_sudoers = template.render(**{
|
||||||
'user': user,
|
'user': user,
|
||||||
'service': find_executable('service'),
|
'service': find_executable('service'),
|
||||||
@ -655,12 +643,6 @@ def update_npm_packages(bench_path='.'):
|
|||||||
|
|
||||||
|
|
||||||
def backup_site(site, bench_path='.'):
|
def backup_site(site, bench_path='.'):
|
||||||
bench.set_frappe_version(bench_path=bench_path)
|
|
||||||
|
|
||||||
if bench.FRAPPE_VERSION == 4:
|
|
||||||
exec_cmd("{frappe} --backup {site}".format(frappe=get_frappe(bench_path=bench_path), site=site),
|
|
||||||
cwd=os.path.join(bench_path, 'sites'))
|
|
||||||
else:
|
|
||||||
run_frappe_cmd('--site', site, 'backup', bench_path=bench_path)
|
run_frappe_cmd('--site', site, 'backup', bench_path=bench_path)
|
||||||
|
|
||||||
|
|
||||||
@ -747,11 +729,6 @@ def fix_prod_setup_perms(bench_path='.', frappe_user=None):
|
|||||||
os.chown(path, uid, gid)
|
os.chown(path, uid, gid)
|
||||||
|
|
||||||
|
|
||||||
def get_current_frappe_version(bench_path='.'):
|
|
||||||
from .app import get_current_frappe_version as fv
|
|
||||||
return fv(bench_path=bench_path)
|
|
||||||
|
|
||||||
|
|
||||||
def run_frappe_cmd(*args, **kwargs):
|
def run_frappe_cmd(*args, **kwargs):
|
||||||
from .cli import from_command_line
|
from .cli import from_command_line
|
||||||
|
|
||||||
@ -811,6 +788,8 @@ sudo supervisorctl reload
|
|||||||
|
|
||||||
|
|
||||||
def update_translations_p(args):
|
def update_translations_p(args):
|
||||||
|
import requests
|
||||||
|
|
||||||
try:
|
try:
|
||||||
update_translations(*args)
|
update_translations(*args)
|
||||||
except requests.exceptions.HTTPError:
|
except requests.exceptions.HTTPError:
|
||||||
@ -818,6 +797,8 @@ def update_translations_p(args):
|
|||||||
|
|
||||||
|
|
||||||
def download_translations_p():
|
def download_translations_p():
|
||||||
|
import multiprocessing
|
||||||
|
|
||||||
pool = multiprocessing.Pool(multiprocessing.cpu_count())
|
pool = multiprocessing.Pool(multiprocessing.cpu_count())
|
||||||
|
|
||||||
langs = get_langs()
|
langs = get_langs()
|
||||||
@ -842,6 +823,8 @@ def get_langs():
|
|||||||
|
|
||||||
|
|
||||||
def update_translations(app, lang):
|
def update_translations(app, lang):
|
||||||
|
import requests
|
||||||
|
|
||||||
translations_dir = os.path.join('apps', app, app, 'translations')
|
translations_dir = os.path.join('apps', app, app, 'translations')
|
||||||
csv_file = os.path.join(translations_dir, lang + '.csv')
|
csv_file = os.path.join(translations_dir, lang + '.csv')
|
||||||
url = "https://translate.erpnext.com/files/{}-{}.csv".format(app, lang)
|
url = "https://translate.erpnext.com/files/{}-{}.csv".format(app, lang)
|
||||||
@ -891,6 +874,8 @@ def get_bench_name(bench_path):
|
|||||||
|
|
||||||
|
|
||||||
def setup_fonts():
|
def setup_fonts():
|
||||||
|
import shutil
|
||||||
|
|
||||||
fonts_path = os.path.join('/tmp', 'fonts')
|
fonts_path = os.path.join('/tmp', 'fonts')
|
||||||
|
|
||||||
if os.path.exists('/etc/fonts_backup'):
|
if os.path.exists('/etc/fonts_backup'):
|
||||||
@ -963,6 +948,8 @@ def find_benches(directory=None):
|
|||||||
|
|
||||||
|
|
||||||
def migrate_env(python, backup=False):
|
def migrate_env(python, backup=False):
|
||||||
|
import shutil
|
||||||
|
from six.moves.urllib.parse import urlparse
|
||||||
from bench.config.common_site_config import get_config
|
from bench.config.common_site_config import get_config
|
||||||
from bench.app import get_apps
|
from bench.app import get_apps
|
||||||
|
|
||||||
|
@ -34,6 +34,8 @@ If you are on a fresh server and logged in as root, at first create a dedicated
|
|||||||
|
|
||||||
*(it is very common to use "frappe" as frappe-username, but this comes with the security flaw of ["frappe" ranking very high](https://www.reddit.com/r/dataisbeautiful/comments/b3sirt/i_deployed_over_a_dozen_cyber_honeypots_all_over/?st=JTJ0SC0Q&sh=76e05240) in as a username challenged in hacking attempts. So, for production sites it is highly recommended to use a custom username harder to guess)*
|
*(it is very common to use "frappe" as frappe-username, but this comes with the security flaw of ["frappe" ranking very high](https://www.reddit.com/r/dataisbeautiful/comments/b3sirt/i_deployed_over_a_dozen_cyber_honeypots_all_over/?st=JTJ0SC0Q&sh=76e05240) in as a username challenged in hacking attempts. So, for production sites it is highly recommended to use a custom username harder to guess)*
|
||||||
|
|
||||||
|
*(you can specify the flag --home to specify a directory for your [frappe-user]. Bench will follow the home directory specified by the user's home directory e.g. /data/[frappe-user]/frappe-bench)*
|
||||||
|
|
||||||
Switch to `[frappe-user]` (using `su [frappe-user]`) and start the setup
|
Switch to `[frappe-user]` (using `su [frappe-user]`) and start the setup
|
||||||
|
|
||||||
wget https://raw.githubusercontent.com/frappe/bench/develop/install.py
|
wget https://raw.githubusercontent.com/frappe/bench/develop/install.py
|
||||||
@ -71,7 +73,7 @@ use --python flag to specify virtual environments python version, by default scr
|
|||||||
|
|
||||||
## How do I start ERPNext
|
## How do I start ERPNext
|
||||||
|
|
||||||
1. For development: Go to your bench folder (`frappe-bench` by default) and start the bench with `bench start`
|
1. For development: Go to your bench folder (`~[frappe-user]/frappe-bench` by default) and start the bench with `bench start`
|
||||||
2. For production: Your process will be setup and managed by `nginx` and `supervisor`. Checkout [Setup Production](https://frappe.io/docs/user/en/bench/guides/setup-production.html) for more information.
|
2. For production: Your process will be setup and managed by `nginx` and `supervisor`. Checkout [Setup Production](https://frappe.io/docs/user/en/bench/guides/setup-production.html) for more information.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
42
install.py
42
install.py
@ -157,13 +157,24 @@ def install_prerequisites():
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# until psycopg2-binary is available for aarch64 (Arm 64-bit), we'll need libpq and libssl dev packages to build psycopg2 from source
|
||||||
|
if platform.machine() == 'aarch64':
|
||||||
|
log("Installing libpq and libssl dev packages to build psycopg2 for aarch64...")
|
||||||
|
run_os_command({
|
||||||
|
'apt-get': ['sudo apt-get install -y libpq-dev libssl-dev'],
|
||||||
|
'yum': ['sudo yum install -y libpq-devel openssl-devel']
|
||||||
|
})
|
||||||
|
|
||||||
install_package('curl')
|
install_package('curl')
|
||||||
install_package('wget')
|
install_package('wget')
|
||||||
install_package('git')
|
install_package('git')
|
||||||
install_package('pip3', 'python3-pip')
|
install_package('pip3', 'python3-pip')
|
||||||
|
|
||||||
|
run_os_command({
|
||||||
|
'python3': "sudo -H python3 -m pip install --upgrade pip setuptools-rust"
|
||||||
|
})
|
||||||
success = run_os_command({
|
success = run_os_command({
|
||||||
'python3': "sudo -H python3 -m pip install --upgrade setuptools wheel cryptography ansible==2.8.5 pip"
|
'python3': "sudo -H python3 -m pip install --upgrade setuptools wheel cryptography ansible~=2.8.15"
|
||||||
})
|
})
|
||||||
|
|
||||||
if not (success or shutil.which('ansible')):
|
if not (success or shutil.which('ansible')):
|
||||||
@ -224,9 +235,10 @@ def install_bench(args):
|
|||||||
extra_vars = vars(args)
|
extra_vars = vars(args)
|
||||||
extra_vars.update(frappe_user=args.user)
|
extra_vars.update(frappe_user=args.user)
|
||||||
|
|
||||||
|
extra_vars.update(user_directory=get_user_home_directory(args.user))
|
||||||
|
|
||||||
if os.path.exists(tmp_bench_repo):
|
if os.path.exists(tmp_bench_repo):
|
||||||
repo_path = tmp_bench_repo
|
repo_path = tmp_bench_repo
|
||||||
|
|
||||||
else:
|
else:
|
||||||
repo_path = os.path.join(os.path.expanduser('~'), 'bench')
|
repo_path = os.path.join(os.path.expanduser('~'), 'bench')
|
||||||
|
|
||||||
@ -247,10 +259,9 @@ def install_bench(args):
|
|||||||
else:
|
else:
|
||||||
frappe_branch = "version-{0}".format(args.version)
|
frappe_branch = "version-{0}".format(args.version)
|
||||||
erpnext_branch = "version-{0}".format(args.version)
|
erpnext_branch = "version-{0}".format(args.version)
|
||||||
else:
|
# Allow override of frappe_branch and erpnext_branch, regardless of args.version (which always has a default set)
|
||||||
if args.frappe_branch:
|
if args.frappe_branch:
|
||||||
frappe_branch = args.frappe_branch
|
frappe_branch = args.frappe_branch
|
||||||
|
|
||||||
if args.erpnext_branch:
|
if args.erpnext_branch:
|
||||||
erpnext_branch = args.erpnext_branch
|
erpnext_branch = args.erpnext_branch
|
||||||
|
|
||||||
@ -261,6 +272,10 @@ def install_bench(args):
|
|||||||
extra_vars.update(bench_name=bench_name)
|
extra_vars.update(bench_name=bench_name)
|
||||||
|
|
||||||
# Will install ERPNext production setup by default
|
# Will install ERPNext production setup by default
|
||||||
|
if args.without_erpnext:
|
||||||
|
log("Initializing bench {bench_name}:\n\tFrappe Branch: {frappe_branch}\n\tERPNext will not be installed due to --without-erpnext".format(bench_name=bench_name, frappe_branch=frappe_branch))
|
||||||
|
else:
|
||||||
|
log("Initializing bench {bench_name}:\n\tFrappe Branch: {frappe_branch}\n\tERPNext Branch: {erpnext_branch}".format(bench_name=bench_name, frappe_branch=frappe_branch, erpnext_branch=erpnext_branch))
|
||||||
run_playbook('site.yml', sudo=True, extra_vars=extra_vars)
|
run_playbook('site.yml', sudo=True, extra_vars=extra_vars)
|
||||||
|
|
||||||
if os.path.exists(tmp_bench_repo):
|
if os.path.exists(tmp_bench_repo):
|
||||||
@ -273,11 +288,15 @@ def clone_bench_repo(args):
|
|||||||
repo_url = args.repo_url or 'https://github.com/frappe/bench'
|
repo_url = args.repo_url or 'https://github.com/frappe/bench'
|
||||||
|
|
||||||
if os.path.exists(tmp_bench_repo):
|
if os.path.exists(tmp_bench_repo):
|
||||||
|
log('Not cloning already existing Bench repository at {tmp_bench_repo}'.format(tmp_bench_repo=tmp_bench_repo))
|
||||||
return 0
|
return 0
|
||||||
elif args.without_bench_setup:
|
elif args.without_bench_setup:
|
||||||
clone_path = os.path.join(os.path.expanduser('~'), 'bench')
|
clone_path = os.path.join(os.path.expanduser('~'), 'bench')
|
||||||
|
log('--without-bench-setup specified, clone path is: {clone_path}'.format(clone_path=clone_path))
|
||||||
else:
|
else:
|
||||||
clone_path = tmp_bench_repo
|
clone_path = tmp_bench_repo
|
||||||
|
# Not logging repo_url to avoid accidental credential leak in case credential is embedded in URL
|
||||||
|
log('Cloning bench repository branch {branch} into {clone_path}'.format(branch=branch, clone_path=clone_path))
|
||||||
|
|
||||||
success = run_os_command(
|
success = run_os_command(
|
||||||
{'git': 'git clone --quiet {repo_url} {bench_repo} --depth 1 --branch {branch}'.format(
|
{'git': 'git clone --quiet {repo_url} {bench_repo} --depth 1 --branch {branch}'.format(
|
||||||
@ -327,8 +346,8 @@ def get_passwords(args):
|
|||||||
mysql_root_password = ''
|
mysql_root_password = ''
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# admin password
|
# admin password, only needed if we're also creating a site
|
||||||
if not admin_password:
|
if not admin_password and not args.without_site:
|
||||||
admin_password = getpass.unix_getpass(prompt='Please enter the default Administrator user password: ')
|
admin_password = getpass.unix_getpass(prompt='Please enter the default Administrator user password: ')
|
||||||
conf_admin_passswd = getpass.unix_getpass(prompt='Re-enter Administrator password: ')
|
conf_admin_passswd = getpass.unix_getpass(prompt='Re-enter Administrator password: ')
|
||||||
|
|
||||||
@ -336,6 +355,8 @@ def get_passwords(args):
|
|||||||
passwords_didnt_match("Administrator")
|
passwords_didnt_match("Administrator")
|
||||||
admin_password = ''
|
admin_password = ''
|
||||||
continue
|
continue
|
||||||
|
elif args.without_site:
|
||||||
|
log("Not creating a new site due to --without-site")
|
||||||
|
|
||||||
pass_set = False
|
pass_set = False
|
||||||
else:
|
else:
|
||||||
@ -366,6 +387,11 @@ def get_extra_vars_json(extra_args):
|
|||||||
|
|
||||||
return ('@' + json_path)
|
return ('@' + json_path)
|
||||||
|
|
||||||
|
def get_user_home_directory(user):
|
||||||
|
# Return home directory /home/USERNAME or anything else defined as home directory in
|
||||||
|
# passwd for user.
|
||||||
|
return os.path.expanduser('~'+user)
|
||||||
|
|
||||||
|
|
||||||
def run_playbook(playbook_name, sudo=False, extra_vars=None):
|
def run_playbook(playbook_name, sudo=False, extra_vars=None):
|
||||||
args = ['ansible-playbook', '-c', 'local', playbook_name , '-vvvv']
|
args = ['ansible-playbook', '-c', 'local', playbook_name , '-vvvv']
|
||||||
@ -405,8 +431,8 @@ def parse_commandline_args():
|
|||||||
|
|
||||||
args_group.add_argument('--develop', dest='develop', action='store_true', default=False, help='Install developer setup')
|
args_group.add_argument('--develop', dest='develop', action='store_true', default=False, help='Install developer setup')
|
||||||
args_group.add_argument('--production', dest='production', action='store_true', default=False, help='Setup Production environment for bench')
|
args_group.add_argument('--production', dest='production', action='store_true', default=False, help='Setup Production environment for bench')
|
||||||
parser.add_argument('--site', dest='site', action='store', default='site1.local', help='Specifiy name for your first ERPNext site')
|
parser.add_argument('--site', dest='site', action='store', default='site1.local', help='Specify name for your first ERPNext site')
|
||||||
parser.add_argument('--without-site', dest='without_site', action='store_true', default=False)
|
parser.add_argument('--without-site', dest='without_site', action='store_true', default=False, help='Do not create a new site')
|
||||||
parser.add_argument('--verbose', dest='verbose', action='store_true', default=False, help='Run the script in verbose mode')
|
parser.add_argument('--verbose', dest='verbose', action='store_true', default=False, help='Run the script in verbose mode')
|
||||||
parser.add_argument('--user', dest='user', help='Install frappe-bench for this user')
|
parser.add_argument('--user', dest='user', help='Install frappe-bench for this user')
|
||||||
parser.add_argument('--bench-branch', dest='bench_branch', help='Clone a particular branch of bench repository')
|
parser.add_argument('--bench-branch', dest='bench_branch', help='Clone a particular branch of bench repository')
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
Click==7.0
|
Click==7.0
|
||||||
GitPython==2.1.15
|
GitPython==2.1.15
|
||||||
honcho==1.0.1
|
honcho==1.0.1
|
||||||
Jinja2==2.10.3
|
Jinja2==2.11.3
|
||||||
python-crontab==2.4.0
|
python-crontab==2.4.0
|
||||||
requests==2.22.0
|
requests==2.22.0
|
||||||
semantic-version==2.8.2
|
semantic-version==2.8.2
|
||||||
|
Loading…
Reference in New Issue
Block a user