Commit 26791acf authored by Cédric Le Ninivin's avatar Cédric Le Ninivin Committed by Romain Courteaud

slapos_jio_api_style: Add support to request instance

parent 5076d606
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_slapos_json_get</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_slapos_json_get</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>slapos_jio_api_get_software_instance</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Action Information</string> </value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>1.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Get Software Instance</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/Base_asJSONTextFromJSON</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_slapos_json_post</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_slapos_json_post</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>slapos_jio_api_request_software_instance</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>9.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Request Software Instance</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/jIOWebSection_requestComputerPartitionFromJSON</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="JSON Form" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>after_method_id</string> </key>
<value> <string>jIOWebSection_requestComputerPartition</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>application/json</string> </value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>jIOWebSection_requestComputerPartitionFromJSON</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>jIOWebSection_requestComputerPartitionFromJSON</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>JSON Form</string> </value>
</item>
<item>
<key> <string>text_content</string> </key>
<value> <string>{\n
"$schema": "http://json-schema.org/draft-07/schema#",\n
"$id": "software-instance-base-schema.json",\n
"title": "Software Instance",\n
"description": "Software Instance",\n
"type": "object",\n
"properties": {\n
"title": {\n
"title": "Title",\n
"type": "string",\n
"description": "Unique Name of the Software Instance",\n
"maxLength": 200\n
},\n
"software_release_uri": {\n
"title": "Software Release URI",\n
"type": "string",\n
"description": "URI of the Software Release to be used by the instance"\n
},\n
"software_type": {\n
"title": "Software Type",\n
"type": "string",\n
"description": "Software type to be requested"\n
},\n
"state": {\n
"title": "Requested State",\n
"type": "string",\n
"enum": ["started", "stopped", "destroyed"],\n
"default": "started",\n
"description": "State of the requested instance"\n
},\n
"parameters": {\n
"title": "Instance Parameters",\n
"type": "object",\n
"additionalProperties": { "type": "string" }\n
},\n
"shared": {\n
"title": "Shared Instance",\n
"type": "boolean",\n
"description": "Ask for a Shared Instance"\n
},\n
"sla_parameters": {\n
"title": "Target Node Selection Parameters",\n
"type": "object",\n
"description": "Also known as SLA parameters. Used to pick where an how the instance is to be deployed",\n
"properties": {\n
"computer_guid": {\n
"title": "Requested Compute Node",\n
"descritpion": "Requested Compute Node Reference, like COMP-1234",\n
"type": "string"\n
},\n
"project_guid": {\n
"title": "Requested Project",\n
"descritpion": "Requested Project Reference",\n
"type": "string"\n
},\n
"instance_guid": {\n
"title": "Requested Host Instance",\n
"descritpion": "Only applicable to shared instance. Requested Host Instance Reference, like SOFTINST-1234",\n
"type": "string"\n
},\n
"network_guid": {\n
"title": "Requested Network",\n
"descritpion": "Requested Network Reference",\n
"type": "string"\n
}\n
},\n
"additionalProperties": { "type": "string" }\n
},\n
"portal_type": {\n
"title": "Portal Type",\n
"const": "Software Instance",\n
"type": "string"\n
},\n
"compute_node_id": {\n
"title": "Compute Node Id",\n
"type": "string",\n
"description": "Id Of the Requesting Compute Node, used by Slap Client when an instance is requesting an instance"\n
},\n
"compute_partition_id": {\n
"title": "Compute Partition Id",\n
"type": "string",\n
"description": "Id Of the Requesting Compute Partition, used by Slap Client when an instance is requesting an instance"\n
}\n
},\n
"required": ["title", "software_release_uri", "portal_type"]\n
}\n
</string> </value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>001</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
compute_node_id = data_dict.get("compute_node_id", None)
compute_partition_id = data_dict.get("compute_partition_id", None)
class SoftwareInstanceNotReady(Exception):
pass
class NotFound(Exception):
pass
class Unauthorized(Exception):
pass
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,
)
LOG = context.log
portal = context.getPortalObject()
def _assertACI(document):
if context.Base_checkPermission(document.relative_url, 'View'):
return document.getObject()
raise Unauthorized('User has no access to %r' % (document.relative_url))
def getDocument(**kwargs):
# No need to get all results if an error is raised when at least 2 objects
# are found
l = portal.portal_catalog.unrestrictedSearchResults(limit=2, select_list=("relative_url", "uid"), **kwargs)
if len(l) != 1:
raise NotFound, "No document found with parameters: %s" % kwargs
else:
return _assertACI(l[0])
def getNonCachedComputeNodeUidByReference(compute_node_reference):
return portal.portal_catalog.unrestrictedSearchResults(
portal_type='Compute Node', reference=compute_node_reference,
validation_state="validated")[0].UID
def getComputePartitionDocument(compute_node_reference,
compute_partition_reference):
"""
Get the compute partition defined in an available compute_node
"""
# Related key might be nice
return getDocument(portal_type='Compute Partition',
reference=compute_partition_reference,
parent_uid=getNonCachedComputeNodeUidByReference(
compute_node_reference))
def getSoftwareInstanceForComputePartition(compute_node_id,
compute_partition_id, slave_reference=None):
compute_partition_document = getComputePartitionDocument(
compute_node_id, compute_partition_id)
if compute_partition_document.getSlapState() != 'busy':
LOG('SlapTool::_getSoftwareInstanceForComputePartition'
+ 'Compute partition %s shall be busy, is free' %
compute_partition_document.getRelativeUrl())
raise NotFound, "No software instance found for: %s - %s" % (compute_node_id,
compute_partition_id)
else:
query_kw = {
'validation_state': 'validated',
'portal_type': 'Slave Instance',
'default_aggregate_uid': compute_partition_document.getUid(),
}
if slave_reference is None:
query_kw['portal_type'] = "Software Instance"
else:
query_kw['reference'] = slave_reference
software_instance = _assertACI(portal.portal_catalog.unrestrictedGetResultValue(**query_kw))
if software_instance is None:
raise NotFound, "No software instance found for: %s - %s" % (
compute_node_id, compute_partition_id)
else:
return software_instance
# Loads partition parameter
partition_parameter = data_dict.get("parameters", {})
if isinstance(partition_parameter, str):
import json
try:
partition_parameter = json.loads(partition_parameter)
except ValueError, e:
return logError(
"Cannot Decode JSON Parameter. Error: %s" % e,
error_name="CANNOT-DECODE-COMPUTER-PARTITION-JSON-PARAMETER",
)
if not isinstance(partition_parameter, dict):
return logError(
"Parameters should be a key value object.",
error_name="INCORRECT-COMPUTER-PARTITION-JSON-PARAMETER",
)
try:
# filter dict
filter_kw = data_dict.get("sla_parameters", {})
partition_reference = data_dict.get("title")
kw = dict(software_release=data_dict.get("software_release_uri"),
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"))
#raise ValueError("%s" % kw)
if compute_node_id and compute_partition_id:
requester = getSoftwareInstanceForComputePartition(
compute_node_id,
compute_partition_id)
instance_tree = requester.getSpecialiseValue()
if instance_tree is not None and instance_tree.getSlapState() == "stop_requested":
kw['state'] = 'stopped'
key = '_'.join([instance_tree.getRelativeUrl(), partition_reference])
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 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 None:
raise SoftwareInstanceNotReady
else:
if not requested_software_instance.getAggregate(portal_type="Compute Partition"):
raise SoftwareInstanceNotReady
else:
return requested_software_instance.asJSONText()
except SoftwareInstanceNotReady:
return logError(
"Software Instance Not Ready",
error_name="SoftwareInstanceNotReady",
error_code=102
)
except Unauthorized, log:
return logError(
log,
error_code=401
)
except NotFound, log:
return logError(
log,
error_code=404
)
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>data_dict, form_reference</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>jIOWebSection_requestComputerPartition</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
Software Instance | slapos_jio_api_get_software_instance
jIO Web Section | slapos_jio_api_create_compute_node
jIO Web Section | slapos_jio_api_create_software_installation
jIO Web Section | slapos_jio_api_request_software_instance
\ No newline at end of file
portal_callables/jIOWebSection_createComputeNodeFromJSON
portal_callables/jIOWebSection_createSoftwareInstallationFromJSON
portal_callables/jIOWebSection_requestComputerPartitionFromJSON
\ No newline at end of file
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