Commit abebfca0 authored by Romain Courteaud's avatar Romain Courteaud

slapos_json_rpc_api: request

parent 2a8c31c4
...@@ -28,6 +28,36 @@ ...@@ -28,6 +28,36 @@
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>jIOWebSection_requestSoftwareInstanceFromJSON</string> </value> <value> <string>jIOWebSection_requestSoftwareInstanceFromJSON</string> </value>
</item> </item>
<item>
<key> <string>output_schema</string> </key>
<value> <string>{\n
"$schema": "http://json-schema.org/draft-07/schema#",\n
"title": "Software Instance Requested",\n
"description": "Response when the software instance is requested",\n
"type": "object",\n
"additionalProperties": false,\n
"properties": {\n
"message": {\n
"title": "Message",\n
"type": "string"\n
},\n
"name": {\n
"title": "Name",\n
"type": "string"\n
},\n
"status": {\n
"title": "Status",\n
"type": "integer"\n
}\n
},\n
"required": [\n
"message",\n
"name",\n
"status"\n
]\n
}\n
</string> </value>
</item>
<item> <item>
<key> <string>portal_type</string> </key> <key> <string>portal_type</string> </key>
<value> <string>JSON Form</string> </value> <value> <string>JSON Form</string> </value>
...@@ -42,6 +72,10 @@ ...@@ -42,6 +72,10 @@
"type": "object",\n "type": "object",\n
"additionalProperties": false,\n "additionalProperties": false,\n
"properties": {\n "properties": {\n
"project_reference": {\n
"title": "Project Reference",\n
"type": "string"\n
},\n
"title": {\n "title": {\n
"title": "Title",\n "title": "Title",\n
"type": "string",\n "type": "string",\n
...@@ -124,7 +158,7 @@ ...@@ -124,7 +158,7 @@
"description": "Id Of the Requesting Compute Partition, used by Slap Client when an instance is requesting an instance"\n "description": "Id Of the Requesting Compute Partition, used by Slap Client when an instance is requesting an instance"\n
}\n }\n
},\n },\n
"required": ["title", "software_release_uri", "portal_type"]\n "required": ["title", "software_release_uri", "software_type", "portal_type"]\n
}\n }\n
</string> </value> </string> </value>
</item> </item>
......
import json
import urllib
compute_node_id = data_dict.get("compute_node_id", None) compute_node_id = data_dict.get("compute_node_id", None)
compute_partition_id = data_dict.get("compute_partition_id", None) compute_partition_id = data_dict.get("compute_partition_id", None)
class SoftwareInstanceNotReady(Exception):
pass
castToStr = context.Base_castDictToXMLString castToStr = context.Base_castDictToXMLString
def logError(e, error_name="", error_code=400, detail_list=None):
return portal.ERP5Site_logApiErrorAndReturn(
error_code=error_code,
error_message=e,
error_name=error_name,
detail_list=detail_list,
)
portal = context.getPortalObject() portal = context.getPortalObject()
# Loads partition parameter # Loads partition parameter
partition_parameter = data_dict.get("parameters", None) partition_parameter = data_dict.get("parameters", {})
if partition_parameter: # filter dict
try: filter_kw = data_dict.get("sla_parameters", {})
partition_parameter = json.loads(partition_parameter)
except ValueError, e: partition_reference = data_dict.get("title")
return logError( kw = dict(software_release=data_dict.get("software_release_uri"),
"Cannot Decode JSON Parameter. Error: %s" % e, software_type=data_dict.get("software_type"),
error_name="CANNOT-DECODE-COMPUTER-PARTITION-JSON-PARAMETER", software_title=partition_reference,
) instance_xml=castToStr(partition_parameter),
shared=data_dict.get("shared", False),
if not isinstance(partition_parameter, dict): sla_xml=castToStr(filter_kw),
return logError( state=data_dict.get("state", "started"),
"Parameters should be a key value object.", project_reference=data_dict.get("project_reference", None))
error_name="INCORRECT-COMPUTER-PARTITION-JSON-PARAMETER",
) if compute_node_id and compute_partition_id:
else: compute_partition = portal.portal_catalog.getComputePartitionObject(
partition_parameter = {} compute_node_id,
compute_partition_id,
try: )
# filter dict requester = compute_partition.getSoftwareInstance()
filter_kw = data_dict.get("sla_parameters", {}) instance_tree = requester.getSpecialiseValue()
partition_reference = data_dict.get("title") if instance_tree is not None:
kw = dict(software_release=urllib.unquote(data_dict.get("software_release_uri")), kw["project_reference"] = instance_tree.getFollowUpReference()
software_type=data_dict.get("software_type", "RootSoftwareInstance"),
software_title=partition_reference,
instance_xml=castToStr(partition_parameter),
shared=data_dict.get("shared", False),
sla_xml=castToStr(filter_kw),
state=data_dict.get("state", "started"),
project_reference=data_dict.get("project_reference", None))
if compute_node_id and compute_partition_id: if instance_tree.getSlapState() == "stop_requested":
compute_partition = portal.portal_catalog.getComputePartitionObject( kw['state'] = 'stopped'
compute_node_id,
compute_partition_id,
)
requester = compute_partition.getSoftwareInstance()
instance_tree = requester.getSpecialiseValue()
if instance_tree is not None: key = '_'.join([instance_tree.getRelativeUrl(), partition_reference])
kw["project_reference"] = instance_tree.getFollowUpReference() else:
# requested as root, so done by human
requester = portal.portal_membership.getAuthenticatedMember().getUserValue()
key = '_'.join([requester.getRelativeUrl(), partition_reference])
last_data = requester.getLastData(key)
requested_software_instance = None
value = dict(
hash='_'.join([requester.getRelativeUrl(), str(kw)]),
)
if instance_tree.getSlapState() == "stop_requested": if last_data is not None and isinstance(last_data, type(value)):
kw['state'] = 'stopped' requested_software_instance = portal.restrictedTraverse(
last_data.get('request_instance'), None)
key = '_'.join([instance_tree.getRelativeUrl(), partition_reference]) if last_data is None or not isinstance(last_data, type(value)) or \
last_data.get('hash') != value['hash'] or \
requested_software_instance is None:
if compute_node_id and compute_partition_id:
requester.requestInstance(**kw)
else: else:
# requested as root, so done by human # requester is a person so we use another method
requester = portal.portal_membership.getAuthenticatedMember().getUserValue() requester.requestSoftwareInstance(**kw)
key = '_'.join([requester.getRelativeUrl(), partition_reference]) requested_software_instance = context.REQUEST.get('request_instance')
last_data = requester.getLastData(key)
requested_software_instance = None
value = dict(
hash='_'.join([requester.getRelativeUrl(), str(kw)]),
)
if last_data is not None and isinstance(last_data, type(value)):
requested_software_instance = portal.restrictedTraverse(
last_data.get('request_instance'), None)
if last_data is None or not isinstance(last_data, type(value)) or \
last_data.get('hash') != value['hash'] or \
requested_software_instance is None:
if compute_node_id and compute_partition_id:
requester.requestInstance(**kw)
else:
# requester is a person so we use another method
requester.requestSoftwareInstance(**kw)
requested_software_instance = context.REQUEST.get('request_instance')
if requested_software_instance is not None:
value['request_instance'] = requested_software_instance\
.getRelativeUrl()
requester.setLastData(value, key=key)
if requested_software_instance is not None: if requested_software_instance is not None:
return requested_software_instance.asJSONText() value['request_instance'] = requested_software_instance\
raise SoftwareInstanceNotReady .getRelativeUrl()
except SoftwareInstanceNotReady: requester.setLastData(value, key=key)
return logError(
"Software Instance Not Ready", if requested_software_instance is not None:
error_name="SoftwareInstanceNotReady", return requested_software_instance.asJSONText()
error_code=102
) return {
'message': 'Software Instance Not Ready',
'status': 102,
'name': 'SoftwareInstanceNotReady'
}
...@@ -1437,89 +1437,73 @@ class TestSlapOSSlapToolPersonAccess(TestSlapOSJsonRpcMixin): ...@@ -1437,89 +1437,73 @@ class TestSlapOSSlapToolPersonAccess(TestSlapOSJsonRpcMixin):
self.assertEqual(instance.getTitle(), new_name) self.assertEqual(instance.getTitle(), new_name)
def test_PersonAccess_34_request_withSlave(self): def test_PersonAccess_34_request_withSlave(self):
self.called_instance_request = "" project_reference = self.project.getReference()
def calledRequestInstance(*args, **kw):
self.called_instance_request = kw
try: response = self.callJsonRpcWebService(
requestSoftwareInstance = self.person.__class__.requestSoftwareInstance "slapos.post.slapos_jio_api_request_software_instance",
project_reference = self.project.getReference() {
self.person.__class__.requestSoftwareInstance = calledRequestInstance
self.login(self.person_user_id)
response = self.callJsonRpcWebService("slapos.post.slapos_jio_api_request_software_instance", {
"portal_type": "Software Instance", "portal_type": "Software Instance",
"project_reference": project_reference, "project_reference": project_reference,
"software_release_uri": "req_release", "software_release_uri": "req_release",
"software_type": "req_type", "software_type": "req_type",
"title": "req_reference", "title": "req_reference",
"shared": True, "shared": True,
}) },
response_dict = json.loads(response.getBody()) self.person_user_id
if 400 != response.getStatus(): )
raise ValueError("Unexpected Result %s" % response_dict) self.assertEqual('application/json', response.headers.get('content-type'))
self.assertEqual('application/json', self.assertEqual({
response.headers.get('content-type')) 'message': 'Software Instance Not Ready',
self.assertEqual(self.called_instance_request, { 'name': 'SoftwareInstanceNotReady',
'instance_xml': "<?xml version='1.0' encoding='utf-8'?>\n<instance/>\n", 'status': 102
'project_reference': project_reference, }, byteify(json.loads(response.getBody())))
'software_title': 'req_reference', self.assertEqual(response.getStatus(), 200)
'software_release': 'req_release',
'state': 'started', self.tic()
'sla_xml': "<?xml version='1.0' encoding='utf-8'?>\n<instance/>\n", requested_instance_tree = self.portal.portal_catalog.getResultValue(
'software_type': 'req_type', portal_type='Instance Tree',
'shared': True title="req_reference"
}) )
self.assertTrue(response_dict.pop("$schema").endswith("error-response-schema.json")) self.assertEqual(requested_instance_tree.getDestinationSectionValue().getUserId(), self.person_user_id)
response_dict.pop("debug_id") self.assertEqual(requested_instance_tree.getFollowUpReference(), project_reference)
self.assertEqual(response_dict, { self.assertEqual(requested_instance_tree.getTitle(), "req_reference")
'message': 'Software Instance Not Ready', self.assertEqual(requested_instance_tree.getUrlString(), "req_release")
'name': 'SoftwareInstanceNotReady', self.assertEqual(requested_instance_tree.getSourceReference(), "req_type")
'status': 102 self.assertTrue(requested_instance_tree.isRootSlave())
})
finally:
self.person.__class__.requestSoftwareInstance = requestSoftwareInstance
def test_PersonAccess_35_request(self): def test_PersonAccess_35_request(self):
self.called_instance_request = "" project_reference = self.project.getReference()
def calledRequestInstance(*args, **kw):
self.called_instance_request = kw
try: response = self.callJsonRpcWebService(
requestSoftwareInstance = self.person.__class__.requestSoftwareInstance "slapos.post.slapos_jio_api_request_software_instance",
project_reference = self.project.getReference() {
self.person.__class__.requestSoftwareInstance = calledRequestInstance
self.login(self.person_user_id)
response = self.callJsonRpcWebService("slapos.post.slapos_jio_api_request_software_instance", {
"portal_type": "Software Instance", "portal_type": "Software Instance",
"project_reference": project_reference,
"software_release_uri": "req_release", "software_release_uri": "req_release",
"software_type": "req_type", "software_type": "req_type",
"title": "req_reference", "title": "req_reference"
"project_reference": project_reference },
}) self.person_user_id
response_dict = json.loads(response.getBody()) )
if 400 != response.getStatus(): self.assertEqual('application/json', response.headers.get('content-type'))
raise ValueError("Unexpected Result %s" % response_dict) self.assertEqual({
self.assertEqual('application/json', 'message': 'Software Instance Not Ready',
response.headers.get('content-type')) 'name': 'SoftwareInstanceNotReady',
self.assertEqual(self.called_instance_request, { 'status': 102
'instance_xml': "<?xml version='1.0' encoding='utf-8'?>\n<instance/>\n", }, byteify(json.loads(response.getBody())))
'project_reference': project_reference, self.assertEqual(response.getStatus(), 200)
'software_title': 'req_reference',
'software_release': 'req_release', self.tic()
'state': 'started', requested_instance_tree = self.portal.portal_catalog.getResultValue(
'sla_xml': "<?xml version='1.0' encoding='utf-8'?>\n<instance/>\n", portal_type='Instance Tree',
'software_type': 'req_type', title="req_reference"
'shared': False )
}) self.assertEqual(requested_instance_tree.getDestinationSectionValue().getUserId(), self.person_user_id)
self.assertTrue(response_dict.pop("$schema").endswith("error-response-schema.json")) self.assertEqual(requested_instance_tree.getFollowUpReference(), project_reference)
response_dict.pop("debug_id") self.assertEqual(requested_instance_tree.getTitle(), "req_reference")
self.assertEqual(response_dict, { self.assertEqual(requested_instance_tree.getUrlString(), "req_release")
'message': 'Software Instance Not Ready', self.assertEqual(requested_instance_tree.getSourceReference(), "req_type")
'name': 'SoftwareInstanceNotReady', self.assertFalse(requested_instance_tree.isRootSlave())
'status': 102
})
finally:
self.person.__class__.requestSoftwareInstance = requestSoftwareInstance
def test_PersonAccess_36_request_allocated_instance(self): def test_PersonAccess_36_request_allocated_instance(self):
self.tic() self.tic()
......
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