Files
pyShelf/installer
2020-05-09 14:30:34 -04:00

395 lines
12 KiB
Python
Executable File
Vendored

#!python
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)
""" TODO check for sites-enabled, create it if it doesnt exist,
then symlink the config """
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:///tmp/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;}
}
""" % (
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=/tmp/pyshelf_wsgi.sock
chmod-socket=666
""" % (
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"]
config["USER"] = "pyshelf"
# Write configuration
Configuration().write_file(config)
# Start checking for our list of required services
service_list = ["postgres", "nginx", "httpd"]
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? Enter for default 'no' > ",
"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? Enter for default 'no' > ",
"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"
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"]
sql_user = "pyshelf"
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 = "/tmp/create_db.sql"
breakpoint()
with open(_sql_file, "w") as sql_file_open:
sql_file_open.write(psql_cmd)
sql_file_open.close()
os.system(
"sudo -u postgres initdb --locale=en_US.UTF-8 -E UTF8 \
-D /var/lib/postgres/data"
)
os.system("sudo systemctl start postgresql")
os.system("sudo -u postgres psql -f %s" % _sql_file)
# os.system("sudo -u postgres psql -c \'%s\'"%psql_cmd)
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,
]
else:
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 = "/tmp/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 psql -f %s" % _sql_file)
# os.system("sudo -u postgres psql -c \'%s\'"%psql_cmd)
messages = messages + [
"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",
'A nginx config for your install has been created "pyshelf_nginx.conf"',
]
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()