Skip to content

Commit

Permalink
Merge pull request #219 from AdaptiveScale/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
ailegion authored Jul 17, 2018
2 parents c477657 + a8bf697 commit 270eda9
Show file tree
Hide file tree
Showing 24 changed files with 3,173 additions and 72 deletions.
2 changes: 1 addition & 1 deletion app/__metadata__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
APP_NAME = 'LXDUI'
APP_CLI_CMD = 'lxdui'
VERSION = '2.1.1'
VERSION = '2.1.2'
GIT_URL = 'https://github.com/AdaptiveScale/lxdui.git'
LXD_URL = 'http://localhost:8443'
LICENSE = 'Apache 2.0'
Expand Down
40 changes: 40 additions & 0 deletions app/api/controllers/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,5 +181,45 @@ def unfreezeContainer(name):
container = LXCContainer({'name': name})
container.unfreeze()
return response.replySuccess(container.info(), message='Container {} is unfrozen.'.format(name))
except ValueError as e:
return response.replyFailed(message=e.__str__())


@container_api.route('/network/<name>/add', methods=['POST'])
@jwt_required()
def addNetwork(name):
input = request.get_json(silent=True)
try:
container = LXCContainer({'name': name})
return response.replySuccess(container.addNetwork(input))
except ValueError as e:
return response.replyFailed(message=e.__str__())


@container_api.route('/network/<name>/remove/<network>', methods=['DELETE'])
@jwt_required()
def removeNetwork(name, network):
try:
container = LXCContainer({'name': name})
return response.replySuccess(container.removeNetwork(network))
except ValueError as e:
return response.replyFailed(message=e.__str__())

@container_api.route('/proxy/<name>/add/<proxy>', methods=['POST'])
@jwt_required()
def addProxy(name, proxy):
input = request.get_json(silent=True)
try:
container = LXCContainer({'name': name})
return response.replySuccess(container.addProxy(proxy, input))
except ValueError as e:
return response.replyFailed(message=e.__str__())

@container_api.route('/proxy/<name>/remove/<proxy>', methods=['DELETE'])
@jwt_required()
def removeProxy(name, proxy):
try:
container = LXCContainer({'name': name})
return response.replySuccess(container.removeProxy(proxy))
except ValueError as e:
return response.replyFailed(message=e.__str__())
170 changes: 161 additions & 9 deletions app/api/controllers/fileManager.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,96 @@
from flask import Blueprint, request
from flask import Blueprint, request, send_file
from flask import jsonify
from flask_jwt import jwt_required

from app.api.models.LXCFileManager import LXCFileManager
from app.api.utils import response
from app.api.utils.authentication import jwt_decode_handler

import io
import json


file_manager_api = Blueprint('file_manager_api', __name__)


@file_manager_api.route('/container/<string:name>')
@file_manager_api.route('/content/container/<string:name>')
@jwt_required()
def list():
def content(name):
path = request.args.get('path')
if path == None:
return jsonify([])
#return response.replyFailed('Path is missing')

input = {}
input['name'] = name
input['path'] = path

try:
fileManager = LXCFileManager()
return response.reply(fileManager.list())

try:
#Folder
fileManager = LXCFileManager(input)
items = json.loads(fileManager.download().decode('utf-8'))['metadata']
return response.replyFailed('Please enter a valid file path')
except:
#File
result = fileManager.download().decode('utf-8')
return response.reply(result)

except ValueError as ex:
return response.replyFailed(ex.__str__())

@file_manager_api.route('/list/container/<string:name>')
@jwt_required()
def list(name):
path = request.args.get('path')
if path == None:
return jsonify([])
#return response.replyFailed('Path is missing')

input = {}
input['name'] = name
input['path'] = path

try:
fileManager = LXCFileManager(input)
try:
results = []
#Folder
items = json.loads(fileManager.download().decode('utf-8'))['metadata']
for item in items:
input['path'] = path + '/' + item
results.append({
'title': item,
'key': item,
'folder': isFolder(LXCFileManager(input)),
'lazy': isFolder(LXCFileManager(input)),
})

return jsonify(results)
return response.reply(results)
except:
#File
return jsonify([])
return response.replyFailed('Please enter a valid directory path')
#result = fileManager.download()

except ValueError as ex:
return response.replyFailed(ex.__str__())


def isFolder(fileManager):
try:
# Folder
result = json.loads(fileManager.download().decode('utf-8'))['metadata']
return True
except:
# File
result = fileManager.download()
return False


#List directory or open file
@file_manager_api.route('/container/<string:name>', methods=['PUT'])
@jwt_required()
def download(name):
Expand All @@ -26,18 +99,75 @@ def download(name):

try:
fileManager = LXCFileManager(input)
return response.reply(fileManager.download())

try:
# Folder
result = json.loads(fileManager.download().decode('utf-8'))['metadata']
except:
# File
result = fileManager.download()

return response.reply(result)
except ValueError as ex:
return response.replyFailed(ex.__str__())


@file_manager_api.route('/download/container/<string:name>', methods=['GET'])
def download_file(name):
path = request.args.get('path')
token = request.args.get('token')
print (token)
if not checkAuthentication(token):
return response.replyFailed('Not authorized')

if path == None:
return jsonify([])

input = {}
input['name'] = name
input['path'] = path

try:
try:
#Folder
fileManager = LXCFileManager(input)
items = json.loads(fileManager.download().decode('utf-8'))['metadata']
return response.replyFailed('Please select a file for download')
except:
#File
fileManager = LXCFileManager(input)
file = io.BytesIO(fileManager.download())
return send_file(file, attachment_filename=path.rsplit("/").pop(), mimetype="application/octet-stream", as_attachment=True)

except ValueError as ex:
return response.replyFailed(ex.__str__())


@file_manager_api.route('/container/<string:name>', methods=['POST'])
@jwt_required()
def upload_file(name):
input = None
try:
file = request.files.get('file')
input = {
'name':name,
'path':request.form.get('path')+file.filename,
'file':file
}
except:
return response.replyFailed(message='Missing one the required fields: [path,file]')

try:
fileManager = LXCFileManager(input)
return response.reply(fileManager.push())
except ValueError as ex:
return response.replyFailed(ex.__str__())


@file_manager_api.route('/new/container/<string:name>', methods=['POST'])
@jwt_required()
def new_file(name):
input = request.get_json(silent=True)
#validation = doValidate(input)
# if validation:
# return response.replyFailed(message=validation.message)

input['name'] = name

Expand All @@ -48,6 +178,21 @@ def upload_file(name):
return response.replyFailed(ex.__str__())


@file_manager_api.route('/edit/container/<string:name>', methods=['POST'])
@jwt_required()
def edit_file(name):
input = request.get_json(silent=True)

input['name'] = name

try:
fileManager = LXCFileManager(input)
fileManager.delete()
return response.reply(fileManager.push())
except ValueError as ex:
return response.replyFailed(ex.__str__())


@file_manager_api.route('/container/<string:name>', methods=['DELETE'])
@jwt_required()
def delete_profile(name):
Expand All @@ -64,3 +209,10 @@ def delete_profile(name):
return response.reply()
except ValueError as ex:
return response.replyFailed(message=ex.__str__())


def checkAuthentication(token):
try:
return jwt_decode_handler(token)
except Exception as e:
return False
50 changes: 49 additions & 1 deletion app/api/models/LXCContainer.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ def __init__(self, input):
super(LXCContainer, self).__init__(remoteHost=self.remoteHost)

if self.client.containers.exists(self.data.get('name')):
self.data['config'] = self.info()['config'];
existing = self.info()
self.data['config'] = existing['config'];
self.data['devices'] = existing['devices']

if input.get('image'):
self.setImageType(input.get('image'))
Expand Down Expand Up @@ -348,4 +350,50 @@ def unfreeze(self, waitIt=True):
logging.exception(e)
raise ValueError(e)

def initNetwork(self):
if not self.data.get('devices', None):
self.data['devices']={}

def addNetwork(self, network):
self.initNetwork()
self.data['devices'][network['name']]=network
try:
container = self.client.containers.get(self.data['name'])
container.devices = self.data['devices']
container.save()
return self.info()
except Exception as e:
raise ValueError(e)

def removeNetwork(self, networkName):
self.initNetwork()
del self.data['devices'][networkName]
try:
container = self.client.containers.get(self.data['name'])
container.devices = self.data['devices']
container.save()
return self.info()
except Exception as e:
raise ValueError(e)

def addProxy(self, name, proxy):
self.initNetwork()
self.data['devices'][name] = proxy
try:
container = self.client.containers.get(self.data['name'])
container.devices = self.data['devices']
container.save()
return self.info()
except Exception as e:
raise ValueError(e)

def removeProxy(self, name):
self.initNetwork()
del self.data['devices'][name]
try:
container = self.client.containers.get(self.data['name'])
container.devices = self.data['devices']
container.save()
return self.info()
except Exception as e:
raise ValueError(e)
2 changes: 1 addition & 1 deletion app/api/models/LXCFileManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def download(self):
logging.info('Download file {} from container {}'.format(self.input.get('path'), self.input.get('name')))
container = self.client.containers.get(self.input.get('name'))
file = container.files.get(self.input.get('path'))
return str(file)
return file
except Exception as e:
logging.error('Download file {} from container {} failed.'.format(self.input.get('path'), self.input.get('name')))
logging.exception(e)
Expand Down
12 changes: 8 additions & 4 deletions app/api/utils/remoteImageMapper.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@

def remoteImagesList(images):
response = []
aliasesProcessed = []
aliases = [alias[20:] for alias in images['metadata']]
for alias in aliases:
aliasesDetails = alias.split('/')
if len(aliasesDetails) > 2:
image = prepRemoteImageObject(alias, aliasesDetails)
if image not in response: response.append(image)
strippedAlias = alias.replace('/default','')
if strippedAlias not in aliasesProcessed:
aliasesDetails = alias.split('/')
if len(aliasesDetails) > 2:
image = prepRemoteImageObject(strippedAlias, aliasesDetails)
if image not in response: response.append(image)
aliasesProcessed.append(strippedAlias)

return response

Expand Down
1 change: 1 addition & 0 deletions app/ui/blueprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def containerDetails(name):
return render_template('container-details.html', currentpage='Container Details',
container=container.info(),
profiles = getProfiles(),
networks = LXDModule().listNetworks(),
lxdui_current_version=VERSION)
except ValueError as ex:
return render_template('container-details.html', currentpage='Container Details',
Expand Down
Loading

0 comments on commit 270eda9

Please sign in to comment.