Commit 9f4b1554 authored by Cédric Le Ninivin's avatar Cédric Le Ninivin Committed by Titouan Soulard

slapos_jio_api_style: Improve search API and add revision to Software Installation and Compute Node

* Add revision to Software Installation and Compute Node
* Add get_parameters to Software Installation and Compute Node result List
* Add revision to Software Installation and Compute Node result list
* Add from jio_api_revision input parameter for Compute Node and Software Installation search
* Add pagination in all searches with next_page_parameter
* Add current_page_full parameter to search results as indication if a query for the next search page is needed
parent eb7d8337
...@@ -35,6 +35,16 @@ ...@@ -35,6 +35,16 @@
"title": "allDocs: Response Payload",\n "title": "allDocs: Response Payload",\n
"description": "Payload returned by allDocs method.",\n "description": "Payload returned by allDocs method.",\n
"properties": {\n "properties": {\n
"current_page_full": {\n
"title": "Current Page Full",\n
"description": "If set to true, the current page has the max quantity of results for one page, the next page might contain more results.",\n
"type": "boolean"\n
},\n
"next_page_request": {\n
"title": "Next Page Request",\n
"description": "Use the content of this object with all docs to get to the next page of this research",\n
"type": "object"\n
},\n
"result_list": {\n "result_list": {\n
"title": "Result List",\n "title": "Result List",\n
"description": "Contains a representation of the items",\n "description": "Contains a representation of the items",\n
...@@ -57,6 +67,28 @@ ...@@ -57,6 +67,28 @@
"title": "Portal Type",\n "title": "Portal Type",\n
"const": "Compute Node",\n "const": "Compute Node",\n
"type": "string"\n "type": "string"\n
},\n
"api_revision": {\n
"title": "API Revision",\n
"type": "string",\n
"description": "The API Revision is set by the master node to mark when the element was last processed. It is incremental. If revision has changed, critical data has been updated"\n
},\n
"get_parameters": {\n
"title": "Get Parameters",\n
"description": "Copy Paste the content of this object in order to get the object",\n
"type": "object",\n
"properties": {\n
"compute_node_id": {\n
"title": "Compute Node ID",\n
"type": "string",\n
"description": "The Id of the compute node, example: COMP-1234"\n
},\n
"portal_type": {\n
"title": "Portal Type",\n
"const": "Compute Node",\n
"type": "string"\n
}\n
}\n
}\n }\n
}\n }\n
}\n }\n
...@@ -86,6 +118,11 @@ ...@@ -86,6 +118,11 @@
"type": "string",\n "type": "string",\n
"description": "The Id of the compute node, example: COMP-1234"\n "description": "The Id of the compute node, example: COMP-1234"\n
},\n },\n
"from_api_revision": {\n
"title": "From API Revision",\n
"type": "string",\n
"description": "Filter by API Revision. Returns the list of elements having an api revision higher or equal to the one inputed. The API Revision is set by the master node to mark when the element was last processed. It is incremental. If revision has changed, critical data has been updated"\n
},\n
"portal_type": {\n "portal_type": {\n
"title": "Portal Type",\n "title": "Portal Type",\n
"const": "Compute Node",\n "const": "Compute Node",\n
......
...@@ -35,15 +35,15 @@ ...@@ -35,15 +35,15 @@
"title": "allDocs: Response Payload",\n "title": "allDocs: Response Payload",\n
"description": "Payload returned by allDocs method.",\n "description": "Payload returned by allDocs method.",\n
"properties": {\n "properties": {\n
"result_number": {\n "current_page_full": {\n
"title": "Result Number",\n "title": "Current Page Full",\n
"type": "number",\n "description": "If set to true, the current page has the max quantity of results for one page, the next page might contain more results.",\n
"description": "Quantity of results found"\n "type": "boolean"\n
},\n },\n
"max_result_number_allowed": {\n "next_page_request": {\n
"title": "Max Result Number",\n "title": "Next Page Request",\n
"type": "number",\n "description": "Use the content of this object with all docs to get to the next page of this research",\n
"description": "Highest number of result given by the system. To get the rest of the result you can use \'from_processing_timestamp\' parameter for pagination."\n "type": "object"\n
},\n },\n
"result_list": {\n "result_list": {\n
"title": "Result List",\n "title": "Result List",\n
...@@ -55,6 +55,23 @@ ...@@ -55,6 +55,23 @@
"type": "object",\n "type": "object",\n
"title": "Software Instance",\n "title": "Software Instance",\n
"properties": {\n "properties": {\n
"get_parameters": {\n
"title": "Get Parameters",\n
"description": "Copy Paste the content of this object in order to get the object",\n
"type": "object",\n
"properties": {\n
"reference": {\n
"title": "Software Instance Id/Reference",\n
"type": "string",\n
"description": "The unique reference of the Software Instance, example: SOFTINST-1234"\n
},\n
"portal_type": {\n
"title": "Portal Type",\n
"const": "Software Instance",\n
"type": "string"\n
}\n
},\n
},\n
"reference": {\n "reference": {\n
"title": "Software Instance Reference",\n "title": "Software Instance Reference",\n
"description": "Unique identifier of the Software Instance",\n "description": "Unique identifier of the Software Instance",\n
...@@ -96,6 +113,23 @@ ...@@ -96,6 +113,23 @@
"type": "object",\n "type": "object",\n
"title": "Shared Instance",\n "title": "Shared Instance",\n
"properties": {\n "properties": {\n
"get_parameters": {\n
"title": "Get Parameters",\n
"description": "Copy Paste the content of this object in order to get the object",\n
"type": "object",\n
"properties": {\n
"reference": {\n
"title": "Software Instance Id/Reference",\n
"type": "string",\n
"description": "The unique reference of the Software Instance, example: SOFTINST-1234"\n
},\n
"portal_type": {\n
"title": "Portal Type",\n
"const": "Software Instance",\n
"type": "string"\n
}\n
},\n
},\n
"reference": {\n "reference": {\n
"title": "Software Instance Reference",\n "title": "Software Instance Reference",\n
"description": "Unique identifier of the Software Instance",\n "description": "Unique identifier of the Software Instance",\n
......
...@@ -35,6 +35,16 @@ ...@@ -35,6 +35,16 @@
"title": "allDocs: Response Payload",\n "title": "allDocs: Response Payload",\n
"description": "Payload returned by allDocs method.",\n "description": "Payload returned by allDocs method.",\n
"properties": {\n "properties": {\n
"next_page_request": {\n
"title": "Next Page Request",\n
"description": "Use the content of this object with all docs to get to the next page of this research",\n
"type": "object"\n
},\n
"current_page_full": {\n
"title": "Current Page Full",\n
"description": "If set to true, the current page has the max quantity of results for one page, the next page might contain more results.",\n
"type": "boolean"\n
},\n
"result_list": {\n "result_list": {\n
"title": "Result List",\n "title": "Result List",\n
"description": "Contains a representation of the items",\n "description": "Contains a representation of the items",\n
...@@ -43,6 +53,26 @@ ...@@ -43,6 +53,26 @@
"type": "object",\n "type": "object",\n
"title": "Item",\n "title": "Item",\n
"properties": {\n "properties": {\n
"get_parameters": {\n
"title": "Get Parameters",\n
"description": "Copy Paste the content of this object in order to get the object",\n
"type": "object",\n
"software_release_uri": {\n
"title": "Software Release URI",\n
"type": "string",\n
"format": "uri-reference"\n
},\n
"compute_node_id": {\n
"title": "Compute Node ID",\n
"type": "string",\n
"description": "The Id of the compute node, example: COMP-1234"\n
},\n
"portal_type": {\n
"title": "Portal Type",\n
"const": "Software Installation",\n
"type": "string"\n
}\n
},\n
"software_release_uri": {\n "software_release_uri": {\n
"title": "Software Release URI",\n "title": "Software Release URI",\n
"type": "string",\n "type": "string",\n
...@@ -63,6 +93,11 @@ ...@@ -63,6 +93,11 @@
"type": "number",\n "type": "number",\n
"description": "Timestamp set by the master node to mark when it was last processed in the master node. If it has been processed on master, it needs reprocessing on the compute node."\n "description": "Timestamp set by the master node to mark when it was last processed in the master node. If it has been processed on master, it needs reprocessing on the compute node."\n
},\n },\n
"api_revision": {\n
"title": "API Revision",\n
"type": "string",\n
"description": "The API Revision is set by the master node to mark when the element was last processed. It is incremental. If revision has changed, critical data has been updated"\n
},\n
"state": {\n "state": {\n
"title": "Requested State",\n "title": "Requested State",\n
"type": "string",\n "type": "string",\n
...@@ -99,6 +134,11 @@ ...@@ -99,6 +134,11 @@
"type": "string",\n "type": "string",\n
"description": "The Id of the compute node, example: COMP-1234"\n "description": "The Id of the compute node, example: COMP-1234"\n
},\n },\n
"from_api_revision": {\n
"title": "From API Revision",\n
"type": "string",\n
"description": "Filter by API Revision. Returns the list of elements having an api revision higher or equal to the one inputed. The API Revision is set by the master node to mark when the element was last processed. It is incremental. If revision has changed, critical data has been updated"\n
},\n
"portal_type": {\n "portal_type": {\n
"title": "Portal Type",\n "title": "Portal Type",\n
"const": "Software Installation",\n "const": "Software Installation",\n
......
# Hardcoded
limit = 1000
search_kw = { search_kw = {
"portal_type": "Compute Node", "portal_type": "Compute Node",
"validation_state": "validated", "validation_state": "validated",
"select_list": ("title", "reference", "portal_type"), "select_list": ("title", "reference", "portal_type", "jio_api_revision.revision"),
"sort_on": ("jio_api_revision.revision", "ASC"),
"limit": limit,
} }
if "title" in data_dict: if "title" in data_dict:
search_kw["title"] = data_dict["title"] search_kw["title"] = data_dict["title"]
if "compute_node_id" in data_dict: if "compute_node_id" in data_dict:
search_kw["reference"] = data_dict["compute_node_id"] search_kw["reference"] = data_dict["compute_node_id"]
if "from_api_revision" in data_dict:
search_kw["jio_api_revision.revision"] = "> %s" % data_dict["from_api_revision"]
result_list = [{ result_list = [{
"title": x.title, "title": x.title,
"compute_node_id": x.reference, "compute_node_id": x.reference,
"portal_type": x.portal_type, "portal_type": x.portal_type,
"api_revision": x.revision,
"get_parameters": {
"compute_node_id": x.reference,
"portal_type": x.portal_type,
}
} for x in context.getPortalObject().portal_catalog(**search_kw)] } for x in context.getPortalObject().portal_catalog(**search_kw)]
if result_list:
data_dict["from_api_revision"] = result_list[-1]["api_revision"]
import json import json
return json.dumps({ return json.dumps({
"$schema": json_form.absolute_url().strip() + "/getOutputJSONSchema", "$schema": json_form.absolute_url().strip() + "/getOutputJSONSchema",
"result_list": result_list "result_list": result_list,
"next_page_request": data_dict,
"current_page_full": len(result_list) == limit,
}, indent=2) }, indent=2)
...@@ -45,6 +45,10 @@ if portal_type == "Software Instance": ...@@ -45,6 +45,10 @@ if portal_type == "Software Instance":
"compute_partition_id": x.aggregate_reference, "compute_partition_id": x.aggregate_reference,
"software_release_uri": x.url_string, "software_release_uri": x.url_string,
"api_revision": x.revision, "api_revision": x.revision,
"get_parameters": {
"portal_type": x.portal_type,
"reference": x.reference,
},
} for x in portal.portal_catalog(**search_kw)] } for x in portal.portal_catalog(**search_kw)]
elif portal_type == "Shared Instance": elif portal_type == "Shared Instance":
...@@ -78,10 +82,14 @@ elif portal_type == "Shared Instance": ...@@ -78,10 +82,14 @@ elif portal_type == "Shared Instance":
result_list = [{ result_list = [{
"title": x.title, "title": x.title,
"reference": x.reference, "reference": x.reference,
"portal_type": "Shared Instance", "portal_type": "Software Instance",
"state": slap_state_dict.get(x.slap_state, ""), "state": slap_state_dict.get(x.slap_state, ""),
"compute_partition_id": x.aggregate_reference, "compute_partition_id": x.aggregate_reference,
"api_revision": x.revision, "api_revision": x.revision,
"get_parameters": {
"portal_type": "Software Instance",
"reference": x.reference,
},
# Slave Instance don't have url_string cataloged. Selecting it return 0 result each time # Slave Instance don't have url_string cataloged. Selecting it return 0 result each time
#"software_release_uri": x.url_string, #"software_release_uri": x.url_string,
} for x in portal.portal_catalog(**search_kw)] } for x in portal.portal_catalog(**search_kw)]
...@@ -92,10 +100,13 @@ else: ...@@ -92,10 +100,13 @@ else:
error_message="You Reached code that was not recheable", error_message="You Reached code that was not recheable",
) )
if result_list:
data_dict["from_api_revision"] = result_list[-1]["api_revision"]
import json import json
return json.dumps({ return json.dumps({
"$schema": json_form.absolute_url().strip() + "/getOutputJSONSchema", "$schema": json_form.absolute_url().strip() + "/getOutputJSONSchema",
"result_list": result_list, "result_list": result_list,
"result_number": len(result_list), "next_page_request": data_dict,
"max_result_number_allowed": limit, "current_page_full": len(result_list) == limit,
}, indent=2) }, indent=2)
# Hardcoded
limit = 1000
search_kw = { search_kw = {
"portal_type": "Software Installation", "portal_type": "Software Installation",
"validation_state": "validated", "validation_state": "validated",
"select_list": ("aggregate_reference", "url_string", "slap_state", "portal_type", "slap_date"), "select_list": ("aggregate_reference", "url_string", "slap_state", "portal_type", "slap_date", "jio_api_revision.revision"),
"sort_on": ("jio_api_revision.revision", "ASC"),
"limit": limit,
} }
if "software_release_uri" in data_dict: if "software_release_uri" in data_dict:
search_kw["url_string"] = data_dict["software_release_uri"] search_kw["url_string"] = data_dict["software_release_uri"]
if "compute_node_id" in data_dict: if "compute_node_id" in data_dict:
search_kw["strict_aggregate_reference"] = data_dict["compute_node_id"] search_kw["strict_aggregate_reference"] = data_dict["compute_node_id"]
if "from_api_revision" in data_dict:
search_kw["jio_api_revision.revision"] = "> %s" % data_dict["from_api_revision"]
result_list = [{ result_list = [{
"get_parameters": {
"software_release_uri": x.url_string,
"compute_node_id": x.aggregate_reference,
"portal_type": x.portal_type,
},
"software_release_uri": x.url_string, "software_release_uri": x.url_string,
"compute_node_id": x.aggregate_reference, "compute_node_id": x.aggregate_reference,
"state": "available" if x.slap_state == "start_requested" else "destroyed", "state": "available" if x.slap_state == "start_requested" else "destroyed",
"api_revision": x.revision,
"portal_type": x.portal_type, "portal_type": x.portal_type,
"processing_timestamp": int(x.slap_date), "processing_timestamp": int(x.slap_date),
} for x in context.getPortalObject().portal_catalog(**search_kw)] } for x in context.getPortalObject().portal_catalog(**search_kw)]
if result_list:
data_dict["from_api_revision"] = result_list[-1]["api_revision"]
import json import json
return json.dumps({ return json.dumps({
"$schema": json_form.absolute_url().strip() + "/getOutputJSONSchema", "$schema": json_form.absolute_url().strip() + "/getOutputJSONSchema",
"result_list": result_list "result_list": result_list,
"next_page_request": data_dict,
"current_page_full": len(result_list) == limit,
}, indent=2) }, indent=2)
...@@ -8,8 +8,7 @@ left outer join ...@@ -8,8 +8,7 @@ left outer join
join join
slapos_item on catalog.uid = slapos_item.uid slapos_item on catalog.uid = slapos_item.uid
where where
jio_api_revision.uid IS NULL AND ( jio_api_revision.uid IS NULL
catalog.portal_type="Slave Instance" OR catalog.portal_type="Software Instance" AND (catalog.portal_type="Slave Instance" OR catalog.portal_type="Software Instance")
) AND AND slapos_item.slap_state!="draft"
catalog.validation_state="validated" AND AND catalog.validation_state="validated"
slapos_item.slap_state!="draft"
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="SQL" module="Products.ZSQLMethods.SQL"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_col</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>name</string> </key>
<value> <string>uid</string> </value>
</item>
<item>
<key> <string>null</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>l</string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <int>6</int> </value>
</item>
</dictionary>
<dictionary>
<item>
<key> <string>name</string> </key>
<value> <string>relative_url</string> </value>
</item>
<item>
<key> <string>null</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>t</string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <int>42</int> </value>
</item>
</dictionary>
</list>
</value>
</item>
<item>
<key> <string>arguments_src</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>connection_id</string> </key>
<value> <string>erp5_sql_connection</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_zSelectMissingJIOAPIRevisionInstanceList</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
return list(context.Base_zSelectMissingJIOAPIRevisionInstanceList()) + list(context.Base_zSelectMissingJIOAPIRevisionSoftwareAndComputeList())
...@@ -2,69 +2,60 @@ ...@@ -2,69 +2,60 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="SQL" module="Products.ZSQLMethods.SQL"/> <global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item> <item>
<key> <string>_col</string> </key> <key> <string>Script_magic</string> </key>
<value> <value> <int>3</int> </value>
<list>
<dictionary>
<item>
<key> <string>name</string> </key>
<value> <string>uid</string> </value>
</item>
<item>
<key> <string>null</string> </key>
<value> <int>0</int> </value>
</item> </item>
<item> <item>
<key> <string>type</string> </key> <key> <string>_bind_names</string> </key>
<value> <string>l</string> </value> <value>
</item> <object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item> <item>
<key> <string>width</string> </key> <key> <string>_asgns</string> </key>
<value> <int>6</int> </value> <value>
</item>
</dictionary>
<dictionary> <dictionary>
<item> <item>
<key> <string>name</string> </key> <key> <string>name_container</string> </key>
<value> <string>relative_url</string> </value> <value> <string>container</string> </value>
</item> </item>
<item> <item>
<key> <string>null</string> </key> <key> <string>name_context</string> </key>
<value> <int>0</int> </value> <value> <string>context</string> </value>
</item> </item>
<item> <item>
<key> <string>type</string> </key> <key> <string>name_m_self</string> </key>
<value> <string>t</string> </value> <value> <string>script</string> </value>
</item> </item>
<item> <item>
<key> <string>width</string> </key> <key> <string>name_subpath</string> </key>
<value> <int>40</int> </value> <value> <string>traverse_subpath</string> </value>
</item> </item>
</dictionary> </dictionary>
</list>
</value> </value>
</item> </item>
<item> </dictionary>
<key> <string>arguments_src</string> </key> </state>
<value> <string></string> </value> </object>
</value>
</item> </item>
<item> <item>
<key> <string>connection_id</string> </key> <key> <string>_params</string> </key>
<value> <string>erp5_sql_connection</string> </value> <value> <string></string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>Base_zSelectMissingJIOAPIRevisionObjectList</string> </value> <value> <string>Base_zSelectMissingJIOAPIRevisionObjectList</string> </value>
</item> </item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
......
select
catalog.uid,
catalog.relative_url
from
catalog
left outer join
jio_api_revision on catalog.uid = jio_api_revision.uid
where
jio_api_revision.uid IS NULL
AND (catalog.portal_type="Compute Node" OR catalog.portal_type="Software Installation")
AND catalog.validation_state="validated"
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="SQL" module="Products.ZSQLMethods.SQL"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_col</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>name</string> </key>
<value> <string>uid</string> </value>
</item>
<item>
<key> <string>null</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>l</string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <int>6</int> </value>
</item>
</dictionary>
<dictionary>
<item>
<key> <string>name</string> </key>
<value> <string>relative_url</string> </value>
</item>
<item>
<key> <string>null</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>t</string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <int>42</int> </value>
</item>
</dictionary>
</list>
</value>
</item>
<item>
<key> <string>arguments_src</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>connection_id</string> </key>
<value> <string>erp5_sql_connection</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_zSelectMissingJIOAPIRevisionSoftwareAndComputeList</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
if context.getValidationState() != "validated":
return None
import json
import hashlib
data = json.loads(context.asJSONText())
key_list = ["compute_node_id", "title", "compute_partition_list"]
hash_dict = {}
for key in key_list:
hash_dict[key] = data.get(key, None)
return hashlib.md5(json.dumps(hash_dict, sort_keys=True)).hexdigest()
<?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></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ComputeNode_calculatejIOAPIRevisionHash</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
if context.getValidationState() != "validated" or context.getSlapState() == "draft":
return None
import json
import hashlib
data = json.loads(context.asJSONText())
key_list = ["software_release_uri", "compute_node_id", "state"]
hash_dict = {}
for key in key_list:
hash_dict[key] = data.get(key, None)
return hashlib.md5(json.dumps(hash_dict, sort_keys=True)).hexdigest()
<?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></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SoftwareInstallation_calculatejIOAPIRevisionHash</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
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