Commit 246c5366 authored by Cédric Le Ninivin's avatar Cédric Le Ninivin

Proxy manage slave

parent 150c6784
--version:7 --version:9
CREATE TABLE IF NOT EXISTS software%(version)s (url VARCHAR(255) UNIQUE); CREATE TABLE IF NOT EXISTS software%(version)s (url VARCHAR(255) UNIQUE);
CREATE TABLE IF NOT EXISTS computer%(version)s ( CREATE TABLE IF NOT EXISTS computer%(version)s (
address VARCHAR(255), address VARCHAR(255),
...@@ -11,11 +11,19 @@ CREATE TABLE IF NOT EXISTS partition%(version)s ( ...@@ -11,11 +11,19 @@ CREATE TABLE IF NOT EXISTS partition%(version)s (
software_release VARCHAR(255), software_release VARCHAR(255),
xml TEXT, xml TEXT,
connection_xml TEXT, connection_xml TEXT,
slave_instance_list TEXT,
software_type VARCHAR(255), software_type VARCHAR(255),
partition_reference VARCHAR(255), partition_reference VARCHAR(255),
requested_by VARCHAR(255) requested_by VARCHAR(255)
); );
CREATE TABLE IF NOT EXISTS slave%(version)s (
reference VARCHAR(255) UNIQUE,
connection_xml TEXT,
hosted_by VARCHAR(255),
asked_by VARCHAR(255)
);
CREATE TABLE IF NOT EXISTS partition_network%(version)s ( CREATE TABLE IF NOT EXISTS partition_network%(version)s (
partition_reference VARCHAR(255), partition_reference VARCHAR(255),
reference VARCHAR(255), reference VARCHAR(255),
......
...@@ -30,15 +30,18 @@ ...@@ -30,15 +30,18 @@
from flask import g, Flask, request, abort from flask import g, Flask, request, abort
import xml_marshaller import xml_marshaller
from lxml import etree from lxml import etree
from slapos.slap.slap import Computer, ComputerPartition, SoftwareRelease, SoftwareInstance from slapos.slap.slap import Computer, ComputerPartition, \
SoftwareRelease, SoftwareInstance
import sqlite3 import sqlite3
app = Flask(__name__) app = Flask(__name__)
DB_VERSION = app.open_resource('schema.sql').readline().strip().split(':')[1] DB_VERSION = app.open_resource('schema.sql').readline().strip().split(':')[1]
class UnauthorizedError(Exception): class UnauthorizedError(Exception):
pass pass
def xml2dict(xml): def xml2dict(xml):
result_dict = {} result_dict = {}
if xml is not None and xml != '': if xml is not None and xml != '':
...@@ -54,16 +57,18 @@ def xml2dict(xml): ...@@ -54,16 +57,18 @@ def xml2dict(xml):
result_dict[key] = value result_dict[key] = value
return result_dict return result_dict
def dict2xml(dictionnary): def dict2xml(dictionnary):
instance = etree.Element('instance') instance = etree.Element('instance')
for parameter_id, parameter_value in dictionnary.iteritems(): for parameter_id, parameter_value in dictionnary.iteritems():
# cast everything to string # cast everything to string
parameter_value = str(parameter_value) parameter_value = str(parameter_value)
etree.SubElement(instance, "parameter", etree.SubElement(instance, "parameter",
attrib={'id':parameter_id}).text = parameter_value attrib={'id': parameter_id}).text = parameter_value
return etree.tostring(instance, pretty_print=True, return etree.tostring(instance, pretty_print=True,
xml_declaration=True, encoding='utf-8') xml_declaration=True, encoding='utf-8')
def partitiondict2partition(partition): def partitiondict2partition(partition):
slap_partition = ComputerPartition(app.config['computer_id'], slap_partition = ComputerPartition(app.config['computer_id'],
partition['reference']) partition['reference'])
...@@ -74,35 +79,43 @@ def partitiondict2partition(partition): ...@@ -74,35 +79,43 @@ def partitiondict2partition(partition):
slap_partition._need_modification = 0 slap_partition._need_modification = 0
slap_partition._parameter_dict = xml2dict(partition['xml']) slap_partition._parameter_dict = xml2dict(partition['xml'])
address_list = [] address_list = []
for address in execute_db('partition_network', 'SELECT * FROM %s WHERE partition_reference=?', [partition['reference']]): for address in execute_db('partition_network',
'SELECT * FROM %s WHERE partition_reference=?',
[partition['reference']]):
address_list.append((address['reference'], address['address'])) address_list.append((address['reference'], address['address']))
if not partition['slave_instance_list'] == None:
slap_partition._parameter_dict['slave_instance_list'] = \
xml_marshaller.xml_marshaller.loads(partition['slave_instance_list'])
slap_partition._parameter_dict['ip_list'] = address_list slap_partition._parameter_dict['ip_list'] = address_list
slap_partition._parameter_dict['slap_software_type'] = partition['software_type'] slap_partition._parameter_dict['slap_software_type'] = \
partition['software_type']
slap_partition._connection_dict = xml2dict(partition['connection_xml']) slap_partition._connection_dict = xml2dict(partition['connection_xml'])
slap_partition._software_release_document = SoftwareRelease( slap_partition._software_release_document = SoftwareRelease(
software_release=partition['software_release'], software_release=partition['software_release'],
computer_guid=app.config['computer_id']) computer_guid=app.config['computer_id'])
return slap_partition return slap_partition
def execute_db(table, query, args=(), one=False): def execute_db(table, query, args=(), one=False):
try: try:
cur = g.db.execute(query % (table + DB_VERSION,), args) cur = g.db.execute(query % (table + DB_VERSION,), args)
except: except:
app.logger.error('There was some issue during processing query %r on table %r with args %r' % (query, table, args)) app.logger.error('There was some issue during processing query %r on table %r with args %r' % (query, table, args))
raise raise
rv = [dict((cur.description[idx][0], value) rv = [dict((cur.description[idx][0], value)
for idx, value in enumerate(row)) for row in cur.fetchall()] for idx, value in enumerate(row)) for row in cur.fetchall()]
return (rv[0] if rv else None) if one else rv return (rv[0] if rv else None) if one else rv
def connect_db(): def connect_db():
return sqlite3.connect(app.config['DATABASE_URI']) return sqlite3.connect(app.config['DATABASE_URI'])
@app.before_request @app.before_request
def before_request(): def before_request():
g.db = connect_db() g.db = connect_db()
schema = app.open_resource('schema.sql') schema = app.open_resource('schema.sql')
schema = schema.read() % dict(version = DB_VERSION) schema = schema.read() % dict(version=DB_VERSION)
g.db.cursor().executescript(schema) g.db.cursor().executescript(schema)
g.db.commit() g.db.commit()
...@@ -150,16 +163,23 @@ def getFullComputerInformation(): ...@@ -150,16 +163,23 @@ def getFullComputerInformation():
@app.route('/setComputerPartitionConnectionXml', methods=['POST']) @app.route('/setComputerPartitionConnectionXml', methods=['POST'])
def setComputerPartitionConnectionXml(): def setComputerPartitionConnectionXml():
computer_id = request.form['computer_id'] slave_reference = request.form['slave_reference'].encode()
computer_partition_id = request.form['computer_partition_id'] computer_partition_id = request.form['computer_partition_id']
connection_xml = request.form['connection_xml'] connection_xml = request.form['connection_xml']
connection_dict = xml_marshaller.xml_marshaller.loads( connection_dict = xml_marshaller.xml_marshaller.loads(
connection_xml.encode()) connection_xml.encode())
connection_xml = dict2xml(connection_dict) connection_xml = dict2xml(connection_dict)
query = 'UPDATE %s SET connection_xml=? WHERE reference=?' if slave_reference == 'None':
argument_list = [connection_xml, computer_partition_id.encode()] query = 'UPDATE %s SET connection_xml=? WHERE reference=?'
execute_db('partition', query, argument_list) argument_list = [connection_xml, computer_partition_id.encode()]
return 'done' execute_db('partition', query, argument_list)
return 'done'
else:
query = 'UPDATE %s SET connection_xml=? , hosted_by=? WHERE reference=?'
argument_list = [connection_xml, computer_partition_id.encode(),
slave_reference]
execute_db('slave', query, argument_list)
return 'done'
@app.route('/buildingSoftwareRelease', methods=['POST']) @app.route('/buildingSoftwareRelease', methods=['POST'])
def buildingSoftwareRelease(): def buildingSoftwareRelease():
...@@ -167,8 +187,6 @@ def buildingSoftwareRelease(): ...@@ -167,8 +187,6 @@ def buildingSoftwareRelease():
@app.route('/availableSoftwareRelease', methods=['POST']) @app.route('/availableSoftwareRelease', methods=['POST'])
def availableSoftwareRelease(): def availableSoftwareRelease():
computer_id = request.form['computer_id']
url = request.form['url']
return 'Ignored' return 'Ignored'
@app.route('/softwareReleaseError', methods=['POST']) @app.route('/softwareReleaseError', methods=['POST'])
...@@ -177,43 +195,90 @@ def softwareReleaseError(): ...@@ -177,43 +195,90 @@ def softwareReleaseError():
@app.route('/buildingComputerPartition', methods=['POST']) @app.route('/buildingComputerPartition', methods=['POST'])
def buildingComputerPartition(): def buildingComputerPartition():
computer_id = request.form['computer_id']
computer_partition_id = request.form['computer_partition_id']
return 'Ignored' return 'Ignored'
@app.route('/availableComputerPartition', methods=['POST']) @app.route('/availableComputerPartition', methods=['POST'])
def availableComputerPartition(): def availableComputerPartition():
computer_id = request.form['computer_id']
computer_partition_id = request.form['computer_partition_id']
return 'Ignored' return 'Ignored'
@app.route('/softwareInstanceError', methods=['POST']) @app.route('/softwareInstanceError', methods=['POST'])
def softwareInstanceError(): def softwareInstanceError():
computer_id = request.form['computer_id']
computer_partition_id = request.form['computer_partition_id']
error_log = request.form['error_log']
return 'Ignored' return 'Ignored'
@app.route('/startedComputerPartition', methods=['POST']) @app.route('/startedComputerPartition', methods=['POST'])
def startedComputerPartition(): def startedComputerPartition():
computer_id = request.form['computer_id']
computer_partition_id = request.form['computer_partition_id']
return 'Ignored' return 'Ignored'
@app.route('/stoppedComputerPartition', methods=['POST']) @app.route('/stoppedComputerPartition', methods=['POST'])
def stoppedComputerPartition(): def stoppedComputerPartition():
computer_id = request.form['computer_id']
computer_partition_id = request.form['computer_partition_id']
return 'Ignored' return 'Ignored'
@app.route('/destroyedComputerPartition', methods=['POST']) @app.route('/destroyedComputerPartition', methods=['POST'])
def destroyedComputerPartition(): def destroyedComputerPartition():
computer_id = request.form['computer_id']
computer_partition_id = request.form['computer_partition_id']
return 'Ignored' return 'Ignored'
@app.route('/useComputer', methods=['POST'])
def useComputer():
return 'Ignored'
@app.route('/loadComputerConfigurationFromXML', methods=['POST'])
def loadComputerConfigurationFromXML():
xml = request.form['xml']
computer_dict = xml_marshaller.xml_marshaller.loads(str(xml))
if app.config['computer_id'] == computer_dict['reference']:
execute_db('computer', 'INSERT OR REPLACE INTO %s values(:address, :netmask)',
computer_dict)
for partition in computer_dict['partition_list']:
execute_db('partition', 'INSERT OR IGNORE INTO %s (reference) values(:reference)', partition)
execute_db('partition_network', 'DELETE FROM %s WHERE partition_reference = ?', [partition['reference']])
for address in partition['address_list']:
address['reference'] = partition['tap']['name']
address['partition_reference'] = partition['reference']
execute_db('partition_network', 'INSERT OR REPLACE INTO %s (reference, partition_reference, address, netmask) values(:reference, :partition_reference, :addr, :netmask)', address)
return 'done'
else:
raise UnauthorizedError, "Only accept request for: %s" % \
app.config['computer_id']
@app.route('/registerComputerPartition', methods=['GET'])
def registerComputerPartition():
computer_reference = request.args['computer_reference']
computer_partition_reference = request.args['computer_partition_reference']
if app.config['computer_id'] == computer_reference:
partition = execute_db('partition', 'SELECT * FROM %s WHERE reference=?',
[computer_partition_reference.encode()], one=True)
if partition is None:
raise UnauthorizedError
return xml_marshaller.xml_marshaller.dumps(
partitiondict2partition(partition))
else:
raise UnauthorizedError, "Only accept request for: %s" % \
app.config['computer_id']
@app.route('/supplySupply', methods=['POST'])
def supplySupply():
url = request.form['url']
computer_id = request.form['computer_id']
if app.config['computer_id'] == computer_id:
execute_db('software', 'INSERT OR REPLACE INTO %s VALUES(?)', [url])
else:
raise UnauthorizedError, "Only accept request for: %s" % \
app.config['computer_id']
return '%r added' % url
@app.route('/requestComputerPartition', methods=['POST']) @app.route('/requestComputerPartition', methods=['POST'])
def requestComputerPartition(): def requestComputerPartition():
shared_xml = request.form.get('shared_xml')
share = xml_marshaller.xml_marshaller.loads(shared_xml)
if not share:
return request_not_shared()
else:
return request_slave()
def request_not_shared():
software_release = request.form['software_release'].encode() software_release = request.form['software_release'].encode()
# some supported parameters # some supported parameters
software_type = request.form.get('software_type', 'RootSoftwareInstance' software_type = request.form.get('software_type', 'RootSoftwareInstance'
...@@ -261,7 +326,7 @@ def requestComputerPartition(): ...@@ -261,7 +326,7 @@ def requestComputerPartition():
q += ' ,requested_by=?' q += ' ,requested_by=?'
a(partition_id) a(partition_id)
if instance_xml: if instance_xml:
q+= ' ,xml=?' q += ' ,xml=?'
a(instance_xml) a(instance_xml)
q += ' WHERE reference=?' q += ' WHERE reference=?'
a(partition['reference'].encode()) a(partition['reference'].encode())
...@@ -280,70 +345,91 @@ def requestComputerPartition(): ...@@ -280,70 +345,91 @@ def requestComputerPartition():
slap_software_release_url=partition['software_release'], slap_software_release_url=partition['software_release'],
slap_server_url='slap_server_url', slap_server_url='slap_server_url',
slap_software_type=partition['software_type'], slap_software_type=partition['software_type'],
slave_id_list=[], slave_instance_list=partition['slave_instance_list'],
ip_list=address_list ip_list=address_list
))) )))
abort(408) abort(408)
computer_id = request.form.get('computer_id')
computer_partition_id = request.form.get('computer_partition_id')
software_type = request.form.get('software_type')
partition_reference = request.form.get('partition_reference')
shared_xml = request.form.get('shared_xml')
partition_parameter_xml = request.form.get('partition_parameter_xml')
filter_xml = request.form.get('filter_xml')
raise NotImplementedError raise NotImplementedError
@app.route('/useComputer', methods=['POST'])
def useComputer():
computer_id = request.form['computer_id']
use_string = request.form['use_string']
return 'Ignored'
@app.route('/loadComputerConfigurationFromXML', methods=['POST'])
def loadComputerConfigurationFromXML():
xml = request.form['xml']
computer_dict = xml_marshaller.xml_marshaller.loads(str(xml))
if app.config['computer_id'] == computer_dict['reference']:
args = []
a = args.append
execute_db('computer', 'INSERT OR REPLACE INTO %s values(:address, :netmask)',
computer_dict)
for partition in computer_dict['partition_list']:
execute_db('partition', 'INSERT OR IGNORE INTO %s (reference) values(:reference)', partition)
execute_db('partition_network', 'DELETE FROM %s WHERE partition_reference = ?', [partition['reference']])
for address in partition['address_list']:
address['reference'] = partition['tap']['name']
address['partition_reference'] = partition['reference']
execute_db('partition_network', 'INSERT OR REPLACE INTO %s (reference, partition_reference, address, netmask) values(:reference, :partition_reference, :addr, :netmask)', address)
return 'done' def request_slave():
"""
Function to organise link between slave and master
"""
software_release = request.form['software_release'].encode()
# some supported parameters
software_type = request.form.get('software_type').encode()
partition_reference = request.form.get('partition_reference', '').encode()
partition_id = request.form.get('computer_partition_id', '').encode()
partition_parameter_kw = request.form.get('partition_parameter_xml', None)
if partition_parameter_kw :
partition_parameter_kw = xml_marshaller.xml_marshaller.loads(
partition_parameter_kw.encode())
else: else:
raise UnauthorizedError, "Only accept request for: %s" % \ partition_parameter_kw = {}
app.config['computer_id'] instance_xml = dict2xml(partition_parameter_kw)
args = []
a = args.append
q = 'SELECT * FROM %s WHERE software_release=?'
a(software_release)
if software_type:
q += ' AND software_type=?'
a(software_type)
partition = execute_db('partition', q, args, one=True)
if partition is None:
app.logger.warning('No partition corresponding to slave request')
abort(408)
# Define Slave
new_slave = {}
slave_reference = partition_id + '_' + partition_reference
new_slave['slave_title'] = slave_reference
new_slave['slap_software_type'] = software_type
new_slave['slave_reference'] = slave_reference
for key in partition_parameter_kw :
new_slave[key] = partition_parameter_kw[key]
@app.route('/registerComputerPartition', methods=['GET']) # Add slave to partition slave_list if not present
def registerComputerPartition(): slave_instance_list = partition['slave_instance_list']
computer_reference = request.args['computer_reference'] if slave_instance_list == None:
computer_partition_reference = request.args['computer_partition_reference'] slave_instance_list = []
if app.config['computer_id'] == computer_reference:
partition = execute_db('partition', 'SELECT * FROM %s WHERE reference=?',
[computer_partition_reference.encode()], one=True)
if partition is None:
raise UnauthorizedError
return xml_marshaller.xml_marshaller.dumps(
partitiondict2partition(partition))
else: else:
raise UnauthorizedError, "Only accept request for: %s" % \ slave_instance_list = xml_marshaller.xml_marshaller.loads(slave_instance_list)
app.config['computer_id'] if not slave_reference in (x['slave_reference'] for x in slave_instance_list):
slave_instance_list.append(new_slave)
@app.route('/supplySupply', methods=['POST']) args = []
def supplySupply(): a = args.append
url = request.form['url'] q = 'UPDATE %s SET slave_instance_list=?'
computer_id = request.form['computer_id'] a(xml_marshaller.xml_marshaller.dumps(slave_instance_list))
if app.config['computer_id'] == computer_id: q += ' WHERE reference=?'
execute_db('software', 'INSERT OR REPLACE INTO %s VALUES(?)', [url]) a(partition['reference'].encode())
else: execute_db('partition', q, args)
raise UnauthorizedError, "Only accept request for: %s" % \ args = []
app.config['computer_id'] partition = execute_db('partition', 'SELECT * FROM %s WHERE reference=?',
return '%r added' % url [partition['reference'].encode()], one=True)
# Add slave to slave table if not there
slave = execute_db('slave', 'SELECT * FROM %s WHERE reference=?',
[slave_reference], one=True)
if slave is None :
execute_db('slave',
'INSERT OR IGNORE INTO %s (reference,asked_by) values(:reference,:asked_by)',
[slave_reference,partition_id])
slave = execute_db('slave','SELECT * FROM %s WHERE reference=?',
[slave_reference], one = True)
address_list = []
for address in execute_db('partition_network',
'SELECT * FROM %s WHERE partition_reference=?',
[partition['reference']]):
address_list.append((address['reference'], address['address']))
return xml_marshaller.xml_marshaller.dumps(SoftwareInstance(**dict(
_connection_dict=xml2dict(slave['connection_xml']),
xml = instance_xml,
slap_computer_id=app.config['computer_id'],
slap_computer_partition_id=slave['hosted_by'],
slap_software_release_url=partition['software_release'],
slap_server_url='slap_server_url',
slap_software_type=partition['software_type'],
ip_list=address_list
)))
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment