forked from frappe/erpnext
-
Notifications
You must be signed in to change notification settings - Fork 0
/
install_erpnext.py
333 lines (259 loc) · 9.85 KB
/
install_erpnext.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
#!/usr/bin/env python
from __future__ import unicode_literals
import os, sys
apache_user = None
is_redhat = is_debian = None
root_password = None
def install(install_path=None):
install_pre_requisites()
if not install_path:
install_path = os.getcwd()
install_erpnext(install_path)
post_install(install_path)
def install_pre_requisites():
global is_redhat, is_debian
is_redhat, is_debian = validate_install()
if is_redhat:
install_using_yum()
elif is_debian:
install_using_apt()
install_python_modules()
print "-"*80
print "Pre-requisites Installed"
print "-"*80
def validate_install():
import platform
# check os
operating_system = platform.system()
print "Operating System =", operating_system
if operating_system != "Linux":
raise Exception, "Sorry! This installer works only for Linux based Operating Systems"
# check python version
python_version = sys.version.split(" ")[0]
print "Python Version =", python_version
if not (python_version and int(python_version.split(".")[0])==2 and int(python_version.split(".")[1]) >= 6):
raise Exception, "Hey! ERPNext needs Python version to be 2.6+"
# check distribution
distribution = platform.linux_distribution()[0].lower().replace('"', '')
print "Distribution = ", distribution
is_redhat = distribution in ("redhat", "centos", "fedora")
is_debian = distribution in ("debian", "ubuntu", "elementary os")
if not (is_redhat or is_debian):
raise Exception, "Sorry! This installer works only with yum or apt-get package management"
return is_redhat, is_debian
def install_using_yum():
packages = "python python-setuptools MySQL-python httpd git memcached ntp vim-enhanced screen"
print "-"*80
print "Installing Packages: (This may take some time)"
print packages
print "-"*80
exec_in_shell("yum install -y %s" % packages)
if not exec_in_shell("which mysql"):
packages = "mysql mysql-server mysql-devel"
print "Installing Packages:", packages
exec_in_shell("yum install -y %s" % packages)
exec_in_shell("service mysqld restart")
# set a root password post install
global root_password
print "Please create a password for root user of MySQL"
root_password = (get_root_password() or "erpnext").strip()
exec_in_shell('mysqladmin -u root password "%s"' % (root_password,))
print "Root password set as", root_password
# install htop
if not exec_in_shell("which htop"):
try:
exec_in_shell("cd /tmp && rpm -i --force http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm && yum install -y htop")
except:
pass
update_config_for_redhat()
def update_config_for_redhat():
import re
global apache_user
apache_user = "apache"
# update memcache user
with open("/etc/sysconfig/memcached", "r") as original:
memcached_conf = original.read()
with open("/etc/sysconfig/memcached", "w") as modified:
modified.write(re.sub('USER.*', 'USER="%s"' % apache_user, memcached_conf))
# set to autostart on startup
for service in ("mysqld", "httpd", "memcached", "ntpd"):
exec_in_shell("chkconfig --level 2345 %s on" % service)
exec_in_shell("service %s restart" % service)
def install_using_apt():
packages = "python python-setuptools python-mysqldb apache2 git memcached ntp vim screen htop"
print "-"*80
print "Installing Packages: (This may take some time)"
print packages
print "-"*80
exec_in_shell("apt-get install -y %s" % packages)
if not exec_in_shell("which mysql"):
packages = "mysql-server libmysqlclient-dev"
print "Installing Packages:", packages
exec_in_shell("apt-get install -y %s" % packages)
update_config_for_debian()
def update_config_for_debian():
global apache_user
apache_user = "www-data"
# update memcache user
with open("/etc/memcached.conf", "r") as original:
memcached_conf = original.read()
with open("/etc/memcached.conf", "w") as modified:
modified.write(memcached_conf.replace("-u memcache", "-u %s" % apache_user))
exec_in_shell("a2enmod rewrite")
for service in ("mysql", "apache2", "memcached", "ntpd"):
exec_in_shell("service %s restart" % service)
def install_python_modules():
python_modules = "pytz python-dateutil jinja2 markdown2 termcolor python-memcached requests chardet dropbox google-api-python-client pygeoip"
print "-"*80
print "Installing Python Modules: (This may take some time)"
print python_modules
print "-"*80
exec_in_shell("easy_install pip")
exec_in_shell("pip install -q %s" % python_modules)
def install_erpnext(install_path):
print
print "-"*80
print "Installing ERPNext"
print "-"*80
# ask for details
global root_password
if not root_password:
root_password = get_root_password()
test_root_connection(root_password)
db_name = raw_input("ERPNext Database Name: ")
if not db_name:
raise Exception, "Sorry! You must specify ERPNext Database Name"
# install folders and conf
setup_folders(install_path)
setup_conf(install_path, db_name)
# setup paths
sys.path.extend([".", "lib", "app"])
# install database, run patches, update schema
setup_db(install_path, root_password, db_name)
setup_cron(install_path)
setup_apache_conf(install_path)
def get_root_password():
# ask for root mysql password
import getpass
root_pwd = None
root_pwd = getpass.getpass("MySQL Root user's Password: ")
return root_pwd
def test_root_connection(root_pwd):
out = exec_in_shell("mysql -u root %s -e 'exit'" % \
(("-p"+root_pwd) if root_pwd else "").replace('$', '\$').replace(' ', '\ '))
if "access denied" in out.lower():
raise Exception("Incorrect MySQL Root user's password")
def setup_folders(install_path):
app = os.path.join(install_path, "app")
if not os.path.exists(app):
print "Cloning erpnext"
exec_in_shell("cd %s && git clone https://github.com/webnotes/erpnext.git app" % install_path)
exec_in_shell("cd app && git config core.filemode false")
lib = os.path.join(install_path, "lib")
if not os.path.exists(lib):
print "Cloning wnframework"
exec_in_shell("cd %s && git clone https://github.com/webnotes/wnframework.git lib" % install_path)
exec_in_shell("cd lib && git config core.filemode false")
public = os.path.join(install_path, "public")
for p in [public, os.path.join(public, "files"), os.path.join(public, "backups"),
os.path.join(install_path, "logs")]:
if not os.path.exists(p):
os.mkdir(p)
def setup_conf(install_path, db_name):
import os, string, random, re
# generate db password
char_range = string.ascii_letters + string.digits
db_password = "".join((random.choice(char_range) for n in xrange(16)))
# make conf file
with open(os.path.join(install_path, "lib", "conf", "conf.py"), "r") as template:
conf = template.read()
conf = re.sub("db_name.*", 'db_name = "%s"' % (db_name,), conf)
conf = re.sub("db_password.*", 'db_password = "%s"' % (db_password,), conf)
with open(os.path.join(install_path, "conf.py"), "w") as conf_file:
conf_file.write(conf)
return db_password
def setup_db(install_path, root_password, db_name):
from webnotes.install_lib.install import Installer
inst = Installer("root", root_password)
inst.import_from_db(db_name, verbose=1)
# run patches and sync
exec_in_shell("./lib/wnf.py --patch_sync_build")
def setup_cron(install_path):
erpnext_cron_entries = [
"*/3 * * * * cd %s && python lib/wnf.py --run_scheduler >> /var/log/erpnext-sch.log 2>&1" % install_path,
"0 */6 * * * cd %s && python lib/wnf.py --backup >> /var/log/erpnext-backup.log 2>&1" % install_path
]
for row in erpnext_cron_entries:
try:
existing_cron = exec_in_shell("crontab -l")
if row not in existing_cron:
exec_in_shell('{ crontab -l; echo "%s"; } | crontab' % row)
except:
exec_in_shell('echo "%s" | crontab' % row)
def setup_apache_conf(install_path):
apache_conf_content = """Listen 8080
NameVirtualHost *:8080
<VirtualHost *:8080>
ServerName localhost
DocumentRoot %s/public/
AddHandler cgi-script .cgi .xml .py
AddType application/vnd.ms-fontobject .eot
AddType font/ttf .ttf
AddType font/otf .otf
AddType application/x-font-woff .woff
<Directory %s/public/>
# directory specific options
Options -Indexes +FollowSymLinks +ExecCGI
# directory's index file
DirectoryIndex web.py
AllowOverride all
Order Allow,Deny
Allow from all
# rewrite rule
RewriteEngine on
RewriteCond %%{REQUEST_FILENAME} !-f
RewriteCond %%{REQUEST_FILENAME} !-d
RewriteCond %%{REQUEST_FILENAME} !-l
RewriteRule ^([^/]+)$ /web.py?page=$1 [QSA,L]
</Directory>
</VirtualHost>""" % (install_path, install_path)
new_apache_conf_path = os.path.join(install_path, os.path.basename(install_path)+".conf")
with open(new_apache_conf_path, "w") as apache_conf_file:
apache_conf_file.write(apache_conf_content)
def post_install(install_path):
global apache_user
exec_in_shell("chown -R %s %s" % (apache_user, install_path))
apache_conf_filename = os.path.basename(install_path)+".conf"
if is_redhat:
os.symlink(os.path.join(install_path, apache_conf_filename),
os.path.join("/etc/httpd/conf.d", apache_conf_filename))
exec_in_shell("service httpd restart")
elif is_debian:
os.symlink(os.path.join(install_path, apache_conf_filename),
os.path.join("/etc/apache2/sites-enabled", apache_conf_filename))
exec_in_shell("service apache2 restart")
print
print "-"*80
print "Installation complete"
print "Open your browser and go to http://localhost:8080"
print "Login using username = Administrator and password = admin"
def exec_in_shell(cmd):
# using Popen instead of os.system - as recommended by python docs
from subprocess import Popen
import tempfile
with tempfile.TemporaryFile() as stdout:
with tempfile.TemporaryFile() as stderr:
p = Popen(cmd, shell=True, stdout=stdout, stderr=stderr)
p.wait()
stdout.seek(0)
out = stdout.read()
stderr.seek(0)
err = stderr.read()
if err and any((kw in err.lower() for kw in ["traceback", "error", "exception"])):
print out
raise Exception, err
else:
print "."
return out
if __name__ == "__main__":
install()