install.py 18 KB
import platform
import os, sys
import subprocess
import shutil
import fileinput


# Re-install the VENV ?
REINSTALL_VENV = True

venv = "venv_py3_pyros"

# python = 'python3'
python_global = os.path.split(sys.executable)[-1]
sql_database = "pyros"
sql_database_test = "pyros_test"
sql_user = "pyros"
sql_pswd = "DjangoPyros"
mysql_exe_path = ""

REQUIREMENTS = 'REQUIREMENTS.txt'
end_of_line = '\n\n'
venv_bin = '/bin/'
# --------------------------------------------
# --- Modified values for Windows
# --------------------------------------------
if (platform.system() == "Windows"):
    REQUIREMENTS = 'REQUIREMENTS_WINDOWS.txt'
    end_of_line = "\r\n\r\n"
    venv_bin = "/Scripts/"
    #pip = '\Scripts\pip' # ----- seems non useful
    #mysql_exe_path = "C:/Program Files (x86)/MySQL/MySQL Server 5.0/bin/"
    #question = "Enter the path of the MySQL server if it is not the following name (" + mysql_exe_path + "): "
    #res = input(question)
    #if res!="":
    #   mysql_exe_path = res
#pip = '/bin/pip'
'''
pip = venv_bin+'pip'
python = venv_bin+'python'
'''
venv_pip = venv + venv_bin+'pip'
venv_python = venv + venv_bin+'python'



class Colors:
    if (platform.system() == "Windows"):
         ERROR = ''
         END = ''
         LOG_BLUE = ''
    else:
         ERROR = '\033[91m'
         END = '\033[0m'
         LOG_BLUE = '\033[94m'

def replacePatternInFile(pattern, replace, file_path):
    try:

        with fileinput.FileInput(file_path, inplace=True, backup='.bak') as file:
            for line in file:
                print(line.replace(pattern, replace), end='')
    except:
        stderr.write(Colors.ERROR + "ERROR !: replacement in file failed !" + Colors.END + "\r\n")
        return 1
    return 0



def install_dependency_ubuntu(command, mode):
    #
    ##install dependency then check the return code
    #

    old = command
    if (mode == 'i'):
        command = 'apt-get install ' + command
    elif (mode == 'u'):
        command = 'apt-get update'
    elif (mode == 'a'):
        command = 'add-apt-repository ' + command
    process = subprocess.Popen(command, shell=True)
    process.wait()
    if process.returncode != 0:
        stderr.write(Colors.ERROR + "ERROR !: installation of " + old + " failed !" + Colors.END + "\r\n")


def install_required_ubuntu():
    install_dependency_ubuntu("update", 'u')
    install_dependency_ubuntu("python-lxml", 'i')
    install_dependency_ubuntu("libxml2-dev", 'i')
    install_dependency_ubuntu("libxslt-dev", 'i')
    install_dependency_ubuntu("zlib1g-dev", 'i')
    install_dependency_ubuntu("update", 'u')
    install_dependency_ubuntu("rabbitmq-server", 'i')
    #install_dependency_ubuntu("libmysqlclient-dev", 'i')


def install_dependency_centos(command, mode):
    #
    ##install dependency then check the return code
    #
    old = command
    if (mode == 'i'):
        command = 'yum -y install ' + command
    elif (mode == 'u'):
        command = 'yum update ' + command
    process = subprocess.Popen(command, shell=True)
    process.wait()
    if process.returncode != 0:
        stderr.write(Colors.ERROR + "ERROR !: installation of " + old + " failed !" + Colors.END + "\r\n")


def install_required_centos():
    install_dependency_centos("yum", 'u')
    install_dependency_centos("kernel", 'u')
    install_dependency_centos("", 'u')
    install_dependency_centos("libxml2", 'i')
    install_dependency_centos("libxslt libxslt-2", 'i')
    install_dependency_centos("libxslt-devel libxml2-devel", 'i')
    install_dependency_centos("rabbitmq-server", 'i')
    install_dependency_centos("mariadb-server", 'i')
    install_dependency_centos("mariadb", 'i')
    install_dependency_centos("mariadb-devel", 'i')

    process = subprocess.Popen("systemctl start mariadb.service", shell=True)
    process.wait()
    if process.returncode != 0:
        stderr.write(Colors.ERROR + "ERROR !" + Colors.END + "\r\n")

    process = subprocess.Popen("systemctl enable mariadb.service", shell=True)
    process.wait()
    if process.returncode != 0:
        stderr.write(Colors.ERROR + "ERROR !" + Colors.END + "\r\n")

    process = subprocess.Popen("mysql_secure_installation", shell=True)
    process.wait()
    if process.returncode != 0:
        stderr.write(Colors.ERROR + "ERROR !" + Colors.END + "\r\n")


def install_required():
    # checking if user is sudo then install the needed dependencies
    # find the linux distribution and call the related function
    distribution = platform.dist()
    if not 'SUDO_UID' in os.environ.keys():
        stderr.write("Super user rights are needed to install prerequisites\r\n")
        exit(1)
    if distribution[0] == "Ubuntu" or distribution[0] == "Debian":
        install_required_ubuntu()
    elif distribution[0] == "centos":
        install_required_centos()
    else:
        print("Requirements are made for Ubuntu, Debian and CentOS only")
        exit(1)


'''
def pip_install_in_venv(package_name:str, options:str=NULL):
    #global venv, pip
    global venv_pip
    #''
    python_exec = '\Scripts\python' if platform.system() == "Windows" else '/bin/python'
    os.system(venv + python_exec + ' -m pip install ' + options+' ' + package_name)
    #''
    #os.system(venv + pip +' install --upgrade wheel')
    os.system(venv_pip + ' install ' + options + ' ' + package_name)
'''



def install_venv(venv:str):

    # --------------------------------------------
    # --- Be aware not to create virtual environment in case of user root
    # --------------------------------------------
    if 'SUDO_UID' in os.environ.keys():
        answer = input(
            "You are about to install your virtualenv only for root, this is discouraged, are you sure ? (Y/N) If you are not sure, relaunch the script without super user privileges\n")
        while (answer != 'Y' and answer != 'y' and answer != 'n' and answer != 'N'):
            answer = input(
                "You are about to install your virtualenv only for root, this is discouraged, are you sure ? (Y/N) \n")
        if (answer not in ['y', 'Y']):
            exit(1)

    # --------------------------------------------
    # --- Create the private directory to put in files for virtual environment
    # --------------------------------------------
    if (os.path.basename(os.getcwd()) != "private"):
        if not(os.path.isdir("../private")):
            print(Colors.LOG_BLUE + "-----------------------------Creating \'private\' directory-----------------------------" + Colors.END)
            os.mkdir("../private")
        print(Colors.LOG_BLUE + "-----------------------------cd private-----------------------------" + Colors.END)

    # --------------------------------------------
    # --- Deleting if already exist then creating the venv
    # --------------------------------------------
    os.chdir("../private")
    while True:
        try:
            if (os.path.isdir(venv)):
                print(Colors.LOG_BLUE + "-----------------------------Deleting existing venv-----------------------------" + Colors.END)
                shutil.rmtree(venv)
            break
        except Exception as e:
            print(e)
            continue

    # --------------------------------------------
    # --- Reinstall the virtual environment
    # --------------------------------------------
    
    print(Colors.LOG_BLUE + "-----------------------------Creating venv " + venv + "-----------------------------"+end_of_line + Colors.END)
    os.system(python_global+" -m venv " + venv)
        
    print(Colors.LOG_BLUE + "-----------------------------Upgrade pip, wheel, and setuptools" + "-----------------------------"+end_of_line + Colors.END)
    # Upgrade pip
    #pip_install_in_venv('pip', '--upgrade')
    os.system(venv_python + ' -m pip install --upgrade pip')
    '''
    if (platform.system() == "Windows"):    
        os.system(venv + '\Scripts\python -m pip install --upgrade pip')
    else: # Linux
        os.system(venv + '/bin/python -m pip install --upgrade pip')
    '''
    
    # Pip upgrade wheel and setuptools
    #pip_install_in_venv('wheel', '--upgrade')
    os.system(venv_pip+' install --upgrade wheel')
    #pip_install_in_venv('setuptools', '--upgrade')
    os.system(venv_pip+' install --upgrade setuptools')
    
    # Lxml for Windows
    if (platform.system() == "Windows"): os.system(venv_pip + ' install ../install\windows\lxml-4.1.1-cp36-cp36m-win_amd64.whl')
    '''
        if (platform.machine() == "x86"):
            os.system(venv + '\Scripts\pip install ../install\windows\lxml-4.1.1-cp36-cp36m-win32.whl')
            os.system(venv_pip + ' install ../install\windows\lxml-4.1.1-cp36-cp36m-win32.whl')
        else:
            os.system(venv_pip + ' install ../install\windows\lxml-4.1.1-cp36-cp36m-win_amd64.whl')
    '''
    
    # Pip install required packages from REQUIREMENTS file
    print(Colors.LOG_BLUE + "-----------------------------Installing python packages via pip-----------------------------" + Colors.END)
    os.system(venv_pip+' install -r ../install' + os.sep + REQUIREMENTS)
    print(Colors.LOG_BLUE + "-----------------------------cd ../install-----------------------------" + Colors.END)
    os.chdir("../install")
    
    
    
def install_database(venv):
    
    # --------------------------------------------
    # --- Default values for Linux
    # --------------------------------------------
    print(Colors.LOG_BLUE + "Python executable is " + python_global + Colors.END)
    ##if platform.dist()[0] == "centos": print("centos platform")

    # --------------------------------------------
    # --- Determine the MySQL version
    # --------------------------------------------
    output = subprocess.check_output("mysql --version", shell=True)
    # output is something like: "mysql  Ver 15.1 Distrib 10.0.20-MariaDB, for Linux (x86_64) using  EditLine wrapper"
    tmp = (str(output).split()[4]).split('.')
    sql_version = float(tmp[0]+'.'+tmp[1])
    print(Colors.LOG_BLUE + "MySQL version is " + str(sql_version) + Colors.END)

    # --------------------------------------------
    # --- Prepare the SQL query to create and initialize the pyros database if needed
    # --------------------------------------------
    if sql_version<5.5:
        sql_query = "drop database "+sql_database+" ; CREATE DATABASE "+sql_database+"; drop database "+sql_database_test+" ; CREATE DATABASE "+sql_database_test+"; CREATE USER "+sql_user+" ; GRANT USAGE ON *.* TO '"+sql_user+"'@'localhost' IDENTIFIED BY '"+sql_pswd+"' WITH GRANT OPTION; DROP USER '"+sql_user+"'@'localhost'; GRANT ALL ON "+sql_database+".* TO '"+sql_user+"'@'localhost' IDENTIFIED BY '"+sql_pswd+"'; GRANT ALL PRIVILEGES ON "+sql_database+".* TO '"+sql_user+"'@'localhost' IDENTIFIED BY '"+sql_pswd+"' WITH GRANT OPTION;  GRANT ALL PRIVILEGES ON "+sql_database_test+".* TO "+sql_user+"@localhost IDENTIFIED BY '"+sql_pswd+"' WITH GRANT OPTION;"
    else:
        sql_query = "CREATE DATABASE IF NOT EXISTS "+sql_database+";  CREATE DATABASE IF NOT EXISTS "+sql_database_test+"; CREATE USER IF NOT EXISTS "+sql_user+"; GRANT USAGE ON *.* TO '"+sql_user+"'; DROP USER '"+sql_user+"'; GRANT ALL ON "+sql_database+".* TO '"+sql_user+"'@'localhost' IDENTIFIED BY '"+sql_pswd+"'; GRANT ALL ON "+sql_database_test+".* TO '"+sql_user+"'@'localhost'; GRANT ALL PRIVILEGES ON "+sql_database_test+".* TO '"+sql_user+"'@'localhost'; GRANT ALL ON "+sql_database_test+".* TO '"+sql_user+"'@'localhost' IDENTIFIED BY '"+sql_pswd+"'"
        # NEWER MYSQL:
        # OLDER MYSQL: Try this instead for OLDER mysql (works on CentOS 6.4 and Centos 7.5 with mysql 5.5):
        #req = "drop database pyros; CREATE DATABASE pyros; drop database pyros_test ; CREATE DATABASE pyros_test; drop user 'pyros'@'localhost' ; CREATE USER pyros; GRANT USAGE ON *.* TO 'pyros'; DROP USER 'pyros'; GRANT ALL ON pyros.* TO 'pyros'@'localhost' IDENTIFIED BY 'DjangoPyros'; GRANT ALL ON test_pyros.* TO 'pyros'@'localhost'; GRANT ALL PRIVILEGES ON test_pyros_test.* TO 'pyros'@'localhost'; GRANT ALL ON pyros_test.* TO 'pyros'@'localhost' IDENTIFIED BY 'DjangoPyros'"
        #req = "drop database pyros ; CREATE DATABASE pyros; drop database pyros_test ; CREATE DATABASE pyros_test; DROP USER 'pyros'@'localhost' ; GRANT USAGE ON *.* TO 'pyros'@'localhost' IDENTIFIED BY 'DjangoPyros' WITH GRANT OPTION; DROP USER 'pyros'@'localhost'; GRANT ALL ON pyros.* TO 'pyros'@'localhost' IDENTIFIED BY 'DjangoPyros'; GRANT ALL PRIVILEGES ON pyros.* TO 'pyros'@'localhost' IDENTIFIED BY 'DjangoPyros' WITH GRANT OPTION;  GRANT ALL PRIVILEGES ON pyros_test.* TO pyros@localhost IDENTIFIED BY 'DjangoPyros' WITH GRANT OPTION;"
        # (EP) ok for CENTOS 7 I suppose (but not for CentOS 6):
        #req_centos = "CREATE DATABASE IF NOT EXISTS pyros; CREATE DATABASE IF NOT EXISTS pyros_test; GRANT USAGE ON *.* TO 'pyros'@'localhost' IDENTIFIED BY 'DjangoPyros' WITH GRANT OPTION; DROP USER 'pyros'@'localhost'; GRANT ALL ON pyros.* TO 'pyros'@'localhost' IDENTIFIED BY 'DjangoPyros'; GRANT ALL PRIVILEGES ON pyros.* TO 'pyros'@'localhost' IDENTIFIED BY 'DjangoPyros' WITH GRANT OPTION;  GRANT ALL PRIVILEGES ON pyros_test.* TO pyros@localhost IDENTIFIED BY 'DjangoPyros' WITH GRANT OPTION;"
    
    # --- Prepare the SQL query to create and initialize the pyros database if needed
    #if platform.dist()[0] == "centos":
    #    req = sql_query
    mysql_call_root = "\"" + mysql_exe_path+ "mysql\" -u root -p"
    mysql_call_pyros = "\"" + mysql_exe_path+ "mysql\" -u "+sql_user+" -p"
    
    
    # --------------------------------------------
    # --- Creating database and creating and granting user pyros
    # --------------------------------------------
    print(Colors.LOG_BLUE + end_of_line+"-----------------------------Launching mysql to create database and create and grant user pyros-----------------------------" + Colors.END)
    user_ros_is_created = True
    if sql_version<5.5:
       print(Colors.LOG_BLUE +"------------------ Check if the user pyros exists in MYSQL (type the pyros password) -----------------------------" + Colors.END)
       # --- We are testing if user pyros already exists in the database
       process = subprocess.Popen("echo quit |" + mysql_call_pyros, shell=True)
       process.wait()
       if (process.returncode == 0):
           user_ros_is_created = False
    if user_ros_is_created:
       # --- The user pyros must be created in the database
       print(Colors.LOG_BLUE +"-----------------------------Please enter your MYSQL root password-----------------------------" + Colors.END)
       process = subprocess.Popen("echo \"" + sql_query + "\" |"+ mysql_call_root, shell=True)
       process.wait()
    if (process.returncode != 0):
        stderr.write(Colors.ERROR + "ERROR !: db configuration failed !" + Colors.END + "\r\n")
        return -1
    print(Colors.LOG_BLUE + end_of_line+"-----------------------------Database created and user pyros successfully created and granted-----------------------------" + Colors.END)

    # --------------------------------------------
    # --- Replacing pattern in settings.py to use mysql
    # --------------------------------------------
    print(Colors.LOG_BLUE + "-----------------------------setting MYSQL = True in settings-----------------------------" + Colors.END)
    replacePatternInFile("MYSQL = False", "MYSQL = True", os.path.normpath("../src/pyros/settings.py"))
    if (platform.system() == "Windows"):
        #
        ## moving voeventparse in site-packages directory
        #
        try:
            site_packages = "..\private\\venv_py3_pyros\Lib\site-packages\\"
            if (not os.path.isdir(site_packages + "voevent_parse-0.9.5.dist-info") and
            not os.path.isdir(site_packages + "voeventparse")):
                print(Colors.LOG_BLUE + "\r\n\r\n-----------------------------Copying the voevent library in Lib/site-packages-----------------------------" + Colors.END)
                process = subprocess.Popen("xcopy /i /y windows\\voeventparse " + site_packages + "voeventparse")
                process.wait()
                if (process.returncode != 0):raise Exception
                process = subprocess.Popen("xcopy /i /y windows\\voevent_parse-0.9.5.dist-info " + site_packages + "voevent_parse-0.9.5.dist-info")
                process.wait()
                if (process.returncode != 0): raise Exception

                print(Colors.LOG_BLUE + "\r\n-----------------------------library successfully copied-----------------------------" + Colors.END)
        except Exception as e:
            print(Colors.ERROR + "ERROR while Copying the voevent library in Lib/site-packages" + Colors.END, file=stderr)
            return False


    print(Colors.LOG_BLUE + "\r\n-----------------------------cd ..-----------------------------" + Colors.END)
    os.chdir("..")

    # --------------------------------------------
    # ---  Executing migrations
    # --------------------------------------------
    
    print(Colors.LOG_BLUE + "\r\n\r\n-----------------------------Migrate : executing pyros.py init_database-----------------------------" + Colors.END)
    #TODO: from venv !!!
    try:
        os.system(python_global+" pyros.py init_database")
        '''
        process = subprocess.Popen(python_global + " pyros.py init_database"  , shell=True)
        process.wait()
        '''

    
    except Exception as e:
        print("Exception ", e)
        print(Colors.ERROR + "Error while initialising database :" + Colors.END)
        return -1

    print(Colors.LOG_BLUE + "\r\n\r\n-----------------------------Install successfull !-----------------------------" + Colors.END)
    return 0


def _help():
    print(
        "Welcome in the installation script of the pyros venv.\t\nPlease launch it from the install directory of pyros.\n\tIf you're on Ubuntu Debian or CentOS:\n\tlaunch it with sudo and <--prerequisites> or <-p> to install the prerequisites.\n\t-->sudo ./test_install.py -p\n\n\tFor the python packages launch it from the install directory of pyros without sudo and without parameter\n\t-->./test_install.py")





if __name__ == '__main__':
    if (len(sys.argv) > 1):
        if sys.argv[1] == "--prerequisites" or sys.argv[1] == "-p":
            install_required()
        else:
            _help()
    elif len(sys.argv) == 1:
        if REINSTALL_VENV: install_venv(venv)
        install_database(venv)

    else:
        _help()