Commit 5de858d5 authored by Xavier Thompson's avatar Xavier Thompson

slapproxy: Show shared in slapos service list/info

Improve hateoas support to show shared instances.
parent 9ec07439
...@@ -1037,6 +1037,29 @@ def busy_root_partitions_list(title=None): ...@@ -1037,6 +1037,29 @@ def busy_root_partitions_list(title=None):
partitions.append(p) partitions.append(p)
return partitions return partitions
def busy_root_shared_list(title=None):
shared = []
query = 'SELECT * FROM %s WHERE asked_by==""'
args = []
if title:
query += ' AND reference=?'
args.append('_' + title)
for row in execute_db('slave', query, args):
host = execute_db('partition', 'SELECT * FROM %s WHERE reference=?', [row['hosted_by']], one=True)
if not host:
continue
for slave_dict in loads(host['slave_instance_list'].encode('utf-8')):
if slave_dict['slave_reference'] == row['reference']:
break
else:
continue
s = {}
s['url_string'] = host['software_release']
s['title'] = row['reference'][1:] # root shared are prefixed with _
s['relative_url'] = url_for('hateoas_shared', shared_reference=s['title'])
shared.append(s)
return shared
def computers_list(reference=None): def computers_list(reference=None):
computers = [] computers = []
query = 'SELECT * FROM %s' query = 'SELECT * FROM %s'
...@@ -1066,11 +1089,14 @@ p_computer_info = p_computer_list + ' AND reference:=' ...@@ -1066,11 +1089,14 @@ p_computer_info = p_computer_list + ' AND reference:='
def parse_query(query): def parse_query(query):
if query == p_service_list: if query == p_service_list:
return busy_root_partitions_list() return busy_root_partitions_list() + busy_root_shared_list()
elif query.startswith(p_service_info): elif query.startswith(p_service_info):
title = query[len(p_service_info):] title = query[len(p_service_info):]
if is_valid(title): if is_valid(title):
return busy_root_partitions_list(title.strip('"')) partition = busy_root_partitions_list(title.strip('"'))
if partition:
return partition
return busy_root_shared_list(title.strip('"'))
elif query == p_computer_list: elif query == p_computer_list:
return computers_list() return computers_list()
elif query.startswith(p_computer_info): elif query.startswith(p_computer_info):
...@@ -1084,6 +1110,38 @@ def hateoas_partitions(partition_reference): ...@@ -1084,6 +1110,38 @@ def hateoas_partitions(partition_reference):
partition = execute_db('partition', 'SELECT * FROM %s WHERE partition_reference=?', [partition_reference], one=True) partition = execute_db('partition', 'SELECT * FROM %s WHERE partition_reference=?', [partition_reference], one=True)
if partition is None: if partition is None:
abort(404) abort(404)
partition['reference']=partition['partition_reference']
return hateoas_service_document(**partition, shared=0)
@app.route('/hateoas/shared/<shared_reference>', methods=['GET'])
def hateoas_shared(shared_reference):
slave_reference = '_' + shared_reference # root shared are prefixed with _ in db
shared = execute_db('slave', 'SELECT * FROM %s WHERE reference=?', [slave_reference], one=True)
if shared is None:
abort(404)
partition = execute_db('partition', 'SELECT * FROM %s WHERE reference=?', [shared['hosted_by']], one=True)
if partition is None:
abort(404)
slave_list = loads(partition['slave_instance_list'].encode('utf-8'))
for slave_dict in slave_list:
if slave_dict['slave_reference'] == slave_reference:
break
else:
abort(404)
del slave_dict['slave_title'], slave_dict['slave_reference']
software_type = slave_dict.pop('slap_software_type')
xml = dict2xml(slave_dict)
return hateoas_service_document(
reference = shared_reference,
requested_state='unused',
xml=xml,
connection_xml=shared['connection_xml'],
software_release=partition['software_release'],
software_type=software_type,
shared=1,
)
def hateoas_service_document(**kw):
# my_slap_state corresponds to requested_state, not slap_state. # my_slap_state corresponds to requested_state, not slap_state.
return { return {
'_embedded': { '_embedded': {
...@@ -1096,37 +1154,37 @@ def hateoas_partitions(partition_reference): ...@@ -1096,37 +1154,37 @@ def hateoas_partitions(partition_reference):
'my_reference': { 'my_reference': {
'type': 'StringField', 'type': 'StringField',
'key': 'field_my_reference', 'key': 'field_my_reference',
'default': partition['partition_reference'], 'default': kw['reference'],
}, },
'my_slap_state': { 'my_slap_state': {
'type': 'StringField', 'type': 'StringField',
'key': 'field_my_slap_state', 'key': 'field_my_slap_state',
'default': partition['requested_state'], 'default': kw['requested_state'],
}, },
'my_text_content': { 'my_text_content': {
'type': 'StringField', 'type': 'StringField',
'key': 'field_my_text_content', 'key': 'field_my_text_content',
'default': partition['xml'], 'default': kw['xml'],
}, },
'my_connection_parameter_list': { 'my_connection_parameter_list': {
'type': 'StringField', 'type': 'StringField',
'key': 'field_my_connection_parameter_list', 'key': 'field_my_connection_parameter_list',
'default': partition['connection_xml'], 'default': kw['connection_xml'],
}, },
'my_url_string': { 'my_url_string': {
'type': 'StringField', 'type': 'StringField',
'key': 'field_my_url_string', 'key': 'field_my_url_string',
'default': partition['software_release'], 'default': kw['software_release'],
}, },
'my_source_reference': { 'my_source_reference': {
'type': 'StringField', 'type': 'StringField',
'key': 'field_my_source_reference', 'key': 'field_my_source_reference',
'default': partition['software_type'], 'default': kw['software_type'],
}, },
'my_root_slave': { 'my_root_slave': {
'type': 'IntegerField', 'type': 'IntegerField',
'key': 'field_my_root_slave', 'key': 'field_my_root_slave',
'default': 0, 'default': kw['shared'],
}, },
}, },
}, },
......
...@@ -1289,6 +1289,16 @@ class TestCliInformation(CliMasterMixin): ...@@ -1289,6 +1289,16 @@ class TestCliInformation(CliMasterMixin):
json.loads(output), json.loads(output),
{'MyInstance0': 'http://sr0//', 'MyInstance1': 'http://sr1//', 'MyInstance2': 'http://sr2//'}) {'MyInstance0': 'http://sr0//', 'MyInstance1': 'http://sr1//', 'MyInstance2': 'http://sr2//'})
def test_service_list_with_shared(self):
self.format_for_number_of_partitions(1)
self.request('http://sr0//', None, 'MyHostInstance0', None)
self.request('http://sr0//', None, 'MySharedInstance1', None, shared=True)
self.request('http://sr0//', None, 'MySharedInstance2', None, shared=True)
output = self.cliDoSlapos(('service', 'list'), stderr=subprocess.DEVNULL)
self.assertEqual(
json.loads(output),
{'MyHostInstance0': 'http://sr0//', 'MySharedInstance1': 'http://sr0//', 'MySharedInstance2': 'http://sr0//'})
def test_service_info(self): def test_service_info(self):
self.format_for_number_of_partitions(3) self.format_for_number_of_partitions(3)
self.request('http://sr0//', None, 'MyInstance0', None) self.request('http://sr0//', None, 'MyInstance0', None)
...@@ -1326,6 +1336,38 @@ class TestCliInformation(CliMasterMixin): ...@@ -1326,6 +1336,38 @@ class TestCliInformation(CliMasterMixin):
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
self.assertIn('Instance MyInstance2 does not exist.', e.output) self.assertIn('Instance MyInstance2 does not exist.', e.output)
def test_service_info_with_shared(self):
self.format_for_number_of_partitions(1)
self.request('http://sr0//', 'MyType1', 'MyHostInstance0', None)
self.request('http://sr0//', 'MyType1', 'MySharedInstance1', None, shared=True, partition_parameter_kw={'couscous': 'hello'})
self.request('http://sr0//', 'MyType1', 'MySharedInstance2', None, shared=True, partition_parameter_kw={'couscous': 'bye'})
output0 = self.cliDoSlapos(('service', 'info', 'MySharedInstance1'), stderr=subprocess.DEVNULL)
self.assertEqual(
json.loads(output0),
{
"software-url": "http://sr0//",
"software-type": "MyType1",
"shared": True,
"requested-state": "unused",
"instance-parameters": {"couscous": "hello"},
"connection-parameters": {},
"status": "unsupported",
},
)
output1 = self.cliDoSlapos(('service', 'info', 'MySharedInstance2'), stderr=subprocess.DEVNULL)
self.assertEqual(
json.loads(output1),
{
"software-url": "http://sr0//",
"software-type": "MyType1",
"shared": True,
"requested-state": "unused",
"instance-parameters": {"couscous": "bye"},
"connection-parameters": {},
"status": "unsupported",
},
)
def test_invalid_service_names(self): def test_invalid_service_names(self):
invalid_names = ('"MyInstance0', 'MyInstance1"', 'My"Instance2', 'title:="MyInstance3"', 'reference:="MyInstance4"') invalid_names = ('"MyInstance0', 'MyInstance1"', 'My"Instance2', 'title:="MyInstance3"', 'reference:="MyInstance4"')
self.format_for_number_of_partitions(len(invalid_names)) self.format_for_number_of_partitions(len(invalid_names))
......
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