2
0
mirror of https://github.com/frappe/bench.git synced 2025-01-23 15:08:24 +00:00

[enhancement] multi-bench setup and test cases for bench with [travis]

This commit is contained in:
Anand Doshi 2016-02-25 17:41:08 +05:30
parent 2a4665ca37
commit 6797768572
11 changed files with 257 additions and 93 deletions

16
.travis.yml Normal file
View File

@ -0,0 +1,16 @@
language: python
python:
- "2.7"
install:
- sudo apt-get purge -y mysql-common
- sudo bash $TRAVIS_BUILD_DIR/install_scripts/setup_frappe.sh --skip-install-bench --mysql-root-password travis
- mkdir -p ~/bench-repo
- cp -r $TRAVIS_BUILD_DIR/* ~/bench-repo/
script:
- cd ~
- sudo pip install --upgrade pip
- sudo pip install -e bench-repo
- sudo python -m unittest bench.tests.test_setup_production

View File

@ -18,7 +18,7 @@ from .utils import (build_assets, patch_sites, exec_cmd, update_bench, get_env_c
from .app import get_app as _get_app
from .app import new_app as _new_app
from .app import pull_all_apps, get_apps, get_current_frappe_version, is_version_upgrade, switch_to_v4, switch_to_v5, switch_to_master, switch_to_develop
from .config import generate_nginx_config, generate_supervisor_config, generate_redis_cache_config, generate_redis_async_broker_config
from .config import generate_nginx_config, generate_supervisor_config, generate_redis_cache_config, generate_redis_async_broker_config, generate_redis_celery_broker_config
from .production_setup import setup_production as _setup_production
from .migrate_to_v5 import migrate_to_v5
import os
@ -74,7 +74,7 @@ def check_uid():
def change_uid():
if is_root() and not cmd_requires_root():
frappe_user = get_config().get('frappe_user')
frappe_user = get_config(".").get('frappe_user')
if frappe_user:
drop_privileges(uid_name=frappe_user, gid_name=frappe_user)
os.environ['HOME'] = pwd.getpwnam(frappe_user).pw_dir
@ -206,7 +206,7 @@ def _update(pull=False, patch=False, build=False, bench=False, auto=False, resta
if not (pull or patch or build or bench or requirements):
pull, patch, build, bench, requirements = True, True, True, True, True
conf = get_config()
conf = get_config(".")
version_upgrade = is_version_upgrade()
@ -449,6 +449,11 @@ def setup_redis_async_broker():
"generate config for redis async broker"
generate_redis_async_broker_config()
@click.command('redis-celery-broker')
def setup_redis_celery_broker():
"generate config for redis celery broker"
generate_redis_celery_broker_config()
@click.command('production')
@click.argument('user')
def setup_production(user):
@ -496,6 +501,7 @@ setup.add_command(setup_sudoers)
setup.add_command(setup_supervisor)
setup.add_command(setup_redis_cache)
setup.add_command(setup_redis_async_broker)
setup.add_command(setup_redis_celery_broker)
setup.add_command(setup_auto_update)
setup.add_command(setup_dnsmasq)
setup.add_command(setup_backups)

View File

@ -6,7 +6,7 @@ import shutil
import socket
from distutils.spawn import find_executable
from jinja2 import Environment, PackageLoader
from .utils import get_sites, get_config, update_config, get_redis_version
from .utils import get_sites, get_config, update_config, get_redis_version, update_common_site_config
env = Environment(loader=PackageLoader('bench', 'templates'), trim_blocks=True)
@ -30,6 +30,7 @@ def generate_supervisor_config(bench='.', user=None):
sites = get_sites(bench=bench)
if not user:
user = getpass.getuser()
config = get_config(bench=bench)
config = template.render(**{
@ -41,9 +42,11 @@ def generate_supervisor_config(bench='.', user=None):
"node": find_executable('node') or find_executable('nodejs'),
"redis_cache_config": os.path.join(bench_dir, 'config', 'redis_cache.conf'),
"redis_async_broker_config": os.path.join(bench_dir, 'config', 'redis_async_broker.conf'),
"redis_celery_broker_config": os.path.join(bench_dir, 'config', 'redis_celery_broker.conf'),
"frappe_version": get_current_frappe_version(),
"webserver_port": config.get('webserver_port'),
"n_workers": config.get('max_workers')
"webserver_port": config.get('webserver_port', 8000),
"n_workers": config.get('max_workers', 2),
"bench_name": os.path.basename(os.path.abspath(bench))
})
write_config_file(bench, 'supervisor.conf', config)
update_config({'restart_supervisor_on_update': True})
@ -55,26 +58,23 @@ def get_site_config(site, bench='.'):
def generate_common_site_config(bench='.'):
'''Generates the default common_site_config.json while a new bench is created'''
config = get_config(bench=bench)
common_site_config = {}
celery_broker_port = config.get('redis_celery_broker_port', '11311')
celery_broker = 'redis://localhost:{0}'.format(celery_broker_port)
for bench_config_field, site_config_field in (
("redis_celery_broker_port", "celery_broker"),
("redis_async_broker_port", "async_redis_server"),
("redis_cache_port", "cache_redis_server")
):
async_redis_server_port = config.get('redis_async_broker_port', '12311')
async_redis_server = 'redis://localhost:{0}'.format(async_redis_server_port)
port = config.get(bench_config_field)
if config.get(bench_config_field):
redis_url = "redis://localhost:{0}".format(port)
common_site_config[site_config_field] = redis_url
cache_redis_server_port = config.get('redis_cache_port', '13311')
cache_redis_server = 'redis://localhost:{0}'.format(cache_redis_server_port)
# TODO Optionally we need to add the host or domain name in case dns_multitenant is false
default_common_site_config = {
"celery_broker" : celery_broker,
"async_redis_server": async_redis_server,
"cache_redis_server": cache_redis_server
}
#TODO Optionally we need to add the host or domain name in case dns_multitenant is false
with open(os.path.join(bench, 'sites', 'common_site_config.json'), 'wb') as f:
json.dump(default_common_site_config, f, indent=1, sort_keys=True)
if common_site_config:
update_common_site_config(common_site_config, bench=bench)
def get_sites_with_config(bench='.'):
sites = get_sites(bench=bench)
@ -111,7 +111,10 @@ def generate_nginx_config(bench='.'):
"http_timeout": config.get("http_timeout", 120),
"default_site": default_site,
"dns_multitenant": config.get('dns_multitenant'),
"sites": sites
"sites": sites,
"webserver_port": config.get('webserver_port', 8000),
"socketio_port": config.get('socketio_port', 3000),
"bench_name": os.path.basename(os.path.abspath(bench))
})
write_config_file(bench, 'nginx.conf', config)

View File

@ -55,16 +55,21 @@ def setup_production(user, bench='.'):
fix_prod_setup_perms(bench, frappe_user=user)
remove_default_nginx_configs()
bench_name = os.path.basename(os.path.abspath(bench))
nginx_conf = '/etc/nginx/conf.d/{bench_name}.conf'.format(bench_name=bench_name)
if is_centos7():
supervisor_conf_filename = 'frappe.ini'
supervisor_conf_extn = "ini"
copy_default_nginx_config()
else:
supervisor_conf_filename = 'frappe.conf'
supervisor_conf_extn = "conf"
supervisor_conf = os.path.join(get_supervisor_confdir(), '{bench_name}.{extn}'.format(
bench_name=bench_name, extn=supervisor_conf_extn))
links = (
(os.path.abspath(os.path.join(bench, 'config', 'nginx.conf')), '/etc/nginx/conf.d/frappe.conf'),
(os.path.abspath(os.path.join(bench, 'config', 'supervisor.conf')), os.path.join(get_supervisor_confdir(), supervisor_conf_filename)),
(os.path.abspath(os.path.join(bench, 'config', 'nginx.conf')), nginx_conf),
(os.path.abspath(os.path.join(bench, 'config', 'supervisor.conf')), supervisor_conf),
)
for src, dest in links:
@ -74,4 +79,5 @@ def setup_production(user, bench='.'):
exec_cmd('supervisorctl reload')
if os.environ.get('NO_SERVICE_RESTART'):
return
restart_service('nginx')

View File

@ -1,12 +1,9 @@
server_names_hash_bucket_size 64;
upstream frappe {
server 127.0.0.1:8000 fail_timeout=0;
upstream {{ bench_name }}-frappe {
server 127.0.0.1:{{ webserver_port }} fail_timeout=0;
}
upstream socketio-server {
server 127.0.0.1:3000 fail_timeout=0;
upstream {{ bench_name}}-socketio-server {
server 127.0.0.1:{{ socketio_port }} fail_timeout=0;
}
{% macro location_block(site, port=80, default=False, server_name=None, sites=None, dns_multitenant=False) -%}
@ -24,7 +21,7 @@ upstream socketio-server {
}
location /socket.io {
proxy_pass http://socketio-server;
proxy_pass http://{{ bench_name }}-socketio-server;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
@ -36,10 +33,10 @@ upstream socketio-server {
}
location / {
try_files /{{ "$host" if dns_multitenant else site.name }}/public/$uri @magic;
try_files /{{ "$host" if dns_multitenant else site.name }}/public/$uri @webserver;
}
location @magic {
location @webserver {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
{% if not dns_multitenant %}
@ -47,9 +44,9 @@ upstream socketio-server {
{% endif %}
proxy_set_header Host $host;
proxy_set_header X-Use-X-Accel-Redirect True;
proxy_read_timeout {{http_timeout}};
proxy_read_timeout {{ http_timeout }};
proxy_redirect off;
proxy_pass http://frappe;
proxy_pass http://{{ bench_name }}-frappe;
}
{%- endmacro %}

View File

@ -33,6 +33,8 @@ http {
#keepalive_timeout 0;
keepalive_timeout 65;
server_names_hash_bucket_size 64;
#gzip on;
index index.html index.htm;

View File

@ -2,8 +2,8 @@
; priority=1 --> Lower priorities indicate programs that start first and shut down last
; killasgroup=true --> send kill signal to child processes too
[program:frappe-web]
command={{ bench_dir }}/env/bin/gunicorn -b 127.0.0.1:{{webserver_port}} -w {{n_workers}} -t {{http_timeout}} frappe.app:application
[program:{{ bench_name }}-frappe-web]
command={{ bench_dir }}/env/bin/gunicorn -b 127.0.0.1:{{ webserver_port }} -w {{ n_workers }} -t {{ http_timeout }} frappe.app:application --preload
priority=4
autostart=true
autorestart=true
@ -12,7 +12,7 @@ stderr_logfile={{ bench_dir }}/logs/web.error.log
user={{ user }}
directory={{ sites_dir }}
[program:frappe-worker]
[program:{{ bench_name }}-frappe-worker]
command={{ bench_dir }}/env/bin/python -m frappe.celery_app worker -n jobs@%%h --soft-time-limit 360 --time-limit 390 --loglevel INFO -Ofair
priority=4
autostart=true
@ -24,7 +24,7 @@ stopwaitsecs=400
directory={{ sites_dir }}
killasgroup=true
[program:frappe-longjob-worker]
[program:{{ bench_name }}-frappe-longjob-worker]
command={{ bench_dir }}/env/bin/python -m frappe.celery_app worker -n longjobs@%%h --soft-time-limit 1500 --time-limit 1530 --loglevel INFO
priority=2
autostart=true
@ -36,7 +36,7 @@ stopwaitsecs=1540
directory={{ sites_dir }}
killasgroup=true
[program:frappe-async-worker]
[program:{{ bench_name }}-frappe-async-worker]
command={{ bench_dir }}/env/bin/python -m frappe.celery_app worker -n async@%%h --soft-time-limit 1500 --time-limit 1530 --loglevel INFO
priority=2
autostart=true
@ -48,7 +48,7 @@ stopwaitsecs=1540
directory={{ sites_dir }}
killasgroup=true
[program:frappe-workerbeat]
[program:{{ bench_name }}-frappe-workerbeat]
command={{ bench_dir }}/env/bin/python -m frappe.celery_app beat -s beat.schedule
priority=3
autostart=true
@ -58,9 +58,7 @@ stderr_logfile={{ bench_dir }}/logs/workerbeat.error.log
user={{ user }}
directory={{ sites_dir }}
{% if frappe_version > 4%}
[program:redis-cache]
[program:{{ bench_name }}-redis-cache]
command={{ redis_server }} {{ redis_cache_config }}
priority=1
autostart=true
@ -69,10 +67,19 @@ stdout_logfile={{ bench_dir }}/logs/redis-cache.log
stderr_logfile={{ bench_dir }}/logs/redis-cache.error.log
user={{ user }}
directory={{ sites_dir }}
{% endif %}
{% if frappe_version > 5%}
[program:redis-async-broker]
[program:{{ bench_name }}-redis-celery-broker]
command={{ redis_server }} {{ redis_celery_broker_config }}
priority=1
autostart=true
autorestart=true
stdout_logfile={{ bench_dir }}/logs/redis-celery-broker.log
stderr_logfile={{ bench_dir }}/logs/redis-celery-broker.error.log
user={{ user }}
directory={{ sites_dir }}
{% if frappe_version > 5 %}
[program:{{ bench_name }}-redis-async-broker]
command={{ redis_server }} {{ redis_async_broker_config }}
priority=1
autostart=true
@ -83,7 +90,7 @@ user={{ user }}
directory={{ sites_dir }}
{% if node %}
[program:node-socketio]
[program:{{ bench_name }}-node-socketio]
command={{ node }} {{ bench_dir }}/apps/frappe/socketio.js
priority=4
autostart=true
@ -96,5 +103,8 @@ directory={{ sites_dir }}
{% endif %}
[group:frappe]
programs=frappe-web,frappe-worker,frappe-workerbeat
[group:{{ bench_name }}-processes]
programs={{ bench_name }}-frappe-web,{{ bench_name }}-frappe-worker,{{ bench_name }}-frappe-longjob-worker,{{ bench_name }}-frappe-async-worker,{{ bench_name }}-frappe-workerbeat {%- if node -%} ,{{ bench_name }}-node-socketio {%- endif%}
[group:{{ bench_name }}-redis]
programs={{ bench_name }}-redis-cache,{{ bench_name }}-redis-celery-broker {%- if frappe_version > 5 -%} ,{{ bench_name }}-redis-async-broker {%- endif %}

View File

@ -5,7 +5,6 @@ import bench.utils
import json
import os
import shutil
import socket
class TestBenchInit(unittest.TestCase):
def setUp(self):
@ -19,9 +18,7 @@ class TestBenchInit(unittest.TestCase):
shutil.rmtree(bench_path)
def test_init(self, bench_name="test-bench"):
self.benches.append(bench_name)
bench.utils.init(bench_name)
self.init_bench(bench_name)
self.assert_folders(bench_name)
@ -34,25 +31,43 @@ class TestBenchInit(unittest.TestCase):
self.assert_socketio(bench_name)
def test_multiple_benches(self):
# 1st bench
self.test_init("test-bench-1")
test_bench_1_ports = {
self.assert_ports("test-bench-1", {
"webserver_port": 8000,
"socketio_port": 9000,
"redis_celery_broker_port": 11000,
"redis_async_broker_port": 12000,
"redis_cache_port": 13000
}
self.assert_ports("test-bench-1", test_bench_1_ports)
})
self.assert_common_site_config("test-bench-1", {
"celery_broker": "redis://localhost:11000",
"async_redis_server": "redis://localhost:12000",
"cache_redis_server": "redis://localhost:13000"
})
# 2nd bench
self.test_init("test-bench-2")
test_bench_2_ports = {
self.assert_ports("test-bench-2", {
"webserver_port": 8001,
"socketio_port": 9001,
"redis_celery_broker_port": 11001,
"redis_async_broker_port": 12001,
"redis_cache_port": 13001
}
self.assert_ports("test-bench-2", test_bench_2_ports)
})
self.assert_common_site_config("test-bench-2", {
"celery_broker": "redis://localhost:11001",
"async_redis_server": "redis://localhost:12001",
"cache_redis_server": "redis://localhost:13001"
})
def init_bench(self, bench_name):
self.benches.append(bench_name)
bench.utils.init(bench_name)
def assert_folders(self, bench_name):
for folder in bench.utils.folders_in_bench:
@ -70,13 +85,12 @@ class TestBenchInit(unittest.TestCase):
self.assert_exists(bench_name, "env", "lib", "python2.7", "site-packages", "pip")
def assert_bench_config(self, bench_name):
config_json = os.path.exists(os.path.join(bench_name, "config.json"))
self.assertTrue(config_json)
with open(config_json, "r") as f:
print f
config_dict = json.loads(f.read().decode("utf-8"))
for key, value in bench.utils.default_config.items():
self.assertEquals(config_dict.get(key), value)
config_json = os.path.join(bench_name, "config.json")
self.assertTrue(os.path.exists(config_json))
config = self.load_json(config_json)
for key, value in bench.utils.default_config.items():
self.assertEquals(config.get(key), value)
def assert_config(self, bench_name):
for config, search_key in (
@ -86,7 +100,7 @@ class TestBenchInit(unittest.TestCase):
self.assert_exists(bench_name, "config", config)
with open(os.path.join(self.bench, "config", config), "r") as f:
with open(os.path.join(bench_name, "config", config), "r") as f:
f = f.read().decode("utf-8")
self.assertTrue(search_key in f)
@ -95,16 +109,22 @@ class TestBenchInit(unittest.TestCase):
self.assert_exists(bench_name, "node_modules", "socket.io")
def assert_ports(self, bench_name, ports):
config_path = os.path.join(self.benches_path, bench_name, 'config', 'config.json')
config_path = os.path.join(bench_name, 'config.json')
config = self.load_json(config_path)
with open(config_path, "r") as f:
config_json = json.load(f)
for key, port in ports.items():
self.assertEquals(config.get(key), port)
for key, port in ports:
self.assertEqual(config_json.get(key), port)
def assert_common_site_config(self, bench_name, expected_config):
common_site_config_path = os.path.join(bench_name, 'sites', 'common_site_config.json')
config = self.load_json(common_site_config_path)
def assert_site_config(self, bench_name):
pass
for key, value in expected_config.items():
self.assertEquals(config.get(key), value)
def assert_exists(self, *args):
self.assertTrue(os.path.exists(os.path.join(*args)))
def load_json(self, path):
with open(path, "r") as f:
return json.loads(f.read().decode("utf-8"))

View File

@ -0,0 +1,95 @@
from __future__ import unicode_literals
from bench.tests.test_init import TestBenchInit
from bench.production_setup import setup_production
import bench.utils
import os
import getpass
import re
import unittest
class TestSetupProduction(TestBenchInit):
# setUp, tearDown and other tests are defiend in TestBenchInit
def test_setup_production(self):
self.test_multiple_benches()
user = getpass.getuser()
for bench_name in ("test-bench-1", "test-bench-2"):
setup_production(user, bench_name)
self.assert_nginx_config(bench_name)
self.assert_supervisor_config(bench_name)
self.assert_supervisor_process(bench_name)
self.assert_nginx_process()
def assert_nginx_config(self, bench_name):
conf_src = os.path.join(os.path.abspath(bench_name), 'config', 'nginx.conf')
conf_dest = "/etc/nginx/conf.d/{bench_name}.conf".format(bench_name=bench_name)
self.assertTrue(os.path.exists(conf_src))
self.assertTrue(os.path.exists(conf_dest))
# symlink matches
self.assertEquals(os.path.realpath(conf_dest), conf_src)
# file content
with open(conf_src, "r") as f:
f = f.read().decode("utf-8")
for key in (
"upstream { bench_name }-frappe",
"upstream { bench_name}-socketio-server"
):
self.assertTrue(key.format(bench_name) in f)
def assert_supervisor_config(self, bench_name):
conf_src = os.path.join(os.path.abspath(bench_name), 'config', 'supervisor.conf')
conf_dest = "/etc/supervisor.d/{bench_name}.conf".format(bench_name=bench_name)
self.assertTrue(os.path.exists(conf_src))
self.assertTrue(os.path.exists(conf_dest))
# symlink matches
self.assertEquals(os.path.realpath(conf_dest), conf_src)
# file content
with open(conf_src, "r") as f:
f = f.read().decode("utf-8")
for key in (
"program:{ bench_name }-frappe-web",
"program:{ bench_name }-frappe-worker",
"program:{ bench_name }-frappe-longjob-worker",
"program:{ bench_name }-frappe-async-worker",
"program:{ bench_name }-frappe-workerbeat",
"program:{ bench_name }-redis-cache",
"program:{ bench_name }-redis-celery-broker",
"program:{ bench_name }-redis-async-broker",
"program:{ bench_name }-node-socketio",
"group:{ bench_name }-processes",
"group:{ bench_name }-redis"
):
self.assertTrue(key.format(bench_name) in f)
def assert_supervisor_process(self, bench_name):
out = bench.utils.get_cmd_output("sudo supervisorctl status")
for key in (
"{bench_name}-process:{ bench_name }-frappe-web[\s]*RUNNING",
"{bench_name}-process:{ bench_name }-frappe-worker[\s]*RUNNING",
"{bench_name}-process:{ bench_name }-frappe-longjob-worker[\s]*RUNNING",
"{bench_name}-process:{ bench_name }-frappe-async-worker[\s]*RUNNING",
"{bench_name}-process:{ bench_name }-frappe-workerbeat[\s]*RUNNING",
"{bench_name}-process:{ bench_name }-node-socketio[\s]*RUNNING",
"{bench_name}-redis:{ bench_name }-redis-cache[\s]*RUNNING",
"{bench_name}-redis:{bench_name}-redis-celery-broker[\s]*RUNNING",
"{bench_name}-redis:{bench_name}-redis-async-broker[\s]*RUNNING",
):
self.assertTrue(re.match(key.format(bench_name), out))
def assert_nginx_process(self):
out = bench.utils.get_cmd_output("sudo nginx -t")
self.assertTrue("nginx: configuration file /etc/nginx/nginx.conf test is successful" in out)

View File

@ -105,8 +105,9 @@ def get_max_worker_count():
'''This function will return the maximum workers that can be started depending upon
number of cpu's present on the machine'''
n_cpus = multiprocessing.cpu_count()
return dict(max_workers=2 * n_cpus)
return {
"max_workers": (2 * n_cpus) + 1
}
def make_ports(benches_path="."):
default_ports = {
@ -449,11 +450,16 @@ def update_common_site_config(ddict, bench='.'):
update_json_file(os.path.join(bench, 'sites', 'common_site_config.json'), ddict)
def update_json_file(filename, ddict):
with open(filename, 'r') as f:
content = json.load(f)
if os.path.exists(filename):
with open(filename, 'r') as f:
content = json.load(f)
else:
content = {}
content.update(ddict)
with open(filename, 'w') as f:
content = json.dump(content, f, indent=1)
content = json.dump(content, f, indent=1, sort_keys=True)
def drop_privileges(uid_name='nobody', gid_name='nogroup'):
# from http://stackoverflow.com/a/2699996

View File

@ -16,7 +16,7 @@ get_passwd() {
}
set_opts () {
OPTS=`getopt -o v --long verbose,mysql-root-password:,frappe-user:,bench-branch:,setup-production,skip-setup-bench,help -n 'parse-options' -- "$@"`
OPTS=`getopt -o v --long verbose,mysql-root-password:,frappe-user:,bench-branch:,setup-production,skip-install-bench,skip-setup-bench,help -n 'parse-options' -- "$@"`
if [ $? != 0 ] ; then echo "Failed parsing options." >&2 ; exit 1 ; fi
@ -27,6 +27,7 @@ set_opts () {
FRAPPE_USER=false
BENCH_BRANCH="master"
SETUP_PROD=false
INSTALL_BENCH=true
SETUP_BENCH=true
if [ -f ~/frappe_passwords.sh ]; then
@ -50,6 +51,7 @@ set_opts () {
--setup-production ) SETUP_PROD=true; shift;;
--bench-branch ) BENCH_BRANCH="$2"; shift;;
--skip-setup-bench ) SETUP_BENCH=false; shift;;
--skip-install-bench ) INSTALL_BENCH=false; shift;;
-- ) shift; break ;;
* ) break ;;
esac
@ -202,14 +204,12 @@ install_packages() {
elif [ $OS == "debian" ] || [ $OS == "Ubuntu" ]; then
export DEBIAN_FRONTEND=noninteractive
setup_debconf
if [ $OS == "debian" ]; then
run_cmd bash -c "curl -sL https://deb.nodesource.com/setup_0.12 | bash -"
fi
run_cmd bash -c "curl -sL https://deb.nodesource.com/setup_0.12 | sudo bash -"
run_cmd sudo apt-get update
run_cmd sudo apt-get install -y python-dev python-setuptools build-essential python-mysqldb git \
ntp vim screen htop mariadb-server mariadb-common libmariadbclient-dev \
libxslt1.1 libxslt1-dev redis-server libssl-dev libcrypto++-dev postfix nginx \
supervisor python-pip fontconfig libxrender1 libxext6 xfonts-75dpi xfonts-base nodejs npm
supervisor python-pip fontconfig libxrender1 libxext6 xfonts-75dpi xfonts-base nodejs
if [ $OS_VER == "precise" ]; then
run_cmd sudo apt-get install -y libtiff4-dev libjpeg8-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.5-dev tk8.5-dev python-tk
@ -454,9 +454,12 @@ main() {
configure_mariadb
echo "Adding frappe user"
add_user
install_bench
if $SETUP_BENCH; then
setup_bench
if $INSTALL_BENCH; then
install_bench
if $SETUP_BENCH; then
setup_bench
fi
fi
echo