mirror of
https://github.com/th3r00t/pyShelf.git
synced 2026-04-28 01:59:35 -04:00
359 lines
11 KiB
Python
Vendored
359 lines
11 KiB
Python
Vendored
#!/usr/bin/python3
|
|
import json
|
|
import os
|
|
import pathlib
|
|
import platform
|
|
import pprint
|
|
import subprocess as sp
|
|
import sys
|
|
from shutil import copyfile
|
|
|
|
import psutil
|
|
from src.backend.lib.display import TerminalDisplay
|
|
|
|
log_file = "installer.log"
|
|
messages = []
|
|
|
|
|
|
class Configuration:
|
|
def __init__(self):
|
|
self._cp = pathlib.Path("config.json")
|
|
self._data = self.open_file()
|
|
self.system = platform.system()
|
|
|
|
def open_file(self):
|
|
"""
|
|
Try to open and then backup the configuration file.
|
|
Fail and return false if initial configuration is not found.
|
|
# TODO: More specific error handling
|
|
"""
|
|
try:
|
|
with open(str(self._cp), "r") as read_file:
|
|
data = json.load(read_file)
|
|
with open("config.backup.json", "w") as backup_file:
|
|
json.dump(data, backup_file)
|
|
return data
|
|
except Exception as e:
|
|
print(e)
|
|
return False
|
|
|
|
def write_file(self, data):
|
|
"""
|
|
Write the provided data to the new configuration file
|
|
"""
|
|
with open(str(self._cp), "w") as write_file:
|
|
json.dump(data, write_file)
|
|
return True
|
|
|
|
|
|
class RequiredServices:
|
|
def check_ps(self, service_list):
|
|
"""
|
|
Check service_list against running processes
|
|
by calling self.process_list, remove found
|
|
services from the list and return
|
|
"""
|
|
# Get the matched processes
|
|
_matches = self.process_list().intersection(set(service_list))
|
|
for r in _matches:
|
|
service_list.remove(r)
|
|
return service_list
|
|
|
|
@staticmethod
|
|
def process_list():
|
|
"""
|
|
Iterate running processes returning the name of each
|
|
make it a set and return
|
|
"""
|
|
_processes = []
|
|
for p in psutil.process_iter():
|
|
_processes.append(p.name())
|
|
return set(_processes)
|
|
|
|
@staticmethod
|
|
def web_server_found(service_list):
|
|
# Determine whether or not both possible webservers are missing
|
|
_c = 0
|
|
for r in service_list:
|
|
if r == "nginx" or r == "httpd":
|
|
_c = _c + 1
|
|
if _c > 1:
|
|
return False # Return false if neither are found
|
|
else:
|
|
return True # Return true if one is found
|
|
|
|
@staticmethod
|
|
def db_server_found(service_list):
|
|
_c = 0
|
|
for r in service_list:
|
|
if r == "postgres":
|
|
_c = _c + 1
|
|
if _c > 0:
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
|
|
class SystemInstaller:
|
|
def __init__(self):
|
|
self.bin = self.get()
|
|
self.site_dirs = ["/etc/nginx/sites-available", "/etc/nginx/sites-enabled"]
|
|
self.nginx_conf = "pyshelf_nginx.conf"
|
|
|
|
def get(self):
|
|
platfrm = platform.platform().split("-")
|
|
if platfrm[0].lower() == "linux":
|
|
installers = [
|
|
{"bin": "apt", "options": [], "search": "search", "install": "install"},
|
|
{"bin": "pacman", "options": [], "search": "-Ss", "install": "-S"},
|
|
{"bin": "yum", "options": [], "search": "search", "install": "install"},
|
|
{"bin": "docker", "options": []},
|
|
]
|
|
_paths = os.environ["PATH"].split(":")
|
|
for p in _paths:
|
|
for _installer in installers:
|
|
_fp = p + "/" + str(_installer["bin"])
|
|
if os.path.isfile(_fp):
|
|
global messages
|
|
messages = messages + [
|
|
"Found system installer binary " + str(_installer["bin"])
|
|
]
|
|
return _installer
|
|
|
|
def copy_config(self, _file=None, _dirs=None):
|
|
if _file is None:
|
|
_file = self.nginx_conf
|
|
if _dirs is None:
|
|
_dirs = self.site_dirs
|
|
|
|
outfile = "/%s" % _file.__str__()
|
|
if os.path.isdir(_dirs[0]):
|
|
os.system("sudo cp %s %s" % (_file, _dirs[0] + outfile))
|
|
else:
|
|
os.system("sudo mkdir %s" % _dirs[0])
|
|
os.system("sudo cp %s %s" % (_file, _dirs[0] + outfile))
|
|
try:
|
|
if os.path.isdir(_dirs[1]):
|
|
ln_string = str(_dirs[0] + outfile + " " + _dirs[1] + outfile)
|
|
os.system("sudo ln -s %s" % ln_string)
|
|
except Exception as e:
|
|
pass
|
|
return True
|
|
|
|
def make_nginx_config(self, answers):
|
|
root = os.path.abspath(".")
|
|
_fp = "pyshelf_nginx.conf"
|
|
for r in answers:
|
|
if r["name"] == "hostname":
|
|
hostname = r["answer"]
|
|
elif r["name"] == "webport":
|
|
port = r["answer"]
|
|
elif r["name"] == "wsgiport":
|
|
wsgiport = r["answer"]
|
|
nginx_conf_str = """
|
|
# pyshelf_nginx.conf
|
|
upstream django {server unix://%s/pyshelf_wsgi.sock;}
|
|
server {
|
|
listen %s;
|
|
server_name %s;
|
|
access_log /var/log/nginx/pyshelf.access.log;
|
|
error_log /var/log/nginx/pyshelf.error.log;
|
|
charset utf-8;
|
|
client_max_body_size 75M;
|
|
location /media {root %s/src/interface;}
|
|
location /static {root %s/src/interface;}
|
|
location /books {internal; alias %s;}
|
|
location / {uwsgi_pass django; include %s/uwsgi_params;}
|
|
}
|
|
""" % (
|
|
root,
|
|
port,
|
|
hostname,
|
|
root,
|
|
root,
|
|
root,
|
|
root,
|
|
)
|
|
with open(_fp, "w") as write_file:
|
|
write_file.write(nginx_conf_str)
|
|
global messages
|
|
messages = messages + ["Generated new pyshelf_nginx.conf", nginx_conf_str]
|
|
|
|
def make_wsgi_config(self, answers):
|
|
root = os.path.abspath(".")
|
|
_fp = "uwsgi.ini"
|
|
for r in answers:
|
|
if r["name"] == "hostname":
|
|
hostname = r["answer"]
|
|
elif r["name"] == "wsgiport":
|
|
wsgiport = r["answer"]
|
|
wsgi_conf_str = """
|
|
[uwsgi]
|
|
chdir=%s/src
|
|
module=frontend.wsgi
|
|
master=True
|
|
pidfile=/tmp/pyShelf.pid
|
|
vacuum=True
|
|
socket=%s/pyshelf_wsgi.sock
|
|
chmod-socket=666
|
|
""" % (
|
|
root,
|
|
root
|
|
)
|
|
with open(_fp, "w") as write_file:
|
|
write_file.write(wsgi_conf_str)
|
|
global messages
|
|
messages = messages + ["Generated uwsgi.ini", wsgi_conf_str]
|
|
|
|
def log(self):
|
|
global log_file
|
|
global messages
|
|
with open(log_file, "w") as write_file:
|
|
write_file.write(TerminalDisplay().banner_render())
|
|
for message in messages:
|
|
write_file.write(message + "\n")
|
|
messages = messages + ["Log file written to " + log_file.__str__()]
|
|
|
|
|
|
config = Configuration().open_file()
|
|
sysinstall = SystemInstaller()
|
|
installer = sysinstall.bin
|
|
# Get user configuration options
|
|
install_answers = TerminalDisplay().installer()
|
|
for key in install_answers:
|
|
config[key["name"]] = key["answer"]
|
|
config["USER"] = os.environ["USER"]
|
|
# Write configuration
|
|
Configuration().write_file(config)
|
|
|
|
# Start checking for our list of required services
|
|
service_list = ["postgres", "nginx", "httpd", "test"]
|
|
req = RequiredServices().check_ps(service_list)
|
|
|
|
# Does user have either nginx || apache?
|
|
if RequiredServices().web_server_found(req) is False:
|
|
web_prompt = [
|
|
{
|
|
"message": " You must have either apache or nginx\n would you like us to try and install nginx now? > ",
|
|
"options": "nginx",
|
|
"name": "NGINX",
|
|
"answer": None,
|
|
"default": "no",
|
|
}
|
|
]
|
|
install_prompt = TerminalDisplay().prompt(web_prompt)
|
|
if install_prompt[0]["answer"] == "yes":
|
|
if installer is None:
|
|
installer = SystemInstaller().bin
|
|
if installer["bin"] == "pacman":
|
|
package = "nginx-mainline"
|
|
else:
|
|
package = "nginx"
|
|
options = ""
|
|
for o in installer["options"]:
|
|
options = options + " " + o
|
|
cmd = (
|
|
"sudo "
|
|
+ installer["bin"]
|
|
+ " "
|
|
+ installer["install"]
|
|
+ " "
|
|
+ options
|
|
+ package
|
|
)
|
|
install_status = os.system(cmd)
|
|
os.system("sudo systemctl start nginx")
|
|
messages = messages + [
|
|
"Nginx installed and started",
|
|
"To enable autostart you must run",
|
|
" sudo systemctl enable nginx",
|
|
"\n",
|
|
]
|
|
# Does user have postgreSQL?
|
|
if RequiredServices().db_server_found(req) is False:
|
|
db_prompt = [
|
|
{
|
|
"message": " You must have PostgreSQL\n would you like us to try and install it now? > ",
|
|
"options": "postgres",
|
|
"name": "postgresql",
|
|
"answer": None,
|
|
"default": "no",
|
|
}
|
|
]
|
|
install_prompt = TerminalDisplay().prompt(db_prompt)
|
|
if install_prompt[0]["answer"] == "yes":
|
|
if installer is None:
|
|
installer = SystemInstaller().bin
|
|
options = ""
|
|
for o in installer["options"]:
|
|
options = options + " " + o
|
|
package = "postgresql postgresql-contrib"
|
|
cmd = (
|
|
"sudo "
|
|
+ installer["bin"]
|
|
+ " "
|
|
+ installer["install"]
|
|
+ " "
|
|
+ options
|
|
+ package
|
|
)
|
|
install_status = os.system(cmd)
|
|
for r in install_answers:
|
|
if r["name"] == "PASSWORD": sql_pass = r["answer"]
|
|
|
|
sql_user = config["USER"]
|
|
db_name = "pyshelf"
|
|
psql_cmd = """
|
|
CREATE DATABASE %s;
|
|
CREATE USER %s WITH PASSWORD \'%s\';
|
|
GRANT ALL PRIVILEGES ON DATABASE %s TO %s;
|
|
""" % (db_name, sql_user, sql_pass, db_name, sql_user)
|
|
_sql_file = "create_db.sql"
|
|
with open(_sql_file, "w") as sql_file_open:
|
|
sql_file_open.write(psql_cmd)
|
|
sql_file_open.close()
|
|
os.system("sudo systemctl start postgresql")
|
|
os.system("sudo -u postgres initdb --locale=en_US.UTF-8 -E UTF8 -D /var/lib/postgres/data")
|
|
os.system("sudo -u postgres psql -f %s"%_sql_file)
|
|
messages = messages + [
|
|
"PostgreSQL installed and started",
|
|
"To enable autostart you must run",
|
|
" sudo systemctl enable nginx",
|
|
"\n",
|
|
"Database cluster initialized at /var/lib/postgres",
|
|
"pyShelf database and user created",
|
|
psql_cmd
|
|
]
|
|
|
|
# Post install configurations
|
|
sysinstall.make_nginx_config(install_answers)
|
|
try:
|
|
os.chdir("src/")
|
|
os.system("python manage.py makemigrations")
|
|
os.system("python manage.py makemigrations interface")
|
|
os.system("python manage.py migrate")
|
|
os.system("python manage.py migrate interface")
|
|
os.chdir("../")
|
|
except Exception as e:
|
|
print("-"*80)
|
|
print(" E:"+e)
|
|
try:
|
|
copy_config = sysinstall.copy_config()
|
|
if copy_config:
|
|
messages = messages + ["pyShelf site config copied to sites-available, and symlinked to sites-enabled"]
|
|
except Exception as e:
|
|
messages = messages + ["nginx site config not copied",
|
|
"you are responsible for setting up your web server"]
|
|
sysinstall.make_wsgi_config(install_answers)
|
|
messages = messages + ["You should now import your books by running importBooks", "You can then start the interface with uwsgi --ini uwsgi.ini"]
|
|
|
|
# Display end screen
|
|
sysinstall.log()
|
|
TerminalDisplay().clear()
|
|
TerminalDisplay().banner()
|
|
for message in messages:
|
|
print(" "+message)
|
|
print()
|
|
|
|
TerminalDisplay().h_rule()
|