Blame view

slapos/runner/views.py 31.9 KB
Alain Takoudjou committed
1
# -*- coding: utf-8 -*-
Marco Mariani committed
2
# vim: set et sts=2:
Marco Mariani committed
3 4
# pylint: disable-msg=W0311,C0301,C0103,C0111

Nicolas Wavrant committed
5
import codecs
Nicolas Wavrant committed
6
import json
Łukasz Nowak committed
7 8
import os
import shutil
Nicolas Wavrant committed
9
import subprocess
Nicolas Wavrant committed
10
import sup_process
Nicolas Wavrant committed
11
import thread
Alain Takoudjou committed
12
import urllib
Łukasz Nowak committed
13

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

17
import slapos
Alain Takoudjou committed
18
from slapos.runner.utils import (checkSoftwareFolder, configNewSR, checkUserCredential,
Nicolas Wavrant committed
19 20
                                 createNewUser, getBuildAndRunParams,
                                 getProfilePath, getSlapgridResult,
Nicolas Wavrant committed
21
                                 html_escape,
Nicolas Wavrant committed
22
                                 listFolder, getBuildAndRunParams,
Alain Takoudjou committed
23
                                 getProjectTitle, getRcode, updateUserCredential,
Cédric Le Ninivin committed
24
                                 getSlapStatus, getSvcStatus,
Alain Takoudjou committed
25
                                 getSvcTailProcess, getUsernameList, isInstanceRunning,
Nicolas Wavrant committed
26
                                 isSoftwareRunning, isSoftwareReleaseReady, isText,
Cédric Le Ninivin committed
27 28
                                 loadSoftwareRList, md5sum, newSoftware,
                                 readFileFrom, readParameters, realpath,
Nicolas Wavrant committed
29
                                 removeCurrentInstance,
Nicolas Wavrant committed
30
                                 removeSoftwareByName, runSlapgridUntilSuccess,
Alain Takoudjou committed
31
                                 saveBuildAndRunParams,
Nicolas Wavrant committed
32
                                 setMiniShellHistory,
33
                                 stopProxy,
34
                                 svcStartStopProcess, svcStartAll, svcStopAll, tail,
Nicolas Wavrant committed
35
                                 updateInstanceParameter)
Cédric Le Ninivin committed
36

Alain Takoudjou committed
37
from git import GitCommandError
Marco Mariani committed
38
from slapos.runner.fileBrowser import FileBrowser
Cédric Le Ninivin committed
39
from slapos.runner.gittools import (cloneRepo, gitStatus, switchBranch,
Alain Takoudjou committed
40 41
                                    addBranch, getDiff, gitCommit, gitPush,
                                    gitPull, updateGitConfig, safeResult)
Marco Mariani committed
42 43


Łukasz Nowak committed
44
app = Flask(__name__)
Alain Takoudjou committed
45
app.config['MAX_CONTENT_LENGTH'] = 20 * 1024 * 1024
Marco Mariani committed
46
file_request = FileBrowser(app.config)
Alain Takoudjou committed
47

Cédric de Saint Martin committed
48
import logging
Nicolas Wavrant committed
49
logger = logging.getLogger('slaprunner')
Marco Mariani committed
50

Alain Takoudjou committed
51 52
def login_redirect(*args, **kwargs):
  return redirect(url_for('login'))
Łukasz Nowak committed
53

Nicolas Wavrant committed
54

Alain Takoudjou committed
55 56
@app.before_request
def before_request():
Nicolas Wavrant committed
57 58
  if request.path.startswith('/static') \
    or request.path == '/isSRReady':
Nicolas Wavrant committed
59
    return
Alain Takoudjou committed
60
  """
Marco Mariani committed
61 62 63 64 65 66 67
  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'))
Alain Takoudjou committed
68 69
  """
  session['title'] = getProjectTitle(app.config)
Nicolas Wavrant committed
70
  g.instance_monitoring_url =  app.config['instance_monitoring_url']
Nicolas Wavrant committed
71

Łukasz Nowak committed
72 73 74 75
# general views
def home():
  return render_template('index.html')

Marco Mariani committed
76

Alain Takoudjou committed
77 78 79 80
# general views
def browseWorkspace():
  return render_template('workspace.html')

Marco Mariani committed
81

Alain Takoudjou committed
82 83 84 85
@app.route("/login")
def login():
  return render_template('login.html')

Marco Mariani committed
86

Alain Takoudjou committed
87 88
@app.route("/setAccount")
def setAccount():
Alain Takoudjou committed
89
  """account = getSession(app.config)
Alain Takoudjou committed
90
  if not account:
Alain Takoudjou committed
91
    return render_template('account.html')
Alain Takoudjou committed
92
  return redirect(url_for('login'))"""
Alain Takoudjou committed
93

Marco Mariani committed
94

Alain Takoudjou committed
95
def myAccount():
Alain Takoudjou committed
96 97 98 99 100 101 102 103 104 105 106 107
  # account = getSession(app.config)
  git_user_path = os.path.join(app.config['etc_dir'], '.git_user')
  name = email = ""
  if os.path.exists(git_user_path):
    with open(git_user_path, 'r') as gfile:
      name, email = gfile.read().split(';')
  return render_template(
    'account.html',
    username_list=getUsernameList(app.config),
    email=email,
    name=name.decode('utf-8'),
    params=getBuildAndRunParams(app.config))
Alain Takoudjou committed
108

Marco Mariani committed
109

Nicolas Wavrant committed
110 111 112 113
def getSlapgridParameters():
  return jsonify(getBuildAndRunParams(app.config))


Nicolas Wavrant committed
114
def manageRepository():
Marco Mariani committed
115
  public_key = open(app.config['public_key']).read()
Alain Takoudjou committed
116 117 118 119
  account = [] #getSession(app.config)
  git_user_path = os.path.join(app.config['etc_dir'], '.git_user')
  name = email = ""
  if os.path.exists(git_user_path):
Nicolas Wavrant committed
120
    with codecs.open(git_user_path, 'r', encoding='utf-8') as gfile:
Alain Takoudjou committed
121
      name, email = gfile.read().split(';')
Nicolas Wavrant committed
122 123
  return render_template('manageRepository.html', workDir='workspace',
            project=listFolder(app.config, 'workspace'),
Alain Takoudjou committed
124 125
            public_key=public_key, name=name.decode('utf-8'),
            email=email)
Alain Takoudjou committed
126

Marco Mariani committed
127

Alain Takoudjou committed
128 129
@app.route("/doLogin", methods=['POST'])
def doLogin():
Nicolas Wavrant committed
130 131 132
  #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="")
Alain Takoudjou committed
133 134


Łukasz Nowak committed
135 136
# software views
def editSoftwareProfile():
Alain Takoudjou committed
137
  profile = getProfilePath(app.config['etc_dir'], app.config['software_profile'])
Alain Takoudjou committed
138 139
  if profile == "":
    flash('Error: can not open profile, please select your project first')
Alain Takoudjou committed
140
  return render_template('updateSoftwareProfile.html', workDir='workspace',
Alain Takoudjou committed
141
      profile=profile, projectList=listFolder(app.config, 'workspace'))
Łukasz Nowak committed
142

Marco Mariani committed
143

Łukasz Nowak committed
144
def inspectSoftware():
Alain Takoudjou committed
145 146
  return render_template('runResult.html', softwareRoot='software_link/',
                         softwares=loadSoftwareRList(app.config))
Łukasz Nowak committed
147

Marco Mariani committed
148

Alain Takoudjou committed
149
#remove content of compiled software release
Łukasz Nowak committed
150 151 152
def removeSoftware():
  if isSoftwareRunning(app.config) or isInstanceRunning(app.config):
    flash('Software installation or instantiation in progress, cannot remove')
Alain Takoudjou committed
153
  elif os.path.exists(app.config['software_root']):
Łukasz Nowak committed
154 155
    svcStopAll(app.config)
    shutil.rmtree(app.config['software_root'])
Alain Takoudjou committed
156 157
    for link in os.listdir(app.config['software_link']):
      os.remove(os.path.join(app.config['software_link'], link))
Łukasz Nowak committed
158 159 160
    flash('Software removed')
  return redirect(url_for('inspectSoftware'))

Marco Mariani committed
161

Łukasz Nowak committed
162
def runSoftwareProfile():
Nicolas Wavrant committed
163 164
  thread.start_new_thread(runSlapgridUntilSuccess, (app.config, "software"))
  return jsonify(result=True)
Marco Mariani committed
165

Łukasz Nowak committed
166 167 168

# instance views
def editInstanceProfile():
Alain Takoudjou committed
169
  profile = getProfilePath(app.config['etc_dir'], app.config['instance_profile'])
Alain Takoudjou committed
170
  if profile == "":
Alain Takoudjou committed
171 172
    flash('Error: can not open instance profile for this Software Release')
  return render_template('updateInstanceProfile.html', workDir='workspace',
Alain Takoudjou committed
173
      profile=profile, projectList=listFolder(app.config, 'workspace'))
Łukasz Nowak committed
174

Marco Mariani committed
175

Alain Takoudjou committed
176
# get status of all computer partitions and process state
Łukasz Nowak committed
177 178
def inspectInstance():
  if os.path.exists(app.config['instance_root']):
Marco Mariani committed
179 180 181 182 183
    file_path = 'instance_root'
    supervisor = getSvcStatus(app.config)
  else:
    file_path = ''
    supervisor = []
Nicolas Wavrant committed
184 185 186 187 188 189 190 191
  if "application/json" in request.accept_mimetypes.best:
    result_list = []
    for service in supervisor:
      result_list.append({
        'service_name': service[0],
        'status': service[1],
      })
    return jsonify(result_list)
Łukasz Nowak committed
192
  return render_template('instanceInspect.html',
Marco Mariani committed
193 194 195 196
                         file_path=file_path,
                         supervisor=supervisor,
                         slap_status=getSlapStatus(app.config),
                         partition_amount=app.config['partition_amount'])
Łukasz Nowak committed
197

198 199 200 201 202 203 204 205 206
def getConnectionParameter(partition_reference):
  """
  Return connection parameters of a partition.
  """
  slap = slapos.slap.slap()
  slap.initializeConnection(app.config['master_url'])
  partition = slap.registerComputerPartition(app.config['computer_id'], partition_reference)
  return jsonify(partition.getConnectionParameterDict())
app.add_url_rule("/getConnectionParameter/<partition_reference>", 'getConnectionParameter', getConnectionParameter, methods=['GET'])
Łukasz Nowak committed
207

Alain Takoudjou committed
208
#Reload instance process ans returns new value to ajax
Alain Takoudjou committed
209 210
def supervisordStatus():
  result = getSvcStatus(app.config)
Marco Mariani committed
211
  if not result:
Alain Takoudjou committed
212
    return jsonify(code=0, result="")
Marco Mariani committed
213
  # XXX-Marco -> template
Alain Takoudjou committed
214 215 216
  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>"
Marco Mariani committed
217
    html += "<td  class='first'><b><a href='" + url_for('tailProcess', process=item[0]) + "'>" + item[0] + "</a></b></td>"
Nicolas Wavrant committed
218
    html += "<td align='center'><a href='" + url_for('startStopProccess', process=item[0], action=item[1]) + "'>" + item[1] + "</a></td>"
Marco Mariani committed
219
    html += "<td align='center'>" + item[3] + "</td><td>" + item[5] + "</td>"
Marco Mariani committed
220
    html += "<td align='center'><a href='" + url_for('startStopProccess', process=item[0], action='RESTART') + "'>Restart</a></td>"
Marco Mariani committed
221
    html += "</tr>"
Alain Takoudjou committed
222 223
  return jsonify(code=1, result=html)

Marco Mariani committed
224

Łukasz Nowak committed
225
def removeInstance():
Thomas Gambier committed
226
  logger.warning("User clicked on 'Destroy All Services'. Removing all instances...")
Nicolas Wavrant committed
227 228 229
  result = removeCurrentInstance(app.config)
  if isinstance(result, str):
    flash(result)
Łukasz Nowak committed
230 231
  return redirect(url_for('inspectInstance'))

Marco Mariani committed
232

Łukasz Nowak committed
233 234 235
def runInstanceProfile():
  if not os.path.exists(app.config['instance_root']):
    os.mkdir(app.config['instance_root'])
Nicolas Wavrant committed
236 237
  thread.start_new_thread(runSlapgridUntilSuccess, (app.config, "instance"))
  return jsonify(result=True)
Marco Mariani committed
238

Łukasz Nowak committed
239

Nicolas Wavrant committed
240 241 242 243 244 245 246 247 248
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 committed
249
  else:
Nicolas Wavrant committed
250 251
    file_path = realpath(app.config, logfile)
  try:
Nicolas Wavrant committed
252 253
    if not os.path.exists(file_path):
      raise IOError
Nicolas Wavrant committed
254
    if not isText(file_path):
Nicolas Wavrant committed
255
      content = "Can not open binary file, please select a text file!"
Nicolas Wavrant committed
256 257 258 259
    if 'truncate' in request.form:
      content = tail(open(file_path), int(request.form['truncate']))
    else:
      with open(file_path) as f:
Nicolas Wavrant committed
260 261
        content = f.read()
    return jsonify(code=1, result=html_escape(content))
Nicolas Wavrant committed
262 263
  except:
    return jsonify(code=0, result="Warning: Log file doesn't exist yet or empty log!!")
Łukasz Nowak committed
264

Marco Mariani committed
265

Łukasz Nowak committed
266 267 268
def stopAllPartition():
  svcStopAll(app.config)
  return redirect(url_for('inspectInstance'))
Alain Takoudjou committed
269

270 271 272
def startAllPartition():
  svcStartAll(app.config)
  return redirect(url_for('inspectInstance'))
Marco Mariani committed
273

Alain Takoudjou committed
274 275 276 277
def tailProcess(process):
  return render_template('processTail.html',
      process_log=getSvcTailProcess(app.config, process), process=process)

Marco Mariani committed
278

Alain Takoudjou committed
279 280 281 282
def startStopProccess(process, action):
  svcStartStopProcess(app.config, process, action)
  return redirect(url_for('inspectInstance'))

Marco Mariani committed
283

Alain Takoudjou committed
284
def openProject(method):
Alain Takoudjou committed
285 286
  return render_template('projectFolder.html', method=method,
                         workDir='workspace')
Alain Takoudjou committed
287

Marco Mariani committed
288

Alain Takoudjou committed
289
def cloneRepository():
Alain Takoudjou committed
290
  path = realpath(app.config, request.form['name'], False)
Alain Takoudjou committed
291 292 293 294 295 296 297
  if not path:
    return jsonify(code=0, result="Can not access folder: Permission Denied")
  try:
    cloneRepo(request.form['repo'], path, request.form['user'], request.form['email'])
    return jsonify(code=1, result="")
  except GitCommandError, e:
    return jsonify(code=0, result=safeResult(str(e)))
Alain Takoudjou committed
298

Marco Mariani committed
299

Nicolas Wavrant committed
300 301 302
def listDirectory():
  folderList = listFolder(app.config, request.form['name'])
  return jsonify(result=folderList)
Alain Takoudjou committed
303

Marco Mariani committed
304

Alain Takoudjou committed
305
def createSoftware():
Alain Takoudjou committed
306
  return newSoftware(request.form['folder'], app.config, session)
Alain Takoudjou committed
307

Marco Mariani committed
308

Alain Takoudjou committed
309 310 311
def checkFolder():
  return checkSoftwareFolder(request.form['path'], app.config)

Marco Mariani committed
312

Alain Takoudjou committed
313 314
def setCurrentProject():
  if configNewSR(app.config, request.form['path']):
Alain Takoudjou committed
315 316 317
    session['title'] = getProjectTitle(app.config)
    return jsonify(code=1, result="")
  else:
Alain Takoudjou committed
318
    return jsonify(code=0, result=("Can not setup this Software Release"))
Alain Takoudjou committed
319

Marco Mariani committed
320

Alain Takoudjou committed
321
def getProjectStatus():
Alain Takoudjou committed
322 323
  path = realpath(app.config, request.form['project'])
  if path:
Alain Takoudjou committed
324 325 326 327 328
    try:
      result, branch, isdirty = gitStatus(path)
      return jsonify(code=1, result=result, branch=branch, dirty=isdirty)
    except GitCommandError, e:
      return jsonify(code=0, result=safeResult(str(e)))
Alain Takoudjou committed
329 330
  else:
    return jsonify(code=0, result="Can not read folder: Permission Denied")
Alain Takoudjou committed
331

Marco Mariani committed
332

Alain Takoudjou committed
333
#view for current software release files
Alain Takoudjou committed
334
def editCurrentProject():
Cédric Le Ninivin committed
335 336 337 338 339
  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()
Alain Takoudjou committed
340
  projectList = listFolder(app.config, 'workspace')
Cédric Le Ninivin committed
341
  if projectList:
Nicolas Wavrant committed
342
    return render_template('softwareFolder.html', workDir='runner_workdir',
Cédric Le Ninivin committed
343
                           project=project,
Alain Takoudjou committed
344
                           projectList=projectList)
Cédric Le Ninivin committed
345
  else:
Nicolas Wavrant committed
346 347
    flash('Please clone slapos repository, or your own repository')
    return redirect(url_for('manageRepository'))
Marco Mariani committed
348

Alain Takoudjou committed
349
#create file or directory
Alain Takoudjou committed
350
def createFile():
Alain Takoudjou committed
351 352
  path = realpath(app.config, request.form['file'], False)
  if not path:
Marco Mariani committed
353
    return jsonify(code=0, result="Error when creating your %s: Permission Denied" % request.form['type'])
Alain Takoudjou committed
354 355
  try:
    if request.form['type'] == "file":
Marco Mariani committed
356
      open(path, 'w')
Alain Takoudjou committed
357
    else:
Alain Takoudjou committed
358
      os.mkdir(path)
Alain Takoudjou committed
359
    return jsonify(code=1, result="")
Marco Mariani committed
360
  except Exception as e:
Alain Takoudjou committed
361 362
    return jsonify(code=0, result=str(e))

Marco Mariani committed
363

Alain Takoudjou committed
364
#remove file or directory
Alain Takoudjou committed
365 366 367 368 369 370 371
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 committed
372
  except Exception as e:
Alain Takoudjou committed
373
    return jsonify(code=0, result=str(e))
Alain Takoudjou committed
374

Marco Mariani committed
375

Alain Takoudjou committed
376
def removeSoftwareDir():
Nicolas Wavrant committed
377 378 379
    status, message = removeSoftwareByName(app.config, request.form['md5'],
      request.form['title'])
    return jsonify(code=status, result=message)
Alain Takoudjou committed
380

Marco Mariani committed
381

Alain Takoudjou committed
382
#read file and return content to ajax
Alain Takoudjou committed
383
def getFileContent():
Alain Takoudjou committed
384 385
  file_path = realpath(app.config, request.form['file'])
  if file_path:
Alain Takoudjou committed
386 387 388
    if not isText(file_path):
      return jsonify(code=0,
            result="Can not open a binary file, please select a text file!")
Marco Mariani committed
389
    if 'truncate' in request.form:
Nicolas Wavrant committed
390
      content = tail(codecs.open(file_path, "r", "utf_8"), int(request.form['truncate']))
Alain Takoudjou committed
391
      return jsonify(code=1, result=content)
Marco Mariani committed
392
    else:
Nicolas Wavrant committed
393
      return jsonify(code=1, result=codecs.open(file_path, "r", "utf_8").read())
Alain Takoudjou committed
394 395
  else:
    return jsonify(code=0, result="Error: No such file!")
Alain Takoudjou committed
396

Marco Mariani committed
397

Alain Takoudjou committed
398
def saveFileContent():
Nicolas Wavrant committed
399
  file_path = realpath(app.config, request.form['file'], False)
Alain Takoudjou committed
400
  if file_path:
Nicolas Wavrant committed
401 402
    with open(file_path, 'w') as f:
      f.write(request.form['content'].encode("utf-8"))
Alain Takoudjou committed
403 404
    return jsonify(code=1, result="")
  else:
Nicolas Wavrant committed
405
    return jsonify(code=0, result="Rejected!! Cannot access to this location.")
Alain Takoudjou committed
406

Marco Mariani committed
407

Alain Takoudjou committed
408
def changeBranch():
Alain Takoudjou committed
409 410
  path = realpath(app.config, request.form['project'])
  if path:
Alain Takoudjou committed
411 412 413 414 415 416 417 418
    try:
      if switchBranch(path, request.form['name']):
        return jsonify(code=1, result="")
      else:
        json = "This is already your active branch for this project"
        return jsonify(code=1, result=json)
    except GitCommandError, e:
      return jsonify(code=0, result=safeResult(str(e)))
Alain Takoudjou committed
419 420
  else:
    return jsonify(code=0, result="Can not read folder: Permission Denied")
Alain Takoudjou committed
421

Marco Mariani committed
422

Alain Takoudjou committed
423
def newBranch():
Alain Takoudjou committed
424 425
  path = realpath(app.config, request.form['project'])
  if path:
Alain Takoudjou committed
426 427 428 429 430 431 432 433 434 435 436
    try:
      if request.form['create'] == '1':
        result = addBranch(path, request.form['name'])
      else:
        result =  addBranch(path, request.form['name'], True)
      if result:
        return jsonify(code=1, result="")
      else:
        return jsonify(code=0, result="Failed to checkout to branch %s.")
    except GitCommandError, e:
      return jsonify(code=0, result=safeResult(str(e)))
Alain Takoudjou committed
437 438
  else:
    return jsonify(code=0, result="Can not read folder: Permission Denied")
Alain Takoudjou committed
439

Marco Mariani committed
440

Nicolas Wavrant committed
441
def getProjectDiff():
Nicolas Wavrant committed
442 443
  path = realpath(app.config, request.form['project'])
  if path:
Nicolas Wavrant committed
444
    return jsonify(code=1, result=getDiff(path))
Nicolas Wavrant committed
445
  else:
Nicolas Wavrant committed
446 447
    return jsonify(code=0,
                  result="Error: No such file or directory. PERMISSION DENIED!")
Alain Takoudjou committed
448

Marco Mariani committed
449

Nicolas Wavrant committed
450 451 452 453 454 455 456 457
def commitProjectFiles():
  path = realpath(app.config, request.form['project'])
  if path:
    return gitCommit(path, request.form['msg'])
  else:
    return jsonify(code=0, result="Can not read folder: Permission Denied")


Alain Takoudjou committed
458
def pushProjectFiles():
Alain Takoudjou committed
459 460
  path = realpath(app.config, request.form['project'])
  if path:
Nicolas Wavrant committed
461
    return gitPush(path)
Alain Takoudjou committed
462 463
  else:
    return jsonify(code=0, result="Can not read folder: Permission Denied")
Alain Takoudjou committed
464

Marco Mariani committed
465

Alain Takoudjou committed
466
def pullProjectFiles():
Alain Takoudjou committed
467 468 469 470 471
  path = realpath(app.config, request.form['project'])
  if path:
    return gitPull(path)
  else:
    return jsonify(code=0, result="Can not read folder: Permission Denied")
Alain Takoudjou committed
472

Marco Mariani committed
473

Alain Takoudjou committed
474
def checkFileType():
Alain Takoudjou committed
475 476 477
  path = realpath(app.config, request.form['path'])
  if not path:
    return jsonify(code=0, result="Can not open file: Permission Denied!")
Alain Takoudjou committed
478 479 480
  if isText(path):
    return jsonify(code=1, result="text")
  else:
Cédric Le Ninivin committed
481 482
    return jsonify(code=0,
                   result="Can not open a binary file, please select a text file!")
Alain Takoudjou committed
483

Marco Mariani committed
484

Alain Takoudjou committed
485
def getmd5sum():
Alain Takoudjou committed
486 487 488 489
  realfile = realpath(app.config, request.form['file'])
  if not realfile:
    return jsonify(code=0, result="Can not open file: Permission Denied!")
  md5 = md5sum(realfile)
Alain Takoudjou committed
490 491 492
  if md5:
    return jsonify(code=1, result=md5)
  else:
Alain Takoudjou committed
493 494
    return jsonify(code=0, result="Can not get md5sum for this file!")

Marco Mariani committed
495

Cédric Le Ninivin committed
496
#return information about state of slapgrid process
Alain Takoudjou committed
497 498 499
def slapgridResult():
  software_state = isSoftwareRunning(app.config)
  instance_state = isInstanceRunning(app.config)
Marco Mariani committed
500 501 502 503 504
  log_result = {
    'content': '',
    'position': 0,
    'truncated': False
  }
Marco Mariani committed
505
  if request.form['log'] in ['software', 'instance']:
Alain Takoudjou committed
506 507
    log_file = request.form['log'] + "_log"
    if os.path.exists(app.config[log_file]):
Marco Mariani committed
508 509
      log_result = readFileFrom(open(app.config[log_file]),
                                int(request.form['position']))
Nicolas Wavrant committed
510 511 512 513 514 515 516 517 518
  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 committed
519 520
                 result=(instance_state or software_state), content=log_result)

Alain Takoudjou committed
521 522

def stopSlapgrid():
Nicolas Wavrant committed
523 524
  counter_file = os.path.join(app.config['runner_workdir'], '.turn-left')
  open(counter_file, 'w+').write(str(0))
Nicolas Wavrant committed
525
  result = sup_process.killRunningProcess(app.config, request.form['type'])
Alain Takoudjou committed
526 527
  return jsonify(result=result)

Marco Mariani committed
528

Alain Takoudjou committed
529 530 531 532 533
def getPath():
  files = request.form['file'].split('#')
  list = []
  for p in files:
    path = realpath(app.config, p)
Alain Takoudjou committed
534
    if not path:
Alain Takoudjou committed
535 536 537 538
      list = []
      break
    else:
      list.append(path)
Marco Mariani committed
539
  realfile = '#'.join(list)
Alain Takoudjou committed
540
  if not realfile:
Cédric Le Ninivin committed
541 542
    return jsonify(code=0,
                   result="Can not access to this file: Permission Denied!")
Alain Takoudjou committed
543
  else:
Alain Takoudjou committed
544 545
    return jsonify(code=1, result=realfile)

Marco Mariani committed
546

Alain Takoudjou committed
547
def saveParameterXml():
Cédric de Saint Martin committed
548 549 550
  """
  Update instance parameter into a local xml file.
  """
Alain Takoudjou committed
551
  project = os.path.join(app.config['etc_dir'], ".project")
Alain Takoudjou committed
552 553
  if not os.path.exists(project):
    return jsonify(code=0, result="Please first open a Software Release")
Alain Takoudjou committed
554
  content = request.form['parameter'].encode("utf-8")
Alain Takoudjou committed
555
  param_path = os.path.join(app.config['etc_dir'], ".parameter.xml")
Alain Takoudjou committed
556
  try:
Marco Mariani committed
557 558
    with open(param_path, 'w') as f:
      f.write(content)
Alain Takoudjou committed
559
    result = readParameters(param_path)
Marco Mariani committed
560
  except Exception as e:
Marco Mariani committed
561
    result = str(e)
Alain Takoudjou committed
562
  software_type = None
Cédric de Saint Martin committed
563
  if request.form['software_type']:
Alain Takoudjou committed
564
    software_type = request.form['software_type']
Alain Takoudjou committed
565
  if type(result) == type(''):
Alain Takoudjou committed
566
    return jsonify(code=0, result=result)
Alain Takoudjou committed
567
  else:
Alain Takoudjou committed
568
    try:
Alain Takoudjou committed
569
      updateInstanceParameter(app.config, software_type)
Marco Mariani committed
570
    except Exception as e:
Cédric Le Ninivin committed
571 572
      return jsonify(
        code=0,
Marco Mariani committed
573
        result="An error occurred while applying your settings!<br/>%s" % e)
Alain Takoudjou committed
574 575
    return jsonify(code=1, result="")

Marco Mariani committed
576

577 578 579
def getSoftwareType():
  software_type_path = os.path.join(app.config['etc_dir'], ".software_type.xml")
  if os.path.exists(software_type_path):
Marco Mariani committed
580
    return jsonify(code=1, result=open(software_type_path).read())
581 582
  return jsonify(code=1, result="default")

Marco Mariani committed
583

Alain Takoudjou committed
584
#read instance parameters into the local xml file and return a dict
Alain Takoudjou committed
585
def getParameterXml(request):
Alain Takoudjou committed
586
  param_path = os.path.join(app.config['etc_dir'], ".parameter.xml")
Alain Takoudjou committed
587
  if not os.path.exists(param_path):
Marco Mariani committed
588
    default = '<?xml version="1.0" encoding="utf-8"?>\n<instance>\n</instance>'
Alain Takoudjou committed
589 590
    return jsonify(code=1, result=default)
  if request == "xml":
Marco Mariani committed
591
    parameters = open(param_path).read()
Alain Takoudjou committed
592 593 594 595
  else:
    parameters = readParameters(param_path)
  if type(parameters) == type('') and request != "xml":
    return jsonify(code=0, result=parameters)
Alain Takoudjou committed
596
  else:
Alain Takoudjou committed
597 598
    return jsonify(code=1, result=parameters)

Marco Mariani committed
599

Nicolas Wavrant committed
600
#update user-defined slapgrid parameters
Nicolas Wavrant committed
601
def updateBuildAndRunConfig():
Nicolas Wavrant committed
602 603 604 605 606 607 608 609 610 611 612
  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 =  {}
Nicolas Wavrant committed
613 614 615 616 617
    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)
Nicolas Wavrant committed
618 619 620 621
    result = "Your parameters have correctly been updated"
  return jsonify(code=code, result=result)


Alain Takoudjou committed
622 623
#update user account data
def updateAccount():
Marco Mariani committed
624

Alain Takoudjou committed
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
  username = request.form['username'].strip()
  password = request.form['password'].strip()
  new_password = request.form['new_password'].strip()
  email = request.form['email'].strip()
  name = request.form['name'].strip()

  if username and password and new_password:
    if not checkUserCredential(app.config, username, password):
      return jsonify(code=0, result="Username and password doesn't match for '%s'" % username)

    result = updateUserCredential(app.config, username, new_password)
    if not result:
      return jsonify(code=0, result="Failed to update Credentials!")

  try:
    updateGitConfig(app.config['default_repository_path'], name, email)
  except GitCommandError, e:
    return jsonify(code=0, result=str(e))
Nicolas Wavrant committed
643 644 645
  git_user_file = os.path.join(app.config['etc_dir'], '.git_user')
  with codecs.open(git_user_file, 'w', encoding='utf-8') as gfile:
    gfile.write(u'{};{}'.format(name, email))
Alain Takoudjou committed
646
  return jsonify(code=1, result="")
Alain Takoudjou committed
647

Marco Mariani committed
648

Alain Takoudjou committed
649 650 651
#update user account data
@app.route("/configAccount", methods=['POST'])
def configAccount():
Alain Takoudjou committed
652
  """last_account = getSession(app.config)
Marco Mariani committed
653 654 655 656 657 658 659 660 661 662
  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()
Nicolas Wavrant committed
663
  recovery_code = getRcode(app.config)
Marco Mariani committed
664 665 666 667 668 669
  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:
Alain Takoudjou committed
670
    return jsonify(code=1, result="")"""
Marco Mariani committed
671

Nicolas Wavrant committed
672 673 674 675 676 677 678
def addUser():
  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")

Alain Takoudjou committed
679

Alain Takoudjou committed
680 681 682 683 684 685 686 687 688 689 690 691 692
#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'))
Marco Mariani committed
693

Alain Takoudjou committed
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
  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)
Alain Takoudjou committed
749 750
  return result

Marco Mariani committed
751

Alain Takoudjou committed
752 753 754
def editFile():
  return render_template('editFile.html', workDir='workspace',
    profile=urllib.unquote(request.args.get('profile', '')),
Alain Takoudjou committed
755
    projectList=listFolder(app.config, 'workspace'),
Alain Takoudjou committed
756 757
    filename=urllib.unquote(request.args.get('filename', '')))

Nicolas Wavrant committed
758
def shell():
Nicolas Wavrant committed
759
  return render_template('shell.html')
Marco Mariani committed
760

Nicolas Wavrant committed
761

Nicolas Wavrant committed
762 763 764
def isSRReady():
  return isSoftwareReleaseReady(app.config)

Nicolas Wavrant committed
765

Nicolas Wavrant committed
766 767 768 769 770 771 772 773
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(' ');
Nicolas Wavrant committed
774
      real_cmd = cmd[:]
Nicolas Wavrant committed
775 776 777 778
      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]))
Nicolas Wavrant committed
779
      if os.path.exists(cd_dir) and os.path.isdir(cd_dir):
Nicolas Wavrant committed
780 781 782 783
        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
Nicolas Wavrant committed
784
        command = command.replace(' '.join(real_cmd), '').strip(';')
Nicolas Wavrant committed
785
        if not command:
Nicolas Wavrant committed
786
          return jsonify(path=cwd, data="Changed directory, now in : "+cwd)
Nicolas Wavrant committed
787
  try:
Nicolas Wavrant committed
788
    setMiniShellHistory(app.config, command)
Nicolas Wavrant committed
789
    command = "timeout 600 " + command
Cédric Le Ninivin committed
790
    return jsonify(path=cwd, data=subprocess.check_output(command, stderr=subprocess.STDOUT, shell=True, cwd=cwd, env={'PATH': app.config['path']}))
Nicolas Wavrant committed
791
  except subprocess.CalledProcessError as e:
Jérome Perrin committed
792
    return jsonify(path=cwd, data=e.output, returncode=e.returncode, error=True)
Nicolas Wavrant committed
793 794


Nicolas Wavrant committed
795 796 797 798 799 800 801 802 803 804
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)


Alain Takoudjou committed
805 806
#Setup List of URLs
app.add_url_rule('/', 'home', home)
Alain Takoudjou committed
807 808 809
app.add_url_rule('/browseWorkspace', 'browseWorkspace', browseWorkspace)
app.add_url_rule('/editSoftwareProfile', 'editSoftwareProfile',
                editSoftwareProfile)
Alain Takoudjou committed
810 811
app.add_url_rule('/inspectSoftware', 'inspectSoftware', inspectSoftware)
app.add_url_rule('/removeSoftware', 'removeSoftware', removeSoftware)
Cédric Le Ninivin committed
812
app.add_url_rule('/runSoftwareProfile', 'runSoftwareProfile',
813
                 runSoftwareProfile, methods=['GET', 'POST'])
Cédric Le Ninivin committed
814 815 816 817 818 819 820
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',
821
                 runInstanceProfile, methods=['GET', 'POST'])
Alain Takoudjou committed
822
app.add_url_rule('/removeInstance', 'removeInstance', removeInstance)
Nicolas Wavrant committed
823 824 825 826
app.add_url_rule('/viewLog', 'viewLog',
                 viewLog, methods=['GET'])
app.add_url_rule("/getFileLog", 'getFileLog', getFileLog,
                 methods=['POST'])
Cédric Le Ninivin committed
827 828
app.add_url_rule('/stopAllPartition', 'stopAllPartition',
                 stopAllPartition, methods=['GET'])
829 830
app.add_url_rule('/startAllPartition', 'startAllPartition',
                 startAllPartition, methods=['GET'])
Cédric Le Ninivin committed
831 832 833 834 835 836
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'])
837 838
app.add_url_rule('/getSoftwareType', 'getSoftwareType',
                 getSoftwareType, methods=['GET'])
Alain Takoudjou committed
839
app.add_url_rule("/stopSlapgrid", 'stopSlapgrid', stopSlapgrid, methods=['POST'])
Cédric Le Ninivin committed
840 841
app.add_url_rule("/slapgridResult", 'slapgridResult',
                 slapgridResult, methods=['POST'])
Alain Takoudjou committed
842
app.add_url_rule("/getmd5sum", 'getmd5sum', getmd5sum, methods=['POST'])
Cédric Le Ninivin committed
843 844
app.add_url_rule("/checkFileType", 'checkFileType', checkFileType,
                 methods=['POST'])
Nicolas Wavrant committed
845 846
app.add_url_rule("/commitProjectFiles", 'commitProjectFiles', commitProjectFiles,
                 methods=['POST'])
Cédric Le Ninivin committed
847 848 849 850
app.add_url_rule("/pullProjectFiles", 'pullProjectFiles', pullProjectFiles,
                 methods=['POST'])
app.add_url_rule("/pushProjectFiles", 'pushProjectFiles', pushProjectFiles,
                 methods=['POST'])
Nicolas Wavrant committed
851 852
app.add_url_rule("/getProjectDiff", 'getProjectDiff', getProjectDiff,
                 methods=['POST'])
Alain Takoudjou committed
853 854
app.add_url_rule("/newBranch", 'newBranch', newBranch, methods=['POST'])
app.add_url_rule("/changeBranch", 'changeBranch', changeBranch, methods=['POST'])
Cédric Le Ninivin committed
855 856 857 858 859 860
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'])
Alain Takoudjou committed
861 862 863
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 committed
864 865 866 867 868 869
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'])
Alain Takoudjou committed
870
app.add_url_rule("/checkFolder", 'checkFolder', checkFolder, methods=['POST'])
Cédric Le Ninivin committed
871 872 873 874
app.add_url_rule('/createSoftware', 'createSoftware', createSoftware,
                 methods=['POST'])
app.add_url_rule('/cloneRepository', 'cloneRepository', cloneRepository,
                 methods=['POST'])
Nicolas Wavrant committed
875 876
app.add_url_rule('/listDirectory', 'listDirectory', listDirectory, methods=['POST'])
app.add_url_rule('/manageRepository', 'manageRepository', manageRepository)
Cédric Le Ninivin committed
877 878
app.add_url_rule("/saveParameterXml", 'saveParameterXml', saveParameterXml,
                 methods=['POST'])
Alain Takoudjou committed
879 880
app.add_url_rule("/getPath", 'getPath', getPath, methods=['POST'])
app.add_url_rule("/myAccount", 'myAccount', myAccount)
Cédric Le Ninivin committed
881 882
app.add_url_rule("/updateAccount", 'updateAccount', updateAccount,
                 methods=['POST'])
Nicolas Wavrant committed
883
app.add_url_rule("/updateBuildAndRunConfig", 'updateBuildAndRunConfig', updateBuildAndRunConfig,
Nicolas Wavrant committed
884
                 methods=['POST'])
Cédric Le Ninivin committed
885 886
app.add_url_rule("/fileBrowser", 'fileBrowser', fileBrowser,
                 methods=['GET', 'POST'])
Alain Takoudjou committed
887
app.add_url_rule("/editFile", 'editFile', editFile, methods=['GET'])
Nicolas Wavrant committed
888
app.add_url_rule('/shell', 'shell', shell)
Nicolas Wavrant committed
889
app.add_url_rule('/isSRReady', 'isSRReady', isSRReady)
Nicolas Wavrant committed
890
app.add_url_rule('/addUser', 'addUser', addUser, methods=['POST'])
Nicolas Wavrant committed
891
app.add_url_rule('/getSlapgridParameters', 'getSlapgridParameters', getSlapgridParameters, methods=['GET'])
Nicolas Wavrant committed
892
app.add_url_rule('/runCommand', 'runCommand', runCommand, methods=['POST'])
Nicolas Wavrant committed
893
app.add_url_rule("/getMiniShellHistory", 'getMiniShellHistory', getMiniShellHistory, methods=['GET'])