Commit 5f34b3f6 authored by Marco Mariani's avatar Marco Mariani

some pep8 love

parent 17a77af3
......@@ -21,8 +21,7 @@ class Parser(OptionParser):
"""
Initialize all possible options.
"""
OptionParser.__init__(self, usage=usage, version=version,
option_list=[
option_list = [
Option("-l", "--log_file",
help="The path to the log file used by the script.",
type=str),
......@@ -38,7 +37,10 @@ class Parser(OptionParser):
default=False,
action="store_true",
help="Debug mode."),
])
]
OptionParser.__init__(self, usage=usage, version=version,
option_list=option_list)
def check_args(self):
"""
......@@ -50,6 +52,7 @@ class Parser(OptionParser):
return options, args[0]
class Config:
def __init__(self):
self.configuration_file_path = None
......@@ -125,6 +128,7 @@ def run():
sys.exit(return_code)
def serve(config):
from views import app
from werkzeug.contrib.fixers import ProxyFix
......@@ -134,7 +138,7 @@ def serve(config):
app.config.update(
software_log=config.software_root.rstrip('/') + '.log',
instance_log=config.instance_root.rstrip('/') + '.log',
workspace = workdir,
workspace=workdir,
software_link=software_link,
instance_profile='instance.cfg',
software_profile='software.cfg',
......
......@@ -11,4 +11,3 @@ def as_json(f):
def inner(*args, **kwargs):
return Response(json.dumps(f(*args, **kwargs)), mimetype='application/json')
return inner
......@@ -31,19 +31,19 @@ class FileBrowser(object):
html = 'var gsdirs = [], gsfiles = [];'
dir = urllib.unquote(dir)
# 'dir' is used below. XXX should not shadow a builtin name
# XXX-Marco 'dir' and 'all' should not shadow builtin names
realdir = realpath(self.config, dir)
if not realdir:
raise NameError('Could not load directory %s: Permission denied' % dir)
ldir = sorted(os.listdir(realdir), key=str.lower)
for f in ldir:
if f.startswith('.') and not all: #do not display this file/folder
if f.startswith('.') and not all: # do not display this file/folder
continue
ff = os.path.join(dir, f)
realfile = os.path.join(realdir, f)
mdate = datetime.datetime.fromtimestamp(os.path.getmtime(realfile)
).strftime("%Y-%d-%m %I:%M")
).strftime("%Y-%d-%m %I:%M")
md5sum = md5.md5(realfile).hexdigest()
if not os.path.isdir(realfile):
size = os.path.getsize(realfile)
......@@ -61,7 +61,6 @@ class FileBrowser(object):
ff + '", "0", "' + md5sum + '", "dir", "' + mdate + '"));'
return html
def makeDirectory(self, dir, filename):
"""Create a directory"""
realdir = self._realdir(dir)
......@@ -72,7 +71,6 @@ class FileBrowser(object):
else:
return '{result: \'0\'}'
def makeFile(self, dir, filename):
"""Create a file in a directory dir taken"""
realdir = self._realdir(dir)
......@@ -85,17 +83,19 @@ class FileBrowser(object):
def deleteItem(self, dir, files):
"""Delete a list of files or directories"""
# XXX-Marco do not shadow 'dir'
realdir = self._realdir(dir)
lfiles = urllib.unquote(files).split(',,,')
try:
# XXX-Marco do not shadow 'file'
for file in lfiles:
file = os.path.join(realdir, file)
if not os.path.exists(file):
continue #silent skip file....
continue # silent skip file....
details = file.split('/')
last = details[-1]
if last and last.startswith('.'):
continue #cannot delete this file/directory, to prevent security
continue # cannot delete this file/directory, to prevent security
if os.path.isdir(file):
shutil.rmtree(file)
else:
......@@ -109,6 +109,7 @@ class FileBrowser(object):
realdir = self._realdir(dir)
lfiles = urllib.unquote(files).split(',,,')
try:
# XXX-Marco do not shadow 'file'
for file in lfiles:
realfile = realpath(self.config, file)
if not realfile:
......
......@@ -29,7 +29,7 @@ def cloneRepo(data):
json = ""
try:
if os.path.exists(workDir) and len(os.listdir(workDir)) < 2:
shutil.rmtree(workDir) #delete useless files
shutil.rmtree(workDir) # delete useless files
repo = Repo.clone_from(data["repo"], workDir)
config_writer = repo.config_writer()
config_writer.add_section("user")
......@@ -42,6 +42,7 @@ def cloneRepo(data):
json = safeResult(str(e))
return jsonify(code=code, result=json)
def gitStatus(project):
"""Run git status and return status of specified project folder
Args:
......@@ -61,6 +62,7 @@ def gitStatus(project):
json = safeResult(str(e))
return jsonify(code=code, result=json, branch=branch, dirty=isdirty)
def switchBranch(project, name):
"""Switch a git branch
Args:
......@@ -76,13 +78,14 @@ def switchBranch(project, name):
if name == current_branch:
json = "This is already your active branch for this project"
else:
git = repo.git
git = repo.git
git.checkout(name)
code = 1
except Exception as e:
json = safeResult(str(e))
return jsonify(code=code, result=json)
def addBranch(project, name, onlyCheckout=False):
"""Add new git branch to the repository
Args:
......@@ -95,7 +98,7 @@ def addBranch(project, name, onlyCheckout=False):
json = ""
try:
repo = Repo(project)
git = repo.git
git = repo.git
if not onlyCheckout:
git.checkout('-b', name)
else:
......@@ -105,6 +108,7 @@ def addBranch(project, name, onlyCheckout=False):
json = safeResult(str(e))
return jsonify(code=code, result=json)
def getDiff(project):
"""Get git diff for the specified project directory"""
result = ""
......@@ -117,6 +121,7 @@ def getDiff(project):
result = safeResult(str(e))
return result
def gitPush(project, msg):
"""Commit and Push changes for the specified repository
Args:
......@@ -145,10 +150,11 @@ def gitPush(project, msg):
code = 1
except Exception as e:
if undo_commit:
git.reset("HEAD~") #undo previous commit
git.reset("HEAD~") # undo previous commit
json = safeResult(str(e))
return jsonify(code=code, result=json)
def gitPull(project):
result = ""
code = 0
......@@ -161,6 +167,7 @@ def gitPull(project):
result = safeResult(str(e))
return jsonify(code=code, result=result)
def safeResult(result):
"""Parse string and remove credential of the user"""
regex = re.compile("(https:\/\/)([\w\d\._-]+:[\w\d\._-]+)\@([\S]+\s)", re.VERBOSE)
......
......@@ -18,6 +18,7 @@ from slapos.runner.process import killRunningProcess, isRunning
from slapos.runner import views
import slapos.slap
#Helpers
def loadJson(response):
return json.loads(response.data)
......@@ -48,6 +49,7 @@ class Config:
if not getattr(self, key, None):
setattr(self, key, configuration_dict[key])
class SlaprunnerTestCase(unittest.TestCase):
def setUp(self):
......@@ -57,8 +59,8 @@ class SlaprunnerTestCase(unittest.TestCase):
self.updateUser = ["newslapuser", "newslappwd", "slaprunner@nexedi.com", "SlapOS web runner"]
self.rcode = "41bf2657"
self.repo = 'http://git.erp5.org/repos/slapos.git'
self.software = "workspace/slapos/software/" #relative directory fo SR
self.project = 'slapos' #Default project name
self.software = "workspace/slapos/software/" # relative directory fo SR
self.project = 'slapos' # Default project name
self.template = 'template.cfg'
self.partitionPrefix = 'slappart'
self.slaposBuildout = "1.6.0-dev-SlapOS-010"
......@@ -77,7 +79,7 @@ class SlaprunnerTestCase(unittest.TestCase):
views.app.config.update(
software_log=config.software_root.rstrip('/') + '.log',
instance_log=config.instance_root.rstrip('/') + '.log',
workspace = workdir,
workspace=workdir,
software_link=software_link,
instance_profile='instance.cfg',
software_profile='software.cfg',
......@@ -117,20 +119,24 @@ class SlaprunnerTestCase(unittest.TestCase):
def configAccount(self, username, password, email, name, rcode):
"""Helper for configAccount"""
return self.app.post('/configAccount', data=dict(
username=username,
password=password,
email=email,
name=name,
rcode=rcode
), follow_redirects=True)
return self.app.post('/configAccount',
data=dict(
username=username,
password=password,
email=email,
name=name,
rcode=rcode
),
follow_redirects=True)
def login(self, username, password):
"""Helper for Login method"""
return self.app.post('/doLogin', data=dict(
clogin=username,
cpwd=password
), follow_redirects=True)
return self.app.post('/doLogin',
data=dict(
clogin=username,
cpwd=password
),
follow_redirects=True)
def setAccount(self):
"""Initialize user account and log user in"""
......@@ -146,13 +152,15 @@ class SlaprunnerTestCase(unittest.TestCase):
def updateAccount(self, newaccount, rcode):
"""Helper for update user account data"""
return self.app.post('/updateAccount', data=dict(
username=newaccount[0],
password=newaccount[1],
email=newaccount[2],
name=newaccount[3],
rcode=rcode
), follow_redirects=True)
return self.app.post('/updateAccount',
data=dict(
username=newaccount[0],
password=newaccount[1],
email=newaccount[2],
name=newaccount[3],
rcode=rcode
),
follow_redirects=True)
def getCurrentSR(self):
return getProfilePath(self.app.config['etc_dir'],
......@@ -189,14 +197,15 @@ class SlaprunnerTestCase(unittest.TestCase):
"""Helper for setup compiled software release dir"""
self.setupProjectFolder(withSoftware=True)
md5 = hashlib.md5(os.path.join(self.app.config['workspace'],
"slapos/software/slaprunner-test", self.app.config['software_profile'])
).hexdigest()
"slapos/software/slaprunner-test",
self.app.config['software_profile'])
).hexdigest()
base = os.path.join(self.app.config['software_root'], md5)
template = os.path.join(base, self.template)
content = "[buildout]\n"
content += "parts = \n create-file\n\n"
content += "eggs-directory = %s\n" % os.path.join(base, 'eggs')
content += "develop-eggs-directory = %s\n\n" % os.path.join(base, 'develop-eggs')
content += "develop-eggs-directory = %s\n\n" % os.path.join(base, 'develop-eggs')
content += "[create-file]\nrecipe = plone.recipe.command\n"
content += "filename = ${buildout:directory}/etc\n"
content += "command = mkdir ${:filename} && echo 'simple file' > ${:filename}/testfile\n"
......@@ -208,7 +217,6 @@ class SlaprunnerTestCase(unittest.TestCase):
"""Kill slapproxy process"""
killRunningProcess('slapproxy', recursive=True)
#Begin test case here
def test_wrong_login(self):
"""Test Login user before create session. This should return error value"""
......@@ -266,12 +274,16 @@ class SlaprunnerTestCase(unittest.TestCase):
"""Start scenario 1 for deploying SR: Clone a project from git repository"""
self.setAccount()
folder = 'workspace/' + self.project
data = {"repo":self.repo, "user":'Slaprunner test',
"email":'slaprunner@nexedi.com', "name":folder}
data = {
'repo': self.repo,
'user': 'Slaprunner test',
'email': 'slaprunner@nexedi.com',
'name': folder
}
response = loadJson(self.app.post('/cloneRepository', data=data,
follow_redirects=True))
self.assertEqual(response['result'], "")
#Get realpath of create project
# Get realpath of create project
path_data = dict(file=folder)
response = loadJson(self.app.post('/getPath', data=path_data,
follow_redirects=True))
......@@ -281,11 +293,13 @@ class SlaprunnerTestCase(unittest.TestCase):
config = open(os.path.join(realFolder, '.git/config'), 'r').read()
assert "slaprunner@nexedi.com" in config and "Slaprunner test" in config
#Checkout to slaprunner branch, this supose that branch slaprunner exit
response = loadJson(self.app.post('/newBranch', data=dict(
project=folder,
create='0',
name='slaprunner'),
follow_redirects=True))
response = loadJson(self.app.post('/newBranch',
data=dict(
project=folder,
create='0',
name='slaprunner'
),
follow_redirects=True))
self.assertEqual(response['result'], "")
self.logout()
......@@ -296,8 +310,8 @@ class SlaprunnerTestCase(unittest.TestCase):
self.setupProjectFolder()
newSoftware = os.path.join(self.software, 'slaprunner-test')
response = loadJson(self.app.post('/createSoftware',
data=dict(folder=newSoftware),
follow_redirects=True))
data=dict(folder=newSoftware),
follow_redirects=True))
self.assertEqual(response['result'], "")
currentSR = self.getCurrentSR()
assert newSoftware in currentSR
......@@ -308,10 +322,10 @@ class SlaprunnerTestCase(unittest.TestCase):
self.test_cloneProject()
#Login
self.login(self.users[0], self.users[1])
software = os.path.join(self.software, 'drupal') #Drupal SR must exist in SR folder
software = os.path.join(self.software, 'drupal') # Drupal SR must exist in SR folder
response = loadJson(self.app.post('/setCurrentProject',
data=dict(path=software),
follow_redirects=True))
data=dict(path=software),
follow_redirects=True))
self.assertEqual(response['result'], "")
currentSR = self.getCurrentSR()
assert software in currentSR
......@@ -340,15 +354,15 @@ class SlaprunnerTestCase(unittest.TestCase):
softwareRelease += "filename = slapos.git\n"
softwareRelease += "download-only = true\n"
response = loadJson(self.app.post('/saveFileContent',
data=dict(file=newSoftware,
content=softwareRelease),
follow_redirects=True))
data=dict(file=newSoftware,
content=softwareRelease),
follow_redirects=True))
self.assertEqual(response['result'], "")
#Compile software and wait until slapgrid it end
#this is supose to use curent SR
response = loadJson(self.app.post('/runSoftwareProfile',
data=dict(),
follow_redirects=True))
data=dict(),
follow_redirects=True))
self.assertTrue(response['result'])
self.assertTrue(os.path.exists(self.app.config['software_root']))
self.assertTrue(os.path.exists(self.app.config['software_log']))
......@@ -369,8 +383,8 @@ class SlaprunnerTestCase(unittest.TestCase):
#Set current projet and run Slapgrid-cp
software = os.path.join(self.software, 'slaprunner-test')
response = loadJson(self.app.post('/setCurrentProject',
data=dict(path=software),
follow_redirects=True))
data=dict(path=software),
follow_redirects=True))
self.assertEqual(response['result'], "")
self.proxyStatus(True)
#Send paramters for the instance
......@@ -380,9 +394,9 @@ class SlaprunnerTestCase(unittest.TestCase):
parameterXml += '<parameter id="cacountry">France</parameter>\n</instance>'
software_type = 'production'
response = loadJson(self.app.post('/saveParameterXml',
data=dict(parameter=parameterXml,
software_type=software_type),
follow_redirects=True))
data=dict(parameter=parameterXml,
software_type=software_type),
follow_redirects=True))
self.assertEqual(response['result'], "")
slap = slapos.slap.slap()
slap.initializeConnection(self.app.config['master_url'])
......@@ -391,8 +405,8 @@ class SlaprunnerTestCase(unittest.TestCase):
self.assertNotEqual(partitionList, [])
#Assume that the requested partition is partition 0
slapParameterDict = partitionList[0].getInstanceParameterDict()
self.assertTrue(slapParameterDict.has_key('appname'))
self.assertTrue(slapParameterDict.has_key('cacountry'))
self.assertTrue('appname' in slapParameterDict)
self.assertTrue('cacountry' in slapParameterDict)
self.assertEqual(slapParameterDict['appname'], 'slaprunnerTest')
self.assertEqual(slapParameterDict['cacountry'], 'France')
self.assertEqual(slapParameterDict['slap_software_type'], 'production')
......@@ -413,13 +427,13 @@ class SlaprunnerTestCase(unittest.TestCase):
self.proxyStatus(False, sleep_time=1)
#run Software profile
response = loadJson(self.app.post('/runSoftwareProfile',
data=dict(),
follow_redirects=True))
data=dict(),
follow_redirects=True))
self.assertTrue(response['result'])
#run instance profile
response = loadJson(self.app.post('/runInstanceProfile',
data=dict(),
follow_redirects=True))
data=dict(),
follow_redirects=True))
self.assertTrue(response['result'])
#Check that all partitions has been created
assert "create-file" in open(self.app.config['instance_log'], 'r').read()
......@@ -439,6 +453,7 @@ class SlaprunnerTestCase(unittest.TestCase):
self.stopSlapproxy()
self.logout()
def main():
# Empty parser for now - so that erp5testnode is happy when doing --help
parser = argparse.ArgumentParser()
......
......@@ -33,10 +33,12 @@ html_escape_table = {
"<": "&lt;",
}
def html_escape(text):
"""Produce entities within text."""
return "".join(html_escape_table.get(c, c) for c in text)
def getSession(config):
"""
Get the session data of current user.
......@@ -53,6 +55,7 @@ def getSession(config):
return False
return user
def saveSession(config, account):
"""
Save account information for the current user
......@@ -74,7 +77,7 @@ def saveSession(config, account):
f = open(user, 'r')
#backup previous data
data = f.read()
open(user+'.back', 'w').write(data)
open('%s.back' % user, 'w').write(data)
f.close()
backup = True
if not account[1]:
......@@ -94,11 +97,12 @@ def saveSession(config, account):
try:
if backup:
os.remove(user)
os.rename(user+'.back', user)
os.rename('%s.back' % user, user)
except:
pass
return str(e)
def getCurrentSoftwareReleaseProfile(config):
"""
Returns used Software Release profile as a string.
......@@ -111,6 +115,7 @@ def getCurrentSoftwareReleaseProfile(config):
except:
return False
def requestInstance(config, software_type=None):
"""
Request the main instance of our environment
......@@ -131,7 +136,7 @@ def requestInstance(config, software_type=None):
param_path = os.path.join(config['etc_dir'], ".parameter.xml")
xml_result = readParameters(param_path)
partition_parameter_kw = None
if type(xml_result) != type('') and xml_result.has_key('instance'):
if type(xml_result) != type('') and 'instance' in xml_result:
partition_parameter_kw = xml_result['instance']
return slap.registerOpenOrder().request(
......@@ -143,6 +148,7 @@ def requestInstance(config, software_type=None):
state=None,
shared=False)
def updateProxy(config):
"""
Configure Slapos Node computer and partitions.
......@@ -158,27 +164,33 @@ def updateProxy(config):
computer = slap.registerComputer(config['computer_id'])
prefix = 'slappart'
slap_config = {
'address': config['ipv4_address'],
'instance_root': config['instance_root'],
'netmask': '255.255.255.255',
'partition_list': [],
'reference': config['computer_id'],
'software_root': config['software_root']}
'address': config['ipv4_address'],
'instance_root': config['instance_root'],
'netmask': '255.255.255.255',
'partition_list': [],
'reference': config['computer_id'],
'software_root': config['software_root']
}
for i in xrange(0, int(config['partition_amount'])):
partition_reference = '%s%s' % (prefix, i)
partition_path = os.path.join(config['instance_root'], partition_reference)
if not os.path.exists(partition_path):
os.mkdir(partition_path)
os.chmod(partition_path, 0750)
slap_config['partition_list'].append({'address_list': [{'addr': config['ipv4_address'],
'netmask': '255.255.255.255'},
{'addr': config['ipv6_address'],
'netmask': 'ffff:ffff:ffff::'},
],
'path': partition_path,
'reference': partition_reference,
'tap': {'name': partition_reference},
})
slap_config['partition_list'].append({
'address_list': [
{
'addr': config['ipv4_address'],
'netmask': '255.255.255.255'
}, {
'addr': config['ipv6_address'],
'netmask': 'ffff:ffff:ffff::'
},
],
'path': partition_path,
'reference': partition_reference,
'tap': {'name': partition_reference}})
computer.updateConfiguration(xml_marshaller.xml_marshaller.dumps(slap_config))
return True
......@@ -219,6 +231,7 @@ def removeProxyDb(config):
if os.path.exists(config['database_uri']):
os.unlink(config['database_uri'])
def isSoftwareRunning(config=None):
"""
Return True if slapgrid-sr is still running and false if slapgrid if not
......@@ -263,13 +276,14 @@ def config_SR_folder(config):
"""Create a symbolik link for each folder in software folder. That allow
user to customize software release folder"""
list = []
# XXX-Marco do not shadow 'list'
config_name = 'slaprunner.config'
for path in os.listdir(config['software_link']):
cfg_path = os.path.join(config['software_link'], path, config_name)
if os.path.exists(cfg_path):
cfg = open(cfg_path, 'r').read().split("#")
if len(cfg) != 2:
continue #there is a broken config file
continue # there is a broken config file
list.append(cfg[1])
folder_list = os.listdir(config['software_root'])
if len(folder_list) < 1:
......@@ -280,7 +294,7 @@ def config_SR_folder(config):
name = projects[len(projects) - 2]
for folder in folder_list:
if folder in list:
continue #this folder is already registered
continue # this folder is already registered
else:
if not os.path.exists(os.path.join(config['software_link'], name)):
destination = os.path.join(config['software_link'], name)
......@@ -292,9 +306,10 @@ def config_SR_folder(config):
os.symlink(source, destination)
#write config file
cf = open(cfg, 'w')
cf.write(curent_project+"#"+folder)
cf.write(curent_project + "#" + folder)
cf.close()
def loadSoftwareRList(config):
"""Return list (of dict) of Software Release from symbolik SR folder"""
list = []
......@@ -304,10 +319,11 @@ def loadSoftwareRList(config):
if os.path.exists(cfg_path):
cfg = open(cfg_path, 'r').read().split("#")
if len(cfg) != 2:
continue #there is a broken config file
continue # there is a broken config file
list.append(dict(md5=cfg[1], path=cfg[0], title=path))
return list
def isInstanceRunning(config=None):
"""
Return True if slapgrid-cp is still running and False otherwise
......@@ -353,6 +369,7 @@ def getProfilePath(projectDir, profile):
projectFolder = open(os.path.join(projectDir, ".project")).read()
return os.path.join(projectFolder, profile)
def getSlapStatus(config):
"""Return all Slapos Partitions with associate information"""
slap = slapos.slap.slap()
......@@ -372,11 +389,13 @@ def getSlapStatus(config):
partition_list.append((slappart_id, []))
return partition_list
def svcStopAll(config):
"""Stop all Instance process on this computer"""
return Popen([config['supervisor'], config['configuration_file_path'],
'shutdown']).communicate()[0]
def removeInstanceRoot(config):
"""Clean instance directory and stop all its running process"""
if os.path.exists(config['instance_root']):
......@@ -384,11 +403,12 @@ def removeInstanceRoot(config):
for root, dirs, _ in os.walk(config['instance_root']):
for fname in dirs:
fullPath = os.path.join(root, fname)
if not os.access(fullPath, os.W_OK) :
if not os.access(fullPath, os.W_OK):
# Some directories may be read-only, preventing to remove files in it
os.chmod(fullPath, 0744)
shutil.rmtree(config['instance_root'])
def getSvcStatus(config):
"""Return all Softwares Instances process Information"""
result = Popen([config['supervisor'], config['configuration_file_path'],
......@@ -397,10 +417,11 @@ def getSvcStatus(config):
supervisord = []
for item in result.split('\n'):
if item.strip() != "":
if re.search(regex, item, re.IGNORECASE) == None:
if re.search(regex, item, re.IGNORECASE) is None:
supervisord.append(re.split('[\s,]+', item))
return supervisord
def getSvcTailProcess(config, process):
"""Get log for the specifie process
......@@ -413,6 +434,7 @@ def getSvcTailProcess(config, process):
return Popen([config['supervisor'], config['configuration_file_path'],
"tail", process]).communicate()[0]
def svcStartStopProcess(config, process, action):
"""Send start or stop process command to supervisord
......@@ -421,10 +443,17 @@ def svcStartStopProcess(config, process, action):
process: process to start or stop.
action: current state which is used to generate the new process state.
"""
cmd = {"RESTART":"restart", "STOPPED":"start", "RUNNING":"stop", "EXITED":"start", "STOP":"stop"}
cmd = {
'RESTART': 'restart',
'STOPPED': 'start',
'RUNNING': 'stop',
'EXITED': 'start',
'STOP': 'stop'
}
return Popen([config['supervisor'], config['configuration_file_path'],
cmd[action], process]).communicate()[0]
def getFolderContent(config, folder):
"""
Read all file and folder into specified directory
......@@ -449,13 +478,13 @@ def getFolderContent(config, folder):
ldir = []
for f in ldir:
if f.startswith('.'): #do not displays this file/folder
if f.startswith('.'): # do not displays this file/folder
continue
ff = os.path.join(d, f)
if os.path.isdir(os.path.join(realdir, f)):
r.append('<li class="directory collapsed"><a href="#%s" rel="%s/">%s</a></li>' % (ff, ff, f))
else:
e = os.path.splitext(f)[1][1:] # get .ext and remove dot
e = os.path.splitext(f)[1][1:] # get .ext and remove dot
r.append('<li class="file ext_%s"><a href="#%s" rel="%s">%s</a></li>' % (e, ff, ff, f))
r.append('</ul>')
except Exception as e:
......@@ -463,6 +492,7 @@ def getFolderContent(config, folder):
r.append('</ul>')
return jsonify(result=''.join(r))
def getFolder(config, folder):
"""
Read list of folder for the specified directory
......@@ -486,7 +516,7 @@ def getFolder(config, folder):
else:
ldir = sorted(os.listdir(realdir), key=str.lower)
for f in ldir:
if f.startswith('.'): #do not display this file/folder
if f.startswith('.'): # do not display this file/folder
continue
ff = os.path.join(d, f)
if os.path.isdir(os.path.join(realdir, f)):
......@@ -497,6 +527,7 @@ def getFolder(config, folder):
r.append('</ul>')
return jsonify(result=''.join(r))
def getProjectList(folder):
"""Return the list of projet (folder) into the workspace
......@@ -512,6 +543,7 @@ def getProjectList(folder):
project.append(elt)
return project
def configNewSR(config, projectpath):
"""Configure a Software Release as current Software Release
......@@ -539,6 +571,7 @@ def configNewSR(config, projectpath):
else:
return False
def newSoftware(folder, config, session):
"""
Create a new Software Release folder with default profiles
......@@ -582,6 +615,7 @@ def newSoftware(folder, config, session):
shutil.rmtree(folderPath)
return jsonify(code=code, result=json)
def checkSoftwareFolder(path, config):
"""Check id `path` is a valid Software Release folder"""
realdir = realpath(config, path)
......@@ -589,6 +623,7 @@ def checkSoftwareFolder(path, config):
return jsonify(result=path)
return jsonify(result="")
def getProjectTitle(config):
"""Generate the name of the current software Release (for slaprunner UI)"""
conf = os.path.join(config['etc_dir'], ".project")
......@@ -598,6 +633,7 @@ def getProjectTitle(config):
return '%s (%s)' % (software, '/'.join(project[:-2]))
return "No Profile"
def getSoftwareReleaseName(config):
"""Get the name of the current Software Release"""
sr_profile = os.path.join(config['etc_dir'], ".project")
......@@ -607,6 +643,7 @@ def getSoftwareReleaseName(config):
return software.replace(' ', '_')
return "No_name"
def removeSoftwareByName(config, md5, folderName):
"""Remove all content of the software release specified by md5
......@@ -622,12 +659,13 @@ def removeSoftwareByName(config, md5, folderName):
raise Exception("Cannot remove software Release: No such file or directory")
if not os.path.exists(linkpath):
raise Exception("Cannot remove software Release: No such file or directory %s" %
('software_root/'+folderName))
('software_root/' + folderName))
svcStopAll(config)
os.unlink(linkpath)
shutil.rmtree(path)
return loadSoftwareRList(config)
def tail(f, lines=20):
"""
Returns the last `lines` lines of file `f`. It is an implementation of tail -f n.
......@@ -655,6 +693,7 @@ def tail(f, lines=20):
block -= 1
return '\n'.join(''.join(data).splitlines()[-lines:])
def readFileFrom(f, lastPosition, limit=20000):
"""
Returns the last lines of file `f`, from position lastPosition.
......@@ -663,22 +702,23 @@ def readFileFrom(f, lastPosition, limit=20000):
"""
BUFSIZ = 1024
f.seek(0, 2)
# XXX-Marco do now shadow 'bytes'
bytes = f.tell()
block = -1
data = ""
length = bytes
truncated = False #True if a part of log data has been truncated
if (lastPosition <= 0 and length > limit) or (length-lastPosition > limit):
truncated = False # True if a part of log data has been truncated
if (lastPosition <= 0 and length > limit) or (length - lastPosition > limit):
lastPosition = length - limit
truncated = True
size = bytes - lastPosition
while bytes > lastPosition:
if abs(block*BUFSIZ) <= size:
if abs(block * BUFSIZ) <= size:
# Seek back one whole BUFSIZ
f.seek(block * BUFSIZ, 2)
data = f.read(BUFSIZ) + data
else:
margin = abs(block*BUFSIZ) - size
margin = abs(block * BUFSIZ) - size
if length < BUFSIZ:
f.seek(0, 0)
else:
......@@ -688,7 +728,12 @@ def readFileFrom(f, lastPosition, limit=20000):
bytes -= BUFSIZ
block -= 1
f.close()
return {"content":data, "position":length, "truncated":truncated}
return {
'content': data,
'position': length,
'truncated': truncated
}
def isText(file):
"""Return True if the mimetype of file is Text"""
......@@ -701,6 +746,7 @@ def isText(file):
except:
return False
def md5sum(file):
"""Compute md5sum of `file` and return hexdigest value"""
if os.path.isdir(file):
......@@ -717,6 +763,7 @@ def md5sum(file):
except:
return False
def realpath(config, path, check_exist=True):
"""
Get realpath of path or return False if user is not allowed to access to
......@@ -724,20 +771,25 @@ def realpath(config, path, check_exist=True):
"""
split_path = path.split('/')
key = split_path[0]
allow_list = {'software_root':config['software_root'], 'instance_root':
config['instance_root'], 'workspace': config['workspace'],
'software_link':config['software_link']}
if allow_list.has_key(key):
del split_path[0]
path = os.path.join(allow_list[key], *split_path)
if check_exist:
if os.path.exists(path):
return path
else:
return False
else:
allow_list = {
'software_root': config['software_root'],
'instance_root': config['instance_root'],
'workspace': config['workspace'],
'software_link': config['software_link']
}
if key not in allow_list:
return False
del split_path[0]
path = os.path.join(allow_list[key], *split_path)
if check_exist:
if os.path.exists(path):
return path
return False
else:
return False
else:
return path
def readParameters(path):
"""Read Instance parameters stored into a local file.
......@@ -755,7 +807,7 @@ def readParameters(path):
sub_obj = {}
for subnode in elt.childNodes:
if subnode.nodeType != subnode.TEXT_NODE:
sub_obj[str(subnode.getAttribute('id'))] = subnode.childNodes[0].data #.decode('utf-8').decode('utf-8')
sub_obj[str(subnode.getAttribute('id'))] = subnode.childNodes[0].data # .decode('utf-8').decode('utf-8')
obj[str(elt.tagName)] = sub_obj
return obj
except Exception, e:
......
......@@ -41,9 +41,11 @@ file_request = FileBrowser(app.config)
import logging
logger = logging.getLogger('werkzeug')
def login_redirect(*args, **kwargs):
return redirect(url_for('login'))
#Access Control: Only static files and login pages are allowed to guest
@app.before_request
def before_request():
......@@ -67,15 +69,18 @@ def before_request():
def home():
return render_template('index.html')
# general views
@login_required()
def browseWorkspace():
return render_template('workspace.html')
@app.route("/login")
def login():
return render_template('login.html')
@app.route("/setAccount")
def setAccount():
account = getSession(app.config)
......@@ -83,17 +88,20 @@ def setAccount():
return render_template('account.html')
return redirect(url_for('login'))
@login_required()
def myAccount():
account = getSession(app.config)
return render_template('account.html', username=account[0],
email=account[2], name=account[3].decode('utf-8'))
@app.route("/dologout")
def dologout():
_ = logout()
return redirect(url_for('login'))
@login_required()
def configRepo():
public_key = open(app.config['public_key'], 'r').read()
......@@ -102,6 +110,7 @@ def configRepo():
public_key=public_key, name=account[3].decode('utf-8'),
email=account[2])
@app.route("/doLogin", methods=['POST'])
def doLogin():
username = request.form['clogin']
......@@ -111,6 +120,7 @@ def doLogin():
return jsonify(code=1, result="")
return jsonify(code=0, result="Login or password is incorrect, please check it!")
# software views
@login_required()
def editSoftwareProfile():
......@@ -120,11 +130,13 @@ def editSoftwareProfile():
return render_template('updateSoftwareProfile.html', workDir='workspace',
profile=profile, projectList=getProjectList(app.config['workspace']))
@login_required()
def inspectSoftware():
return render_template('runResult.html', softwareRoot='software_link/',
softwares=loadSoftwareRList(app.config))
#remove content of compiled software release
@login_required()
def removeSoftware():
......@@ -138,12 +150,14 @@ def removeSoftware():
flash('Software removed')
return redirect(url_for('inspectSoftware'))
@login_required()
def runSoftwareProfile():
if runSoftwareWithLock(app.config):
return jsonify(result = True)
return jsonify(result=True)
else:
return jsonify(result = False)
return jsonify(result=False)
@login_required()
def viewSoftwareLog():
......@@ -154,6 +168,7 @@ def viewSoftwareLog():
return render_template('viewLog.html', type='software',
result=result.encode("utf-8"))
# instance views
@login_required()
def editInstanceProfile():
......@@ -163,6 +178,7 @@ def editInstanceProfile():
return render_template('updateInstanceProfile.html', workDir='workspace',
profile=profile, projectList=getProjectList(app.config['workspace']))
# get status of all computer partitions and process state
@login_required()
def inspectInstance():
......@@ -178,6 +194,7 @@ def inspectInstance():
slap_status=getSlapStatus(app.config),
supervisore=result, partition_amount=app.config['partition_amount'])
#Reload instance process ans returns new value to ajax
@login_required()
def supervisordStatus():
......@@ -200,13 +217,14 @@ def supervisordStatus():
html += "</tr>"
return jsonify(code=1, result=html)
@login_required()
def removeInstance():
if isInstanceRunning(app.config):
flash('Instantiation in progress, cannot remove')
else:
removeProxyDb(app.config)
svcStopAll(app.config) #Stop All instance process
svcStopAll(app.config) # Stop All instance process
removeInstanceRoot(app.config)
param_path = os.path.join(app.config['etc_dir'], ".parameter.xml")
if os.path.exists(param_path):
......@@ -214,14 +232,16 @@ def removeInstance():
flash('Instance removed')
return redirect(url_for('inspectInstance'))
@login_required()
def runInstanceProfile():
if not os.path.exists(app.config['instance_root']):
os.mkdir(app.config['instance_root'])
if runInstanceWithLock(app.config):
return jsonify(result = True)
return jsonify(result=True)
else:
return jsonify(result = False)
return jsonify(result=False)
@login_required()
def viewInstanceLog():
......@@ -232,49 +252,63 @@ def viewInstanceLog():
return render_template('viewLog.html', type='instance',
result=result.encode("utf-8"))
@login_required()
def stopAllPartition():
svcStopAll(app.config)
return redirect(url_for('inspectInstance'))
@login_required(login_redirect)
def tailProcess(process):
return render_template('processTail.html',
process_log=getSvcTailProcess(app.config, process), process=process)
@login_required(login_redirect)
def startStopProccess(process, action):
svcStartStopProcess(app.config, process, action)
return redirect(url_for('inspectInstance'))
@login_required(login_redirect)
def openProject(method):
return render_template('projectFolder.html', method=method,
workDir='workspace')
@login_required()
def cloneRepository():
path = realpath(app.config, request.form['name'], False)
data = {"repo":request.form['repo'], "user":request.form['user'],
"email":request.form['email'], "path":path}
data = {
'repo': request.form['repo'],
'user': request.form['user'],
'email': request.form['email'],
'path': path
}
return cloneRepo(data)
@login_required()
def readFolder():
return getFolderContent(app.config, request.form['dir'])
@login_required()
def openFolder():
return getFolder(app.config, request.form['dir'])
@login_required()
def createSoftware():
return newSoftware(request.form['folder'], app.config, session)
@login_required()
def checkFolder():
return checkSoftwareFolder(request.form['path'], app.config)
@login_required()
def setCurrentProject():
if configNewSR(app.config, request.form['path']):
......@@ -283,11 +317,13 @@ def setCurrentProject():
else:
return jsonify(code=0, result=("Can not setup this Software Release"))
@login_required()
def manageProject():
return render_template('manageProject.html', workDir='workspace',
project=getProjectList(app.config['workspace']))
@login_required()
def getProjectStatus():
path = realpath(app.config, request.form['project'])
......@@ -296,6 +332,7 @@ def getProjectStatus():
else:
return jsonify(code=0, result="Can not read folder: Permission Denied")
#view for current software release files
@login_required()
def editCurrentProject():
......@@ -306,12 +343,13 @@ def editCurrentProject():
projectList=getProjectList(app.config['workspace']))
return redirect(url_for('configRepo'))
#create file or directory
@login_required()
def createFile():
path = realpath(app.config, request.form['file'], False)
if not path:
return jsonify(code=0, result="Error when creating your " + \
return jsonify(code=0, result="Error when creating your " +
request.form['type'] + ": Permission Denied")
try:
if request.form['type'] == "file":
......@@ -322,6 +360,7 @@ def createFile():
except Exception as e:
return jsonify(code=0, result=str(e))
#remove file or directory
@login_required()
def removeFile():
......@@ -334,6 +373,7 @@ def removeFile():
except Exception as e:
return jsonify(code=0, result=str(e))
@login_required()
def removeSoftwareDir():
try:
......@@ -343,6 +383,7 @@ def removeSoftwareDir():
except Exception as e:
return jsonify(code=0, result=str(e))
#read file and return content to ajax
@login_required()
def getFileContent():
......@@ -351,14 +392,15 @@ def getFileContent():
if not isText(file_path):
return jsonify(code=0,
result="Can not open a binary file, please select a text file!")
if not request.form.has_key('truncate'):
return jsonify(code=1, result=open(file_path, 'r').read())
else:
if 'truncate' in request.form:
content = tail(open(file_path, 'r'), int(request.form['truncate']))
return jsonify(code=1, result=content)
else:
return jsonify(code=1, result=open(file_path, 'r').read())
else:
return jsonify(code=0, result="Error: No such file!")
@login_required()
def saveFileContent():
file_path = realpath(app.config, request.form['file'])
......@@ -368,6 +410,7 @@ def saveFileContent():
else:
return jsonify(code=0, result="Error: No such file!")
@login_required()
def changeBranch():
path = realpath(app.config, request.form['project'])
......@@ -376,6 +419,7 @@ def changeBranch():
else:
return jsonify(code=0, result="Can not read folder: Permission Denied")
@login_required()
def newBranch():
path = realpath(app.config, request.form['project'])
......@@ -387,12 +431,14 @@ def newBranch():
else:
return jsonify(code=0, result="Can not read folder: Permission Denied")
@login_required(login_redirect)
def getProjectDiff(project):
path = os.path.join(app.config['workspace'], project)
return render_template('projectDiff.html', project=project,
diff=getDiff(path))
@login_required()
def pushProjectFiles():
path = realpath(app.config, request.form['project'])
......@@ -401,6 +447,7 @@ def pushProjectFiles():
else:
return jsonify(code=0, result="Can not read folder: Permission Denied")
@login_required()
def pullProjectFiles():
path = realpath(app.config, request.form['project'])
......@@ -409,6 +456,7 @@ def pullProjectFiles():
else:
return jsonify(code=0, result="Can not read folder: Permission Denied")
@login_required()
def checkFileType():
path = realpath(app.config, request.form['path'])
......@@ -420,6 +468,7 @@ def checkFileType():
return jsonify(code=0,
result="Can not open a binary file, please select a text file!")
@login_required()
def getmd5sum():
realfile = realpath(app.config, request.form['file'])
......@@ -431,26 +480,33 @@ def getmd5sum():
else:
return jsonify(code=0, result="Can not get md5sum for this file!")
#return information about state of slapgrid process
@login_required()
def slapgridResult():
software_state = isSoftwareRunning(app.config)
instance_state = isInstanceRunning(app.config)
log_result = {"content":"", "position":0, "truncated":False}
if request.form['log'] == "software" or\
log_result = {
'content': '',
'position': 0,
'truncated': False
}
if request.form['log'] == "software" or \
request.form['log'] == "instance":
log_file = request.form['log'] + "_log"
if os.path.exists(app.config[log_file]):
log_result = readFileFrom(open(app.config[log_file], 'r'),
int(request.form['position']))
return jsonify(software=software_state, instance=instance_state,
result=(instance_state or software_state), content=log_result)
return jsonify(software=software_state, instance=instance_state,
result=(instance_state or software_state), content=log_result)
@login_required()
def stopSlapgrid():
result = killRunningProcess(request.form['type'])
return jsonify(result=result)
@login_required()
def getPath():
files = request.form['file'].split('#')
......@@ -469,6 +525,7 @@ def getPath():
else:
return jsonify(code=1, result=realfile)
@login_required()
def saveParameterXml():
"""
......@@ -500,6 +557,7 @@ def saveParameterXml():
result="An error occurred while applying your settings!<br/>" + str(e))
return jsonify(code=1, result="")
@login_required()
def getSoftwareType():
software_type_path = os.path.join(app.config['etc_dir'], ".software_type.xml")
......@@ -507,6 +565,7 @@ def getSoftwareType():
return jsonify(code=1, result=open(software_type_path, 'r').read())
return jsonify(code=1, result="default")
#read instance parameters into the local xml file and return a dict
@login_required()
def getParameterXml(request):
......@@ -636,6 +695,7 @@ def fileBrowser():
return str(e)
return result
@login_required()
def editFile():
return render_template('editFile.html', workDir='workspace',
......@@ -643,6 +703,7 @@ def editFile():
projectList=getProjectList(app.config['workspace']),
filename=urllib.unquote(request.args.get('filename', '')))
#Setup List of URLs
app.add_url_rule('/', 'home', home)
app.add_url_rule('/browseWorkspace', 'browseWorkspace', browseWorkspace)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment