Projet

Général

Profil

Télécharger (18,2 ko) Statistiques
| Branche: | Tag: | Révision:
2e0a7cb1 Sylvain L. Sauvage
# -*- coding: utf-8 -*-
#
# This program is a part of the IoTa project.
#
19b58bab Rémy Ménard
# Copyright © 2011-2013 Université de Caen Basse-Normandie, GREYC
#
2e0a7cb1 Sylvain L. Sauvage
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# <http://www.gnu.org/licenses/>
#
# See AUTHORS for a list of contributors.
#
import os
import os.path
import shutil
import re
import time
import urllib
import readline
import xml.dom.minidom
import traceback
import sys

from config import CONFIG

# Debug
SHOW_TRACEBACK = True
HALT_ON_ERROR = True


96454bcd Sylvain L. Sauvage
# ActiveMQ Utilities

def isActiveMQRunning():
try:
cnx = urllib.urlopen(CONFIG.get("activemq", "admin_url"))
cnx.close()
return True
except IOError:
return False


def startActiveMQ():
putWait("Starting up ActiveMQ")
if isActiveMQRunning():
putDoneOK("(already running)")
return
commandStart = ("ACTIVEMQ_OPTS_MEMORY=' ' " + CONFIG.get("activemq", "home") + "/bin/activemq start")
if not sh_exec(commandStart):
putDoneFail()
return
putDoneOK()


2e0a7cb1 Sylvain L. Sauvage
# Tomcat Utilities

def isTomcatRunning():
try:
cnx = urllib.urlopen( "http://" + CONFIG.get("global", "host") +
":" + CONFIG.get("tomcat", "http_port") + "/" )
cnx.close()
return True
except IOError:
return False


def startTomcat():
putWait("Starting up Tomcat engine")
# verify if running
if isTomcatRunning():
putDoneOK("(already running)")
return
# ask and wait for startup
filename = CONFIG.get("tomcat", "catalina_home") + "logs/catalina.out"
sh_touch(filename)
with open(filename, 'r') as logfile:
logfile.seek(0, 2)
# start Tomcat
commandStart = CONFIG.get("tomcat", "catalina_home") + "bin/startup.sh"
if not sh_exec(commandStart):
putDoneFail()
return
# wait for Tomcat’s loading of the webapps
while True:
where = logfile.tell()
line = logfile.readline()
if not line:
time.sleep(1)
logfile.seek(where)
else:
if line.find("Server startup in") != -1:
break
putDoneOK()

def stopTomcat():
putWait("Shutting down Tomcat engine")
# verify if running
if not isTomcatRunning():
putDoneOK("(not running)")
return
# ask and wait for shutdown
filename = CONFIG.get("tomcat", "catalina_home") + "logs/catalina.out"
sh_touch(filename)
with open(filename, 'r') as logfile:
logfile.seek(0, 2)
# stop Tomcat
commandStop = CONFIG.get("tomcat", "catalina_home") + "bin/shutdown.sh"
if not sh_exec(commandStop):
putDoneFail()
return
# wait for Tomcat’s unloading of the webapps
while True:
where = logfile.tell()
line = logfile.readline()
if not line:
time.sleep(1)
logfile.seek(where)
else:
if line.find("destroy") != -1:
break
putDoneOK()


def manageTomcat(query):
try:
url = ("http://" + CONFIG.get("tomcat", "login") + ":" + CONFIG.get("tomcat", "password") +
"@" + CONFIG.get("global", "host") + ":" + CONFIG.get("tomcat", "http_port") +
"/" + CONFIG.get("tomcat", "manager_path") + "/")
cnx = urllib.urlopen(url + query)
ret = cnx.readline()
cnx.close()
if ret[0:2] == "OK":
putDoneOK()
else:
putDoneFail(error=ret)
except IOError as e:
putDoneFail(error=e)


# Web Applications Utiliites

def copyWar(webapp_repo, webapp_name, conffile=None):
webapp_path = CONFIG.get("tomcat", "catalina_home") + "webapps/" + webapp_name
warfile = webapp_path + ".war"
if os.path.exists(warfile):
96454bcd Sylvain L. Sauvage
if not getYN("Webapp exists. Do you really want to overwrite it?"):
2e0a7cb1 Sylvain L. Sauvage
return
sh_rm(warfile)
sh_rm_r(webapp_path)
if conffile and os.path.exists(conffile):
sh_rm(conffile)
sh_cp(webapp_repo, warfile)


def deployWar(pretty_name, section_name):
webapp_name = CONFIG.get(section_name, "name")
if CONFIG.isTrue("tomcat", "use_manager"):
putWait("Deploying " + pretty_name)
manageTomcat("deploy?path=/" + webapp_name + "&update=true&war=file://" +
sh_pwd() + "/" + CONFIG.get(section_name, "repo"))
else:
putMessage("Deploying " + pretty_name + " ...")
stopTomcat()
copyWar(CONFIG.get(section_name, "repo"), webapp_name)
startTomcat()


def deployWarDB(pretty_name, section_name):
webapp_name = CONFIG.get(section_name, "name")
contextfile = configureDB(pretty_name, webapp_name, section_name)
if CONFIG.isTrue("tomcat", "use_manager"):
putWait("Deploying " + pretty_name)
pwd = sh_pwd() + "/"
manageTomcat("deploy?path=/" + webapp_name + "&update=true&config=file://" + pwd +
contextfile + "&war=file://" + pwd + CONFIG.get(section_name, "repo"))
else:
putMessage("Deploying " + pretty_name + " ...")
stopTomcat()
host_contextfile = (CONFIG.get("tomcat", "catalina_home") +
"conf/Catalina/localhost/" + webapp_name + ".xml")
copyWar(CONFIG.get(section_name, "repo"), webapp_name, host_contextfile)
webapp_contextfile = (CONFIG.get("tomcat", "catalina_home") + webapp_name + "/META-INF/context.xml")
sh_cp(contextfile, webapp_contextfile)
sh_cp(contextfile, host_contextfile)
startTomcat()


def configurePropertiesWebApp(pretty_name, filename, section_name, dic):
putMessage("Configuring " + pretty_name + " (" + filename + ".properties) ...")
webapp = CONFIG.get(section_name, "name")
propfilename = (CONFIG.get("tomcat", "catalina_home") + "webapps/" + webapp +
"/WEB-INF/classes/" + filename + ".properties")
waitForFile(propfilename)
putWait("Modifying file " + filename + ".properties")
modifyPropertiesFile(propfilename, dic)


# Application Configuration Utilities

def configureProperties(pretty_name, filename, section_name, dic):
putWait("Configuring " + pretty_name + " (" + filename + ".properties) ...")
# create file
propfilename = CONFIG.get(section_name, "directory") + "/" + CONFIG.get(section_name, "name") + "/" + filename + ".properties"
sh_touch(propfilename)
modifyPropertiesFile(propfilename, dic)


def modifyPropertiesFile(propfilename, dic):
# read existing file
with open(propfilename, "r") as propfile:
lines = propfile.readlines()
# write new version
with open(propfilename, "w") as propfile:
# replace old values
for line in lines:
words = re.split("[=:]", line)
96454bcd Sylvain L. Sauvage
# don’t touch lines without = or :
2e0a7cb1 Sylvain L. Sauvage
if len(words) < 2:
propfile.write(line)
continue
96454bcd Sylvain L. Sauvage
# get the key (part before first = or :)
2e0a7cb1 Sylvain L. Sauvage
key = words[0].strip()
if key in dic:
val = dic[key]
if not isinstance(val, basestring):
val = CONFIG.get(val[0], val[1])
96454bcd Sylvain L. Sauvage
# beware =
val = val.replace("=", "\\=")
2e0a7cb1 Sylvain L. Sauvage
propfile.write(key + " = " + val + "\n")
del dic[key]
else:
propfile.write(line)
# add new variables
for key in dic.keys():
val = dic[key]
if not isinstance(val, basestring):
val = CONFIG.get(val[0], val[1])
96454bcd Sylvain L. Sauvage
# beware =
val = val.replace("=", "\\=")
2e0a7cb1 Sylvain L. Sauvage
propfile.write(key + " = " + val + "\n")
putDoneOK()


# Database Utilities

def configureDB(pretty_name, webapp_name, section_name):
putMessage("Tomcat DB configuration for " + pretty_name)
if getSetConfigYN("Do you want to create the " + pretty_name + " database?", section_name, "db_install"):
createDB(pretty_name, section_name)
contextfile = "resources/" + webapp_name + "_context.xml"
putWait("Creating " + contextfile)
doc = xml.dom.minidom.Document()
ctxt = doc.createElement("Context")
ctxt.setAttribute("path", "/" + webapp_name)
ctxt.setAttribute("reloadable", "true")
doc.appendChild(ctxt)
resc = doc.createElement("Resource")
resc.setAttribute("auth", "Container")
resc.setAttribute("defaultAutoCommit", "false")
resc.setAttribute("type", "javax.sql.DataSource")
resc.setAttribute("name", "jdbc/" + CONFIG.get(section_name, "db_jndi"))
resc.setAttribute("driverClassName", "com.mysql.jdbc.Driver")
resc.setAttribute("username", CONFIG.get(section_name, "db_login"))
resc.setAttribute("password", CONFIG.get(section_name, "db_password"))
url = ("jdbc:mysql://" + CONFIG.get("db", "host") + ":" + CONFIG.get("db", "port") +
"/" + CONFIG.get(section_name, "db_name") + "?autoReconnect=true")
resc.setAttribute("url", url)
ctxt.appendChild(resc)
# write result
with open(contextfile, "w") as cf:
doc.writexml(writer=cf, addindent=" ", encoding="utf-8")
putDoneOK()
return contextfile


def createDB(pretty_name, section_name):
if not execDB("Creating " + pretty_name + "’s database", "mysql",
"CREATE DATABASE " + CONFIG.get(section_name, "db_name") + ";"):
return
if not execDB("Granting access rights", "mysql",
"GRANT SELECT, INSERT, UPDATE, DELETE ON " +
CONFIG.get(section_name, "db_name") + ".* TO " +
96454bcd Sylvain L. Sauvage
CONFIG.get(section_name, "db_login") + "@'" + CONFIG.get("db", "user_host") + "' " +
2e0a7cb1 Sylvain L. Sauvage
"IDENTIFIED BY '" + CONFIG.get(section_name, "db_password") + "';"):
return
if not execDB("Creating tables", CONFIG.get(section_name, "db_name"),
"source resources/" + section_name + "_schema.sql;"):
return


def execDB(msg, db, query):
putWait(msg)
if sh_exec("mysql --host=" + CONFIG.get("db", "host") +
" --port=" + CONFIG.get("db", "port") +
" --user=" + CONFIG.get("db", "login") +
" --password=" + CONFIG.get("db", "password") +
" --database=" + db +
" --execute=\"" + query + "\""):
putDoneOK()
return True
putDoneFail()
return False


def createLDAP(msg, schema):
putWait(msg)
if sh_exec("ldapadd -Y EXTERNAL -H ldapi:/// -f " + schema):
putDoneOK()
return True
putDoneFail()
return False


def execLDAP(msg, ldiffile):
putWait(msg)
if sh_exec("ldapadd -x -D\"cn=" + CONFIG.get("ldap", "login") + "," + CONFIG.get("ldap", "base_dn") + "\" " +
"-w \"" + CONFIG.get("ldap", "password") + "\" -f " + ldiffile):
putDoneOK()
return True
putDoneFail()
return False


96454bcd Sylvain L. Sauvage
# Key and certificate tool
def execKeytool(msg, keycmd, storetype, keystore, password, keyalias, keypass, other_opts):
putWait(msg)
if keypass:
keypass = "-keypass \"" + keypass + "\""
cmd = ("keytool " + keycmd + " -storetype \"" + storetype + "\" -keystore \"" + keystore +
"\" -storepass \"" + password + "\" -alias \"" + keyalias + "\" " + keypass)
for opt, value in other_opts:
19b58bab Rémy Ménard
if value:
value = " \"" + value + "\""
cmd += " " + opt + value
if sh_exec(cmd):
putDoneOK()
else:
putDoneFail()


def execSrcToDestKeyTool(msg, keycmd, srcstoretype, srckeystore, srcstorepass, srcalias, deststoretype, destkeystore, deststorepass, deststorealias, other_opts):
putWait(msg)
cmd = ("keytool " + keycmd + " -srcstoretype \"" + srcstoretype + "\" -srckeystore \"" + srckeystore +
"\" -srcstorepass \"" + srcstorepass + "\" -srcalias \""+ srcalias +
"\" -deststoretype \"" + deststoretype + "\" -destkeystore \"" + destkeystore +
"\" -deststorepass \"" + deststorepass + "\" -destalias \"" + deststorealias + "\"")
for opt, value in other_opts:
if value:
value = " \"" + value + "\""
bf9c3717 Rémy Ménard
cmd += " " + opt + value
if sh_exec(cmd):
putDoneOK()
else:
putDoneFail()


def execSrcToDestOpenssl(msg, keycmd, srckeystore, srcstorepass, destkeystore, deststorepass, other_opts):
putWait(msg)
cmd = ("openssl " + keycmd + " -in \"" + srckeystore + "\" -passin pass:\"" + srcstorepass +
"\" -out \"" + destkeystore + "\" -passout pass:\"" + deststorepass + "\"")
for opt, value in other_opts:
if value:
value = " \"" + value + "\""
cmd += " " + opt + value
if sh_exec(cmd):
putDoneOK()
else:
putDoneFail()


def execOpenssl(msg, keycmd, other_opts):
putWait(msg)
cmd = ("openssl " + keycmd)
for opt, value in other_opts:
if value:
value = " \"" + value + "\""
19b58bab Rémy Ménard
cmd += " " + opt + value
96454bcd Sylvain L. Sauvage
if sh_exec(cmd):
putDoneOK()
else:
putDoneFail()


2e0a7cb1 Sylvain L. Sauvage
# File and Shell Utilities

def sh_rm(filename):
try:
putWait("Deleting " + filename)
os.remove(filename)
putDoneOK()
except Exception as e:
putDoneFail(error=e)


def sh_rm_r(dirname):
try:
if dirname[-1] != "/":
dirname += "/"
putWait("Deleting " + dirname)
shutil.rmtree(dirname)
putDoneOK()
except Exception as e:
putDoneFail(error=e)


def sh_cp(orig, dest):
try:
putWait("Copying " + orig + " to " + dest)
shutil.copy(orig, dest)
putDoneOK()
except Exception as e:
putDoneFail(error=e)


def sh_touch(filename):
# just making sure the file exists
with open(filename, "a") as touch:
pass


def sh_mkdir_p(path):
try:
os.makedirs(path)
except:
# we don’t care if the path already exists
pass


def sh_pwd():
return os.getcwd()


def sh_exec(cmd):
with open("install.log", "a") as logfile:
logfile.write("\n## executing <" + cmd + ">:\n")
96454bcd Sylvain L. Sauvage
return os.system(cmd + " >>install.log 2>&1") == 0
2e0a7cb1 Sylvain L. Sauvage

def waitForFile(filename):
putWait("Waiting for " + filename)
while not os.path.exists(filename):
time.sleep(1)
putDoneOK()


def writeFile(msg, filename, content):
putWait(msg)
with open(filename, "w") as wfile:
wfile.write(content)
putDoneOK()


# Input/Output Utilities

def putTitle(title):
print "[ ]"
print "[ ]\033[1m " + title + "\033[0m"
print "[ ]"


def putMessage(msg):
for line in msg.split("\n"):
print "[\033[1;34minfo\033[0m] " + line


def putError(msg, error=None):
if SHOW_TRACEBACK:
print ""
if error:
print error
traceback.print_exc()
for line in msg.split("\n"):
print "[\033[1;31mFAIL\033[0m] " + line
if HALT_ON_ERROR:
sys.exit(-1)


def putAgain(msg):
for line in msg.split("\n"):
print "[\033[1;31mfail\033[0m] " + line


def putSuccess(msg):
for line in msg.split("\n"):
print "[\033[0;32m ok \033[0m] " + line


def putWarning(msg):
for line in msg.split("\n"):
print "[\033[0;33mWARN\033[0m] " + line


def putWait(msg):
print "[\033[0;34m....\033[0m] " + msg,
sys.stdout.flush()


def putDoneOK(note=None):
putDone(note)
putSuccess("")


def putDoneFail(note=None, error=None):
putDone(note)
putError("", error)


def putDone(note):
if note:
print note,
sys.stdout.write("\r")


def ask(question):
return raw_input("[ ? ] " + question)


def getYN(question, default_value=None):
valid = { 'y': True, 'yes': True, 'n': False, 'no': False }
if default_value != None:
if not default_value in [ True, False ]:
default_value = str(default_value).lower() == "true"
valid[''] = default_value

prompt = { True: " (YES/no) ", False: " (yes/NO) ", None: " (Yes/No) " }
question += prompt[default_value]

while True:
response = ask(question).lower()
if response in valid:
return valid[response]
putWarning("Please answer 'Yes' or 'No' (or 'y' or 'n').")


def getWithDefault(question, value):
question += ": "
readline.set_startup_hook(lambda: readline.insert_text(value))
try:
return ask(question)
finally:
readline.set_startup_hook()


def getPathWithDefault(question, value):
while True:
path = getWithDefault(question, value)
if os.path.exists(path) and os.path.isdir(path):
if path[-1] != "/":
path += "/"
return path
else:
putAgain(path + " is not a valid folder path!")


def getFileWithDefault(question, value):
while True:
path = getWithDefault(question, value)
if os.path.exists(path) and os.path.isfile(path):
return path;
else:
putAgain(path + " does not exist!")


def getSetConfig(question, section, option, reader=getWithDefault):
value = CONFIG.get(section, option)
if CONFIG.isTrue("global", "accept_defaults"):
putMessage(question + " : using <" + value + ">")
return value
new_value = reader(question, value)
CONFIG.set(section, option, new_value)
return new_value


def getSetConfigYN(question, section, option):
value = getSetConfig(question, section, option, getYN)
return str(value).lower() == "true"


def getSetConfigPath(question, section, option):
return getSetConfig(question, section, option, getPathWithDefault)


def getSetConfigFile(question, section, option):
return getSetConfig(question, section, option, getFileWithDefault)


def getSetConfigType(question, section, option, gstype=None):
types = { "YN": getSetConfigYN,
"file": getSetConfigFile,
"path": getSetConfigPath }
func = getSetConfig
if gstype in types:
func = types[gstype]
return func(question, section, option)