views.py 29.1 KB
Newer Older
1
# -*- coding: utf-8 -*-
Marco Mariani's avatar
Marco Mariani committed
2
# vim: set et sts=2:
Marco Mariani's avatar
Marco Mariani committed
3 4
# pylint: disable-msg=W0311,C0301,C0103,C0111

5

6
import json
Łukasz Nowak's avatar
Łukasz Nowak committed
7 8
import os
import shutil
9
import subprocess
10
import thread
11
import urllib
Łukasz Nowak's avatar
Łukasz Nowak committed
12

Marco Mariani's avatar
Marco Mariani committed
13 14 15
from flask import (Flask, request, redirect, url_for, render_template,
                   g, flash, jsonify, session, abort, send_file)

16
from slapos.runner.process import killRunningProcess
17
from slapos.runner.utils import (checkSoftwareFolder, configNewSR,
18 19
                                 createNewUser, getBuildAndRunParams,
                                 getProfilePath, getSlapgridResult,
20
                                 listFolder, getBuildAndRunParams,
21
                                 getProjectTitle, getRcode, getSession,
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
22 23
                                 getSlapStatus, getSvcStatus,
                                 getSvcTailProcess, isInstanceRunning,
24
                                 isSoftwareRunning, isSoftwareReleaseReady, isText,
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
25 26 27 28
                                 loadSoftwareRList, md5sum, newSoftware,
                                 readFileFrom, readParameters, realpath,
                                 removeInstanceRoot, removeProxyDb,
                                 removeSoftwareByName, runInstanceWithLock,
29 30
                                 runSoftwareWithLock, runSlapgridUntilSuccess,
                                 saveSession, saveBuildAndRunParams,
31
                                 setMiniShellHistory,
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
32
                                 svcStartStopProcess, svcStopAll, tail,
33
                                 updateInstanceParameter)
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
34

Marco Mariani's avatar
Marco Mariani committed
35
from slapos.runner.fileBrowser import FileBrowser
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
36
from slapos.runner.gittools import (cloneRepo, gitStatus, switchBranch,
37
                                    addBranch, getDiff, gitCommit, gitPush, gitPull)
Marco Mariani's avatar
Marco Mariani committed
38 39


Łukasz Nowak's avatar
Łukasz Nowak committed
40
app = Flask(__name__)
41
app.config['MAX_CONTENT_LENGTH'] = 20 * 1024 * 1024
Marco Mariani's avatar
Marco Mariani committed
42
file_request = FileBrowser(app.config)
43

Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
44 45 46 47
# Setup default flask (werkzeug) parser
import logging
logger = logging.getLogger('werkzeug')

Marco Mariani's avatar
Marco Mariani committed
48

49 50
def login_redirect(*args, **kwargs):
  return redirect(url_for('login'))
Łukasz Nowak's avatar
Łukasz Nowak committed
51

52

53 54
@app.before_request
def before_request():
55 56
  if request.path.startswith('/static') \
    or request.path == '/isSRReady':
57 58
    return

59 60 61 62 63 64 65 66
  account = getSession(app.config)
  if account:
    session['title'] = getProjectTitle(app.config)
  else:
    session['title'] = "No account is defined"
    if request.path != "/setAccount" and request.path != "/configAccount":
      return redirect(url_for('setAccount'))

67
  g.instance_monitoring_url =  app.config['instance_monitoring_url']
68

Łukasz Nowak's avatar
Łukasz Nowak committed
69 70 71 72
# general views
def home():
  return render_template('index.html')

Marco Mariani's avatar
Marco Mariani committed
73

74 75 76 77
# general views
def browseWorkspace():
  return render_template('workspace.html')

Marco Mariani's avatar
Marco Mariani committed
78

79 80 81 82
@app.route("/login")
def login():
  return render_template('login.html')

Marco Mariani's avatar
Marco Mariani committed
83

84 85 86 87
@app.route("/setAccount")
def setAccount():
  account = getSession(app.config)
  if not account:
88
    return render_template('account.html')
89 90
  return redirect(url_for('login'))

Marco Mariani's avatar
Marco Mariani committed
91

92 93 94
def myAccount():
  account = getSession(app.config)
  return render_template('account.html', username=account[0],
95
          email=account[2], name=account[3].decode('utf-8'),
96
          params=getBuildAndRunParams(app.config))
97

Marco Mariani's avatar
Marco Mariani committed
98

99 100 101 102
def getSlapgridParameters():
  return jsonify(getBuildAndRunParams(app.config))


103
def manageRepository():
104
  public_key = open(app.config['public_key']).read()
105
  account = getSession(app.config)
106 107
  return render_template('manageRepository.html', workDir='workspace',
            project=listFolder(app.config, 'workspace'),
108 109
            public_key=public_key, name=account[3].decode('utf-8'),
            email=account[2])
110

Marco Mariani's avatar
Marco Mariani committed
111

112 113
@app.route("/doLogin", methods=['POST'])
def doLogin():
114 115 116
  #XXX Now has to check the .htpasswd if we want to warn
  #the user that he misspelled his name/password
  return jsonify(code=1, result="")
117 118


Łukasz Nowak's avatar
Łukasz Nowak committed
119 120
# software views
def editSoftwareProfile():
121
  profile = getProfilePath(app.config['etc_dir'], app.config['software_profile'])
122 123
  if profile == "":
    flash('Error: can not open profile, please select your project first')
124
  return render_template('updateSoftwareProfile.html', workDir='workspace',
125
      profile=profile, projectList=listFolder(app.config, 'workspace'))
Łukasz Nowak's avatar
Łukasz Nowak committed
126

Marco Mariani's avatar
Marco Mariani committed
127

Łukasz Nowak's avatar
Łukasz Nowak committed
128
def inspectSoftware():
129 130
  return render_template('runResult.html', softwareRoot='software_link/',
                         softwares=loadSoftwareRList(app.config))
Łukasz Nowak's avatar
Łukasz Nowak committed
131

Marco Mariani's avatar
Marco Mariani committed
132

Alain Takoudjou's avatar
Alain Takoudjou committed
133
#remove content of compiled software release
Łukasz Nowak's avatar
Łukasz Nowak committed
134 135 136
def removeSoftware():
  if isSoftwareRunning(app.config) or isInstanceRunning(app.config):
    flash('Software installation or instantiation in progress, cannot remove')
137
  elif os.path.exists(app.config['software_root']):
Łukasz Nowak's avatar
Łukasz Nowak committed
138 139
    svcStopAll(app.config)
    shutil.rmtree(app.config['software_root'])
140 141
    for link in os.listdir(app.config['software_link']):
      os.remove(os.path.join(app.config['software_link'], link))
Łukasz Nowak's avatar
Łukasz Nowak committed
142 143 144
    flash('Software removed')
  return redirect(url_for('inspectSoftware'))

Marco Mariani's avatar
Marco Mariani committed
145

Łukasz Nowak's avatar
Łukasz Nowak committed
146
def runSoftwareProfile():
147 148
  thread.start_new_thread(runSlapgridUntilSuccess, (app.config, "software"))
  return jsonify(result=True)
Marco Mariani's avatar
Marco Mariani committed
149

Łukasz Nowak's avatar
Łukasz Nowak committed
150 151 152

# instance views
def editInstanceProfile():
153
  profile = getProfilePath(app.config['etc_dir'], app.config['instance_profile'])
154
  if profile == "":
155 156
    flash('Error: can not open instance profile for this Software Release')
  return render_template('updateInstanceProfile.html', workDir='workspace',
157
      profile=profile, projectList=listFolder(app.config, 'workspace'))
Łukasz Nowak's avatar
Łukasz Nowak committed
158

Marco Mariani's avatar
Marco Mariani committed
159

Alain Takoudjou's avatar
Alain Takoudjou committed
160
# get status of all computer partitions and process state
Łukasz Nowak's avatar
Łukasz Nowak committed
161 162
def inspectInstance():
  if os.path.exists(app.config['instance_root']):
163 164 165 166 167
    file_path = 'instance_root'
    supervisor = getSvcStatus(app.config)
  else:
    file_path = ''
    supervisor = []
Łukasz Nowak's avatar
Łukasz Nowak committed
168
  return render_template('instanceInspect.html',
169 170 171 172
                         file_path=file_path,
                         supervisor=supervisor,
                         slap_status=getSlapStatus(app.config),
                         partition_amount=app.config['partition_amount'])
Łukasz Nowak's avatar
Łukasz Nowak committed
173 174


Alain Takoudjou's avatar
Alain Takoudjou committed
175
#Reload instance process ans returns new value to ajax
176 177
def supervisordStatus():
  result = getSvcStatus(app.config)
178
  if not result:
179
    return jsonify(code=0, result="")
180
  # XXX-Marco -> template
181 182 183
  html = "<tr><th>Partition and Process name</th><th>Status</th><th>Process PID </th><th> UpTime</th><th></th></tr>"
  for item in result:
    html += "<tr>"
184 185
    html += "<td  class='first'><b><a href='" + url_for('tailProcess', process=item[0]) + "'>" + item[0] + "</a></b></td>"
    html += "<td align='center'><a href='" + url_for('startStopProccess', process=item[0], action=item[1]) + "'>" + item[1] + "</a></td>"
Marco Mariani's avatar
Marco Mariani committed
186
    html += "<td align='center'>" + item[3] + "</td><td>" + item[5] + "</td>"
187
    html += "<td align='center'><a href='" + url_for('startStopProccess', process=item[0], action='RESTART') + "'>Restart</a></td>"
Marco Mariani's avatar
Marco Mariani committed
188
    html += "</tr>"
189 190
  return jsonify(code=1, result=html)

Marco Mariani's avatar
Marco Mariani committed
191

Łukasz Nowak's avatar
Łukasz Nowak committed
192 193 194
def removeInstance():
  if isInstanceRunning(app.config):
    flash('Instantiation in progress, cannot remove')
195
  else:
196
    removeProxyDb(app.config)
Marco Mariani's avatar
Marco Mariani committed
197
    svcStopAll(app.config)  # Stop All instance process
198
    removeInstanceRoot(app.config)
199
    param_path = os.path.join(app.config['etc_dir'], ".parameter.xml")
200 201
    if os.path.exists(param_path):
      os.remove(param_path)
Łukasz Nowak's avatar
Łukasz Nowak committed
202 203 204
    flash('Instance removed')
  return redirect(url_for('inspectInstance'))

Marco Mariani's avatar
Marco Mariani committed
205

Łukasz Nowak's avatar
Łukasz Nowak committed
206 207 208
def runInstanceProfile():
  if not os.path.exists(app.config['instance_root']):
    os.mkdir(app.config['instance_root'])
209 210
  thread.start_new_thread(runSlapgridUntilSuccess, (app.config, "instance"))
  return jsonify(result=True)
Marco Mariani's avatar
Marco Mariani committed
211

Łukasz Nowak's avatar
Łukasz Nowak committed
212

213 214 215 216 217 218 219 220 221
def viewLog():
  return render_template('viewLog.html')

def getFileLog():
  logfile = request.form.get('filename', '').encode('utf-8')
  if logfile == "instance.log":
    file_path = app.config['instance_log']
  elif logfile == "software.log":
    file_path = app.config['software_log']
Łukasz Nowak's avatar
Łukasz Nowak committed
222
  else:
223 224
    file_path = realpath(app.config, logfile)
  try:
225 226
    if not os.path.exists(file_path):
      raise IOError
227 228 229 230 231 232 233 234 235 236 237
    if not isText(file_path):
      return jsonify(code=0,
            result="Can not open binary file, please select a text file!")
    if 'truncate' in request.form:
      content = tail(open(file_path), int(request.form['truncate']))
      return jsonify(code=1, result=content)
    else:
      with open(file_path) as f:
        return jsonify(code=1, result=f.read())
  except:
    return jsonify(code=0, result="Warning: Log file doesn't exist yet or empty log!!")
Łukasz Nowak's avatar
Łukasz Nowak committed
238

Marco Mariani's avatar
Marco Mariani committed
239

Łukasz Nowak's avatar
Łukasz Nowak committed
240 241 242
def stopAllPartition():
  svcStopAll(app.config)
  return redirect(url_for('inspectInstance'))
243

Marco Mariani's avatar
Marco Mariani committed
244

245 246 247 248
def tailProcess(process):
  return render_template('processTail.html',
      process_log=getSvcTailProcess(app.config, process), process=process)

Marco Mariani's avatar
Marco Mariani committed
249

250 251 252 253
def startStopProccess(process, action):
  svcStartStopProcess(app.config, process, action)
  return redirect(url_for('inspectInstance'))

Marco Mariani's avatar
Marco Mariani committed
254

255
def openProject(method):
256 257
  return render_template('projectFolder.html', method=method,
                         workDir='workspace')
258

Marco Mariani's avatar
Marco Mariani committed
259

260
def cloneRepository():
261
  path = realpath(app.config, request.form['name'], False)
Marco Mariani's avatar
Marco Mariani committed
262 263 264 265 266 267
  data = {
    'repo': request.form['repo'],
    'user': request.form['user'],
    'email': request.form['email'],
    'path': path
  }
268
  return cloneRepo(data)
269

Marco Mariani's avatar
Marco Mariani committed
270

271 272 273
def listDirectory():
  folderList = listFolder(app.config, request.form['name'])
  return jsonify(result=folderList)
274

Marco Mariani's avatar
Marco Mariani committed
275

276
def createSoftware():
277
  return newSoftware(request.form['folder'], app.config, session)
278

Marco Mariani's avatar
Marco Mariani committed
279

280 281 282
def checkFolder():
  return checkSoftwareFolder(request.form['path'], app.config)

Marco Mariani's avatar
Marco Mariani committed
283

284 285
def setCurrentProject():
  if configNewSR(app.config, request.form['path']):
286 287 288
    session['title'] = getProjectTitle(app.config)
    return jsonify(code=1, result="")
  else:
289
    return jsonify(code=0, result=("Can not setup this Software Release"))
290

Marco Mariani's avatar
Marco Mariani committed
291

292
def getProjectStatus():
293 294 295 296 297
  path = realpath(app.config, request.form['project'])
  if path:
    return gitStatus(path)
  else:
    return jsonify(code=0, result="Can not read folder: Permission Denied")
298

Marco Mariani's avatar
Marco Mariani committed
299

Alain Takoudjou's avatar
Alain Takoudjou committed
300
#view for current software release files
301
def editCurrentProject():
302 303 304 305 306
  project_file = os.path.join(app.config['etc_dir'], ".project")
  # XXX hardcoded default project
  project = "workspace/slapos"
  if os.path.exists(project_file):
    project = open(project_file).read()
307
  projectList = listFolder(app.config, 'workspace')
308
  if projectList:
309
    return render_template('softwareFolder.html', workDir='runner_workdir',
310
                           project=project,
311
                           projectList=projectList)
312
  else:
313 314
    flash('Please clone slapos repository, or your own repository')
    return redirect(url_for('manageRepository'))
Marco Mariani's avatar
Marco Mariani committed
315

Alain Takoudjou's avatar
Alain Takoudjou committed
316
#create file or directory
317
def createFile():
318 319
  path = realpath(app.config, request.form['file'], False)
  if not path:
Marco Mariani's avatar
Marco Mariani committed
320
    return jsonify(code=0, result="Error when creating your %s: Permission Denied" % request.form['type'])
321 322
  try:
    if request.form['type'] == "file":
Marco Mariani's avatar
Marco Mariani committed
323
      open(path, 'w')
324
    else:
325
      os.mkdir(path)
326
    return jsonify(code=1, result="")
Marco Mariani's avatar
Marco Mariani committed
327
  except Exception as e:
328 329
    return jsonify(code=0, result=str(e))

Marco Mariani's avatar
Marco Mariani committed
330

Alain Takoudjou's avatar
Alain Takoudjou committed
331
#remove file or directory
332 333 334 335 336 337 338
def removeFile():
  try:
    if request.form['type'] == "folder":
      shutil.rmtree(request.form['path'])
    else:
      os.remove(request.form['path'])
    return jsonify(code=1, result="")
Marco Mariani's avatar
Marco Mariani committed
339
  except Exception as e:
340
    return jsonify(code=0, result=str(e))
341

Marco Mariani's avatar
Marco Mariani committed
342

343
def removeSoftwareDir():
344
  try:
345 346
    data = removeSoftwareByName(app.config, request.form['md5'],
            request.form['title'])
347
    return jsonify(code=1, result=data)
Marco Mariani's avatar
Marco Mariani committed
348
  except Exception as e:
349
    return jsonify(code=0, result=str(e))
350

Marco Mariani's avatar
Marco Mariani committed
351

Alain Takoudjou's avatar
Alain Takoudjou committed
352
#read file and return content to ajax
353
def getFileContent():
354 355
  file_path = realpath(app.config, request.form['file'])
  if file_path:
Alain Takoudjou's avatar
Alain Takoudjou committed
356 357 358
    if not isText(file_path):
      return jsonify(code=0,
            result="Can not open a binary file, please select a text file!")
Marco Mariani's avatar
Marco Mariani committed
359
    if 'truncate' in request.form:
360
      content = tail(open(file_path), int(request.form['truncate']))
361
      return jsonify(code=1, result=content)
Marco Mariani's avatar
Marco Mariani committed
362
    else:
363
      return jsonify(code=1, result=open(file_path).read())
364 365
  else:
    return jsonify(code=0, result="Error: No such file!")
366

Marco Mariani's avatar
Marco Mariani committed
367

368
def saveFileContent():
369
  file_path = realpath(app.config, request.form['file'], False)
370
  if file_path:
371 372
    with open(file_path, 'w') as f:
      f.write(request.form['content'].encode("utf-8"))
373 374
    return jsonify(code=1, result="")
  else:
375
    return jsonify(code=0, result="Rejected!! Cannot access to this location.")
376

Marco Mariani's avatar
Marco Mariani committed
377

378
def changeBranch():
379 380 381 382 383
  path = realpath(app.config, request.form['project'])
  if path:
    return switchBranch(path, request.form['name'])
  else:
    return jsonify(code=0, result="Can not read folder: Permission Denied")
384

Marco Mariani's avatar
Marco Mariani committed
385

386
def newBranch():
387 388 389 390 391 392 393 394
  path = realpath(app.config, request.form['project'])
  if path:
    if request.form['create'] == '1':
      return addBranch(path, request.form['name'])
    else:
      return addBranch(path, request.form['name'], True)
  else:
    return jsonify(code=0, result="Can not read folder: Permission Denied")
395

Marco Mariani's avatar
Marco Mariani committed
396

397
def getProjectDiff():
398 399
  path = realpath(app.config, request.form['project'])
  if path:
400
    return jsonify(code=1, result=getDiff(path))
401
  else:
402 403
    return jsonify(code=0,
                  result="Error: No such file or directory. PERMISSION DENIED!")
404

Marco Mariani's avatar
Marco Mariani committed
405

406
def pushProjectFiles():
407 408
  path = realpath(app.config, request.form['project'])
  if path:
409
    return gitPush(path)
410 411
  else:
    return jsonify(code=0, result="Can not read folder: Permission Denied")
412

Marco Mariani's avatar
Marco Mariani committed
413

414
def pullProjectFiles():
415 416 417 418 419
  path = realpath(app.config, request.form['project'])
  if path:
    return gitPull(path)
  else:
    return jsonify(code=0, result="Can not read folder: Permission Denied")
420

Marco Mariani's avatar
Marco Mariani committed
421

422
def checkFileType():
423 424 425
  path = realpath(app.config, request.form['path'])
  if not path:
    return jsonify(code=0, result="Can not open file: Permission Denied!")
426 427 428
  if isText(path):
    return jsonify(code=1, result="text")
  else:
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
429 430
    return jsonify(code=0,
                   result="Can not open a binary file, please select a text file!")
431

Marco Mariani's avatar
Marco Mariani committed
432

433
def getmd5sum():
434 435 436 437
  realfile = realpath(app.config, request.form['file'])
  if not realfile:
    return jsonify(code=0, result="Can not open file: Permission Denied!")
  md5 = md5sum(realfile)
438 439 440
  if md5:
    return jsonify(code=1, result=md5)
  else:
441 442
    return jsonify(code=0, result="Can not get md5sum for this file!")

Marco Mariani's avatar
Marco Mariani committed
443

Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
444
#return information about state of slapgrid process
445 446 447
def slapgridResult():
  software_state = isSoftwareRunning(app.config)
  instance_state = isInstanceRunning(app.config)
Marco Mariani's avatar
Marco Mariani committed
448 449 450 451 452
  log_result = {
    'content': '',
    'position': 0,
    'truncated': False
  }
Marco Mariani's avatar
Marco Mariani committed
453
  if request.form['log'] in ['software', 'instance']:
454 455
    log_file = request.form['log'] + "_log"
    if os.path.exists(app.config[log_file]):
456 457
      log_result = readFileFrom(open(app.config[log_file]),
                                int(request.form['position']))
458 459 460 461 462 463 464 465 466
  build_result = getSlapgridResult(app.config, 'software')
  run_result = getSlapgridResult(app.config, 'instance')
  software_info = {'state':software_state,
                   'last_build':build_result['last_build'],
                   'success':build_result['success']}
  instance_info = {'state':instance_state,
                   'last_build':run_result['last_build'],
                   'success':run_result['success']}
  return jsonify(software=software_info, instance=instance_info,
Marco Mariani's avatar
Marco Mariani committed
467 468
                 result=(instance_state or software_state), content=log_result)

469 470

def stopSlapgrid():
471 472
  counter_file = os.path.join(app.config['runner_workdir'], '.turn-left')
  open(counter_file, 'w+').write(str(0))
473
  result = killRunningProcess(request.form['type'])
474 475
  return jsonify(result=result)

Marco Mariani's avatar
Marco Mariani committed
476

477 478 479 480 481
def getPath():
  files = request.form['file'].split('#')
  list = []
  for p in files:
    path = realpath(app.config, p)
Alain Takoudjou's avatar
Alain Takoudjou committed
482
    if not path:
483 484 485 486
      list = []
      break
    else:
      list.append(path)
Marco Mariani's avatar
Marco Mariani committed
487
  realfile = '#'.join(list)
488
  if not realfile:
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
489 490
    return jsonify(code=0,
                   result="Can not access to this file: Permission Denied!")
491
  else:
492 493
    return jsonify(code=1, result=realfile)

Marco Mariani's avatar
Marco Mariani committed
494

495
def saveParameterXml():
496 497 498
  """
  Update instance parameter into a local xml file.
  """
499
  project = os.path.join(app.config['etc_dir'], ".project")
500 501
  if not os.path.exists(project):
    return jsonify(code=0, result="Please first open a Software Release")
502
  content = request.form['parameter'].encode("utf-8")
503
  param_path = os.path.join(app.config['etc_dir'], ".parameter.xml")
504
  try:
505 506
    with open(param_path, 'w') as f:
      f.write(content)
507
    result = readParameters(param_path)
Marco Mariani's avatar
Marco Mariani committed
508
  except Exception as e:
509
    result = str(e)
510
  software_type = None
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
511
  if request.form['software_type']:
512
    software_type = request.form['software_type']
513
  if type(result) == type(''):
514
    return jsonify(code=0, result=result)
515
  else:
516
    try:
517
      updateInstanceParameter(app.config, software_type)
Marco Mariani's avatar
Marco Mariani committed
518
    except Exception as e:
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
519 520
      return jsonify(
        code=0,
Marco Mariani's avatar
Marco Mariani committed
521
        result="An error occurred while applying your settings!<br/>%s" % e)
522 523
    return jsonify(code=1, result="")

Marco Mariani's avatar
Marco Mariani committed
524

525 526 527
def getSoftwareType():
  software_type_path = os.path.join(app.config['etc_dir'], ".software_type.xml")
  if os.path.exists(software_type_path):
528
    return jsonify(code=1, result=open(software_type_path).read())
529 530
  return jsonify(code=1, result="default")

Marco Mariani's avatar
Marco Mariani committed
531

Alain Takoudjou's avatar
Alain Takoudjou committed
532
#read instance parameters into the local xml file and return a dict
533
def getParameterXml(request):
534
  param_path = os.path.join(app.config['etc_dir'], ".parameter.xml")
535
  if not os.path.exists(param_path):
Marco Mariani's avatar
Marco Mariani committed
536
    default = '<?xml version="1.0" encoding="utf-8"?>\n<instance>\n</instance>'
537 538
    return jsonify(code=1, result=default)
  if request == "xml":
539
    parameters = open(param_path).read()
540 541 542 543
  else:
    parameters = readParameters(param_path)
  if type(parameters) == type('') and request != "xml":
    return jsonify(code=0, result=parameters)
544
  else:
545 546
    return jsonify(code=1, result=parameters)

547

548
#update user-defined slapgrid parameters
549
def updateBuildAndRunConfig():
550 551 552 553 554 555 556 557 558 559 560
  code = 1
  try:
    max_run_instance = int(request.form['max_run_instance'].strip())
    max_run_software = int(request.form['max_run_software'].strip())
  except ValueError:
    code = 0
    result = "Error! You should have provided an integer"
  run_instance = (True if request.form['run_instance']=="true" else False)
  run_software = (True if request.form['run_software']=="true" else False)
  if code:
    params =  {}
561 562 563 564 565
    params['run_instance'] = run_instance
    params['run_software'] = run_software
    params['max_run_instance'] = max_run_instance
    params['max_run_software'] = max_run_software
    saveBuildAndRunParams(app.config, params)
566 567 568 569
    result = "Your parameters have correctly been updated"
  return jsonify(code=code, result=result)


570 571
#update user account data
def updateAccount():
572
  code = request.form['rcode'].strip()
573
  recovery_code = getRcode(app.config)
574 575
  if code != recovery_code:
    return jsonify(code=0, result="Your password recovery code is not valid!")
576 577 578 579 580 581 582

  account = [
    request.form['username'].strip(),
    request.form['password'].strip(),
    request.form['email'].strip(),
    request.form['name'].strip()
  ]
583
  result = saveSession(app.config, account)
584 585 586
  if type(result) == type(""):
    return jsonify(code=0, result=result)
  else:
587 588
    return jsonify(code=1, result="")

589

590 591 592 593
#update user account data
@app.route("/configAccount", methods=['POST'])
def configAccount():
  last_account = getSession(app.config)
594 595 596 597 598 599 600 601 602 603
  if last_account:
    return jsonify(code=0,
                   result="Unable to respond to your request, permission denied.")

  account = []
  account.append(request.form['username'].strip())
  account.append(request.form['password'].strip())
  account.append(request.form['email'].strip())
  account.append(request.form['name'].strip())
  code = request.form['rcode'].strip()
604
  recovery_code = getRcode(app.config)
605 606 607 608 609 610 611 612
  if code != recovery_code:
    return jsonify(code=0, result="Your password recovery code is not valid!")
  result = saveSession(app.config, account)
  if type(result) == type(""):
    return jsonify(code=0, result=result)
  else:
    return jsonify(code=1, result="")

613 614
def addUser():
  code = request.form['rcode'].strip()
615
  recovery_code = getRcode(app.config)
616 617 618 619 620 621 622 623
  if code != recovery_code:
    return jsonify(code=0, result="Your password recovery code is not valid!")
  if createNewUser(app.config, request.form['username'],
                   request.form['password']):
    return jsonify(code=1, result="New user succesfully saved")
  else:
    return jsonify(code=0, result="Problem while creating new user")

624

625 626 627 628 629 630 631 632 633 634 635 636 637
#Global File Manager
def fileBrowser():
  if request.method == 'POST':
    filename = request.form.get('filename', '').encode('utf-8')
    dir = request.form['dir'].encode('utf-8')
    newfilename = request.form.get('newfilename', '').encode('utf-8')
    files = request.form.get('files', '').encode('utf-8')
    if not request.form.has_key('opt') or not request.form['opt']:
      opt = 1
    else:
      opt = int(request.form['opt'])
  else:
    opt = int(request.args.get('opt'))
638

639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
  try:
    if opt == 1:
      #list files and directories
      result = file_request.listDirs(dir)
    elif opt == 2:
      #Create file
      result = file_request.makeFile(dir, filename)
    elif opt == 3:
      #Create directory
      result = file_request.makeDirectory(dir, filename)
    elif opt == 4:
      #Delete a list of files or/and directories
      result = file_request.deleteItem(dir, files)
    elif opt == 5:
      #copy a lis of files or/and directories
      result = file_request.copyItem(dir, files)
    elif opt == 6:
      #rename file or directory
      result = file_request.rename(dir, filename, newfilename)
    elif opt == 7:
      result = file_request.copyItem(dir, files, del_source=True)
    elif opt == 8:
      #donwload file
      filename = request.args.get('filename').encode('utf-8')
      result = file_request.downloadFile(request.args.get('dir').encode('utf-8'),
                filename)
      try:
        return send_file(result, attachment_filename=filename, as_attachment=True)
      except:
        abort(404)
    elif opt == 9:
      result = file_request.readFile(dir, filename, False)
    elif opt == 11:
      #Upload file
      result = file_request.uploadFile(dir, request.files)
    elif opt == 14:
      #Copy file or directory as ...
      result = file_request.copyAsFile(dir, filename, newfilename)
    elif opt == 16:
      #zip file
      result = file_request.zipFile(dir, filename, newfilename)
    elif opt == 17:
      #zip file
      result = file_request.unzipFile(dir, filename, newfilename)
    elif opt == 20:
      #Fancy Load folder
      key = request.args.get('key')
      dir = request.args.get('dir').encode('utf-8')
      listfiles = request.args.get('listfiles', '')
      data = file_request.fancylistDirs(dir, key, listfiles)
      result = json.dumps(data)
    else:
      result = "ARGS PARSE ERROR: Bad option..."
  except Exception as e:
    return str(e)
694 695
  return result

Marco Mariani's avatar
Marco Mariani committed
696

697 698 699
def editFile():
  return render_template('editFile.html', workDir='workspace',
    profile=urllib.unquote(request.args.get('profile', '')),
700
    projectList=listFolder(app.config, 'workspace'),
701 702
    filename=urllib.unquote(request.args.get('filename', '')))

703
def shell():
704
  return render_template('shell.html')
Marco Mariani's avatar
Marco Mariani committed
705

706

707 708 709
def isSRReady():
  return isSoftwareReleaseReady(app.config)

710

711 712 713 714 715 716 717 718 719 720 721 722
def runCommand():
  cwd = open(app.config['minishell_cwd_file'], 'r').read().strip()
  command = request.form.get("command", '').strip()
  parsed_commands = command.split(';');
  # does the user want to change current directory ?
  for cmd in parsed_commands:
    if 'cd' == cmd[:2]:
      cmd = cmd.split(' ');
      if len(cmd) == 1:
        cmd.append(os.environ.get('HOME'))
      # shorten directory's name, to avoid things like : /a/../b
      cd_dir = os.path.realpath(os.path.join(cwd, cmd[1]))
723
      if os.path.exists(cd_dir) and os.path.isdir(cd_dir):
724 725 726 727 728 729 730 731
        cwd = cd_dir
        # save new cwd in the config file
        open(app.config['minishell_cwd_file'], 'w').write(cwd)
        # if the command was just cd, execute it. Otherwise, execute the rest
        command = command.replace(' '.join(cmd), '').strip(';')
        if not command:
          return "Changed directory, now in : " + cwd
  try:
732
    setMiniShellHistory(app.config, command)
733 734 735 736 737 738 739
    return subprocess.check_output(command, stderr=subprocess.STDOUT, shell=True, cwd=cwd)
  except subprocess.CalledProcessError as e:
    error = "Error : process exited with exit code " + str(e.returncode) + \
            "\nProcess says :\n" + e.output
    return error


740 741 742 743 744 745 746 747 748 749
def getMiniShellHistory():
  history_file = app.config['minishell_history_file']
  if not os.path.exists(history_file):
    return ""
  history = open(history_file, 'r').readlines()
  for line, text in enumerate(history):
    history[line] = text.strip()
  return json.dumps(history)


750 751
#Setup List of URLs
app.add_url_rule('/', 'home', home)
752 753 754
app.add_url_rule('/browseWorkspace', 'browseWorkspace', browseWorkspace)
app.add_url_rule('/editSoftwareProfile', 'editSoftwareProfile',
                editSoftwareProfile)
755 756
app.add_url_rule('/inspectSoftware', 'inspectSoftware', inspectSoftware)
app.add_url_rule('/removeSoftware', 'removeSoftware', removeSoftware)
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
757
app.add_url_rule('/runSoftwareProfile', 'runSoftwareProfile',
758
                 runSoftwareProfile, methods=['GET', 'POST'])
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
759 760 761 762 763 764 765
app.add_url_rule('/editInstanceProfile', 'editInstanceProfile',
                 editInstanceProfile)
app.add_url_rule('/inspectInstance', 'inspectInstance',
                 inspectInstance, methods=['GET'])
app.add_url_rule('/supervisordStatus', 'supervisordStatus',
                 supervisordStatus, methods=['GET'])
app.add_url_rule('/runInstanceProfile', 'runInstanceProfile',
766
                 runInstanceProfile, methods=['GET', 'POST'])
767
app.add_url_rule('/removeInstance', 'removeInstance', removeInstance)
768 769 770 771
app.add_url_rule('/viewLog', 'viewLog',
                 viewLog, methods=['GET'])
app.add_url_rule("/getFileLog", 'getFileLog', getFileLog,
                 methods=['POST'])
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
772 773 774 775 776 777 778 779
app.add_url_rule('/stopAllPartition', 'stopAllPartition',
                 stopAllPartition, methods=['GET'])
app.add_url_rule('/tailProcess/name/<process>', 'tailProcess',
                 tailProcess, methods=['GET'])
app.add_url_rule('/startStopProccess/name/<process>/cmd/<action>',
                 'startStopProccess', startStopProccess, methods=['GET'])
app.add_url_rule("/getParameterXml/<request>", 'getParameterXml',
                 getParameterXml, methods=['GET'])
780 781
app.add_url_rule('/getSoftwareType', 'getSoftwareType',
                 getSoftwareType, methods=['GET'])
782
app.add_url_rule("/stopSlapgrid", 'stopSlapgrid', stopSlapgrid, methods=['POST'])
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
783 784
app.add_url_rule("/slapgridResult", 'slapgridResult',
                 slapgridResult, methods=['POST'])
785
app.add_url_rule("/getmd5sum", 'getmd5sum', getmd5sum, methods=['POST'])
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
786 787 788 789 790 791
app.add_url_rule("/checkFileType", 'checkFileType', checkFileType,
                 methods=['POST'])
app.add_url_rule("/pullProjectFiles", 'pullProjectFiles', pullProjectFiles,
                 methods=['POST'])
app.add_url_rule("/pushProjectFiles", 'pushProjectFiles', pushProjectFiles,
                 methods=['POST'])
792 793
app.add_url_rule("/getProjectDiff", 'getProjectDiff', getProjectDiff,
                 methods=['POST'])
794 795
app.add_url_rule("/newBranch", 'newBranch', newBranch, methods=['POST'])
app.add_url_rule("/changeBranch", 'changeBranch', changeBranch, methods=['POST'])
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
796 797 798 799 800 801
app.add_url_rule("/saveFileContent", 'saveFileContent', saveFileContent,
                 methods=['POST'])
app.add_url_rule("/removeSoftwareDir", 'removeSoftwareDir', removeSoftwareDir,
                 methods=['POST'])
app.add_url_rule("/getFileContent", 'getFileContent', getFileContent,
                 methods=['POST'])
802 803 804
app.add_url_rule("/removeFile", 'removeFile', removeFile, methods=['POST'])
app.add_url_rule("/createFile", 'createFile', createFile, methods=['POST'])
app.add_url_rule("/editCurrentProject", 'editCurrentProject', editCurrentProject)
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
805 806 807 808 809 810
app.add_url_rule("/getProjectStatus", 'getProjectStatus', getProjectStatus,
                 methods=['POST'])
app.add_url_rule('/openProject/<method>', 'openProject', openProject,
                 methods=['GET'])
app.add_url_rule("/setCurrentProject", 'setCurrentProject', setCurrentProject,
                 methods=['POST'])
811
app.add_url_rule("/checkFolder", 'checkFolder', checkFolder, methods=['POST'])
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
812 813 814 815
app.add_url_rule('/createSoftware', 'createSoftware', createSoftware,
                 methods=['POST'])
app.add_url_rule('/cloneRepository', 'cloneRepository', cloneRepository,
                 methods=['POST'])
816 817
app.add_url_rule('/listDirectory', 'listDirectory', listDirectory, methods=['POST'])
app.add_url_rule('/manageRepository', 'manageRepository', manageRepository)
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
818 819
app.add_url_rule("/saveParameterXml", 'saveParameterXml', saveParameterXml,
                 methods=['POST'])
820 821
app.add_url_rule("/getPath", 'getPath', getPath, methods=['POST'])
app.add_url_rule("/myAccount", 'myAccount', myAccount)
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
822 823
app.add_url_rule("/updateAccount", 'updateAccount', updateAccount,
                 methods=['POST'])
824
app.add_url_rule("/updateBuildAndRunConfig", 'updateBuildAndRunConfig', updateBuildAndRunConfig,
825
                 methods=['POST'])
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
826 827
app.add_url_rule("/fileBrowser", 'fileBrowser', fileBrowser,
                 methods=['GET', 'POST'])
828
app.add_url_rule("/editFile", 'editFile', editFile, methods=['GET'])
829
app.add_url_rule('/shell', 'shell', shell)
830
app.add_url_rule('/isSRReady', 'isSRReady', isSRReady)
831
app.add_url_rule('/addUser', 'addUser', addUser, methods=['POST'])
832
app.add_url_rule('/getSlapgridParameters', 'getSlapgridParameters', getSlapgridParameters, methods=['GET'])
833
app.add_url_rule('/runCommand', 'runCommand', runCommand, methods=['POST'])
834
app.add_url_rule("/getMiniShellHistory", 'getMiniShellHistory', getMiniShellHistory, methods=['GET'])