Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
slapos.core
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jérome Perrin
slapos.core
Commits
42e72e67
Commit
42e72e67
authored
Sep 04, 2014
by
Alain Takoudjou
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into operation-control
parents
64c208f6
14904721
Changes
35
Hide whitespace changes
Inline
Side-by-side
Showing
35 changed files
with
2118 additions
and
190 deletions
+2118
-190
CHANGES.txt
CHANGES.txt
+14
-0
master/bt5/slapos_crm/SkinTemplateItem/portal_skins/slapos_crm_monitoring/Alarm_checkAndUpdateComputerAllocationScope.xml
...onitoring/Alarm_checkAndUpdateComputerAllocationScope.xml
+20
-2
master/bt5/slapos_crm/SkinTemplateItem/portal_skins/slapos_crm_monitoring/Computer_checkAndUpdateAllocationScope.xml
...crm_monitoring/Computer_checkAndUpdateAllocationScope.xml
+15
-10
master/bt5/slapos_crm/SkinTemplateItem/portal_skins/slapos_crm_monitoring/Computer_checkAndUpdatePersonalAllocationScope.xml
...toring/Computer_checkAndUpdatePersonalAllocationScope.xml
+69
-0
master/bt5/slapos_crm/TestTemplateItem/testSlapOSCRMSkins.py
master/bt5/slapos_crm/TestTemplateItem/testSlapOSCRMSkins.py
+39
-5
master/bt5/slapos_crm/TestTemplateItem/testSlapOSCRMSupportRequestGeneration.py
...TestTemplateItem/testSlapOSCRMSupportRequestGeneration.py
+50
-5
master/bt5/slapos_crm/bt/revision
master/bt5/slapos_crm/bt/revision
+1
-1
master/bt5/slapos_crm/bt/template_path_list
master/bt5/slapos_crm/bt/template_path_list
+0
-1
master/bt5/slapos_erp5/PortalTypeRolesTemplateItem/Restricted%20Access%20Token.xml
...rtalTypeRolesTemplateItem/Restricted%20Access%20Token.xml
+5
-0
master/bt5/slapos_erp5/PortalTypeWorkflowChainTemplateItem/workflow_chain_type.xml
...rtalTypeWorkflowChainTemplateItem/workflow_chain_type.xml
+4
-0
master/bt5/slapos_erp5/WorkflowTemplateItem/portal_workflow/local_permission_slapos_interaction_workflow/interactions/RestrictedAccessToken_edit.xml
...tion_workflow/interactions/RestrictedAccessToken_edit.xml
+96
-0
master/bt5/slapos_erp5/WorkflowTemplateItem/portal_workflow/local_permission_slapos_interaction_workflow/interactions/UpgradeDecision_edit.xml
...nteraction_workflow/interactions/UpgradeDecision_edit.xml
+96
-0
master/bt5/slapos_erp5/bt/revision
master/bt5/slapos_erp5/bt/revision
+1
-1
master/bt5/slapos_erp5/bt/template_portal_type_workflow_chain_list
...5/slapos_erp5/bt/template_portal_type_workflow_chain_list
+1
-0
master/bt5/slapos_pdm/PathTemplateItem/portal_alarms/slapos_pdm_upgrade_decision_process_stopped.xml
...al_alarms/slapos_pdm_upgrade_decision_process_stopped.xml
+14
-14
master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/Alarm_processStoppedUpgradeDecision.xml
..._skins/slapos_pdm/Alarm_processStoppedUpgradeDecision.xml
+7
-14
master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareRelease_createUpgradeDecision.xml
...kins/slapos_pdm/SoftwareRelease_createUpgradeDecision.xml
+6
-5
master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/UpgradeDecision_getComputerNotificationMessage.xml
...os_pdm/UpgradeDecision_getComputerNotificationMessage.xml
+92
-0
master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/UpgradeDecision_isUpgradeFinished.xml
...al_skins/slapos_pdm/UpgradeDecision_isUpgradeFinished.xml
+25
-25
master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/UpgradeDecision_notifyDelivered.xml
...rtal_skins/slapos_pdm/UpgradeDecision_notifyDelivered.xml
+126
-0
master/bt5/slapos_pdm/TestTemplateItem/testSlapOSPDMAlarm.py
master/bt5/slapos_pdm/TestTemplateItem/testSlapOSPDMAlarm.py
+17
-0
master/bt5/slapos_pdm/TestTemplateItem/testSlapOSPDMSkins.py
master/bt5/slapos_pdm/TestTemplateItem/testSlapOSPDMSkins.py
+162
-1
master/bt5/slapos_pdm/bt/revision
master/bt5/slapos_pdm/bt/revision
+1
-1
master/bt5/slapos_pdm/bt/template_path_list
master/bt5/slapos_pdm/bt/template_path_list
+1
-0
master/bt5/slapos_web/SkinTemplateItem/portal_skins/slapos_rss/WebSection_getUserRssTicketList.xml
...rtal_skins/slapos_rss/WebSection_getUserRssTicketList.xml
+2
-2
master/bt5/slapos_web/SkinTemplateItem/portal_skins/vifib_hosting/Base_generateRssRestrictedAccessTokenFromJS.xml
...b_hosting/Base_generateRssRestrictedAccessTokenFromJS.xml
+7
-2
master/bt5/slapos_web/bt/revision
master/bt5/slapos_web/bt/revision
+1
-1
slapos/collect/__init__.py
slapos/collect/__init__.py
+1
-1
slapos/grid/slapgrid.py
slapos/grid/slapgrid.py
+11
-1
slapos/proxy/schema.sql
slapos/proxy/schema.sql
+18
-6
slapos/proxy/views.py
slapos/proxy/views.py
+171
-91
slapos/tests/slapgrid.py
slapos/tests/slapgrid.py
+3
-0
slapos/tests/slapproxy/__init__.py
slapos/tests/slapproxy/__init__.py
+930
-0
slapos/tests/slapproxy/database_dump_version_10.sql
slapos/tests/slapproxy/database_dump_version_10.sql
+111
-0
slapos/version.py
slapos/version.py
+1
-1
No files found.
CHANGES.txt
View file @
42e72e67
Changes
Changes
=======
=======
1.2.1 (2014-08-21)
------------------
* slapproxy: add automatic migration to new database schema if needed.
1.2.0 (2014-08-18)
------------------
Note: not officially released as egg.
* slapproxy: add correct support for slaves, instance_guid, state.
* slapproxy: add getComputerPartitionStatus dummy support.
* slapproxy: add multi-nodes support
1.1.2 (2014-06-02)
1.1.2 (2014-06-02)
------------------
------------------
...
...
master/bt5/slapos_crm/SkinTemplateItem/portal_skins/slapos_crm_monitoring/Alarm_checkAndUpdateComputerAllocationScope.xml
View file @
42e72e67
...
@@ -50,10 +50,13 @@
...
@@ -50,10 +50,13 @@
</item>
</item>
<item>
<item>
<key>
<string>
_body
</string>
</key>
<key>
<string>
_body
</string>
</key>
<value>
<string>
portal = context.getPortalObject()\n
<value>
<string
encoding=
"cdata"
>
<![CDATA[
portal = context.getPortalObject()\n
\n
\n
category_public = portal.restrictedTraverse("portal_categories/allocation_scope/open/public", None)\n
category_public = portal.restrictedTraverse("portal_categories/allocation_scope/open/public", None)\n
category_friend = portal.restrictedTraverse("portal_categories/allocation_scope/open/friend", None)\n
category_friend = portal.restrictedTraverse("portal_categories/allocation_scope/open/friend", None)\n
category_personal = portal.restrictedTraverse("portal_categories/allocation_scope/open/personal", None)\n
\n
\n
if category_public is not None:\n
if category_public is not None:\n
portal.portal_catalog.searchAndActivate(\n
portal.portal_catalog.searchAndActivate(\n
...
@@ -63,8 +66,23 @@ if category_public is not None:\n
...
@@ -63,8 +66,23 @@ if category_public is not None:\n
method_id=\'Computer_checkAndUpdateAllocationScope\',\n
method_id=\'Computer_checkAndUpdateAllocationScope\',\n
activate_kw={\'tag\': tag}\n
activate_kw={\'tag\': tag}\n
)\n
)\n
\n
if category_personal is not None:\n
portal.portal_catalog.searchAndActivate(\n
portal_type=\'Computer\', \n
validation_state=\'validated\', \n
modification_date=(DateTime() - 30).strftime(\'<=%Y/%m/%d\'), \n
order_by=((\'modification_date\', "ASC"), ), \n
default_allocation_scope_uid=category_personal.getUid(), \n
left_join_list=[\'aggregate_related_uid\'], \n
aggregate_related_uid=None,\n
method_id=\'Computer_checkAndUpdatePersonalAllocationScope\',\n
activate_kw={\'tag\': tag})\n
\n
context.activate(after_tag=tag).getId()\n
context.activate(after_tag=tag).getId()\n
</string>
</value>
]]>
</string>
</value>
</item>
</item>
<item>
<item>
<key>
<string>
_params
</string>
</key>
<key>
<string>
_params
</string>
</key>
...
...
master/bt5/slapos_crm/SkinTemplateItem/portal_skins/slapos_crm_monitoring/Computer_checkAndUpdateAllocationScope.xml
View file @
42e72e67
...
@@ -57,7 +57,11 @@ portal = context.getPortalObject()\n
...
@@ -57,7 +57,11 @@ portal = context.getPortalObject()\n
allocation_scope = computer.getAllocationScope()\n
allocation_scope = computer.getAllocationScope()\n
computer_reference = computer.getReference()\n
computer_reference = computer.getReference()\n
\n
\n
if allocation_scope not in [\'open/public\', \'open/friend\']:\n
if allocation_scope not in [\'open/public\', \'open/friend\', \'open/personal\']:\n
return\n
\n
if allocation_scope == target_allocation_scope:\n
# already changed\n
return\n
return\n
\n
\n
person = computer.getSourceAdministrationValue(portal_type="Person")\n
person = computer.getSourceAdministrationValue(portal_type="Person")\n
...
@@ -65,17 +69,15 @@ if not person:\n
...
@@ -65,17 +69,15 @@ if not person:\n
return\n
return\n
\n
\n
if not person.Person_isServiceProvider():\n
if not person.Person_isServiceProvider():\n
#Turn this computer allocation scope to \'open/personal\'\n
edit_kw = {\n
edit_kw = {\n
\'allocation_scope\':
\'open/personal\'
,\n
\'allocation_scope\':
target_allocation_scope
,\n
}\n
}\n
computer.edit(**edit_kw)\n
\n
\n
# Create a ticket (or re-open it) for this issue!\n
# Create a ticket (or re-open it) for this issue!\n
support_request = None\n
support_request = None\n
request_title = \'We have changed allocation scope for %s\' % computer_reference\n
request_title = \'We have changed allocation scope for %s\' % computer_reference\n
request_description = \'Allocation scope has been changed
back
to \' \\\n
request_description = \'Allocation scope has been changed to \' \\\n
\'
open/personal for %s\' % computer_reference
\n
\'
%s for %s\' % (target_allocation_scope, computer_reference)
\n
\n
\n
support_request_url = context.Base_generateSupportRequestForSlapOS(\n
support_request_url = context.Base_generateSupportRequestForSlapOS(\n
request_title,\n
request_title,\n
...
@@ -91,7 +93,7 @@ if not person.Person_isServiceProvider():\n
...
@@ -91,7 +93,7 @@ if not person.Person_isServiceProvider():\n
support_request = portal.portal_catalog.getResultValue(\n
support_request = portal.portal_catalog.getResultValue(\n
portal_type = \'Support Request\',\n
portal_type = \'Support Request\',\n
title = request_title,\n
title = request_title,\n
simulation_state =
\'suspended\'
,\n
simulation_state =
[\'suspended\', \'open\']
,\n
source_project_uid = computer.getUid()\n
source_project_uid = computer.getUid()\n
)\n
)\n
if support_request is None:\n
if support_request is None:\n
...
@@ -100,7 +102,7 @@ if not person.Person_isServiceProvider():\n
...
@@ -100,7 +102,7 @@ if not person.Person_isServiceProvider():\n
\n
\n
# Send notification message\n
# Send notification message\n
notification_message = portal.portal_notifications.getDocumentValue(\n
notification_message = portal.portal_notifications.getDocumentValue(\n
reference=
\'slapos-crm-computer_allocation_scope.notification\'
)\n
reference=
notification_message_reference
)\n
\n
\n
if notification_message is not None:\n
if notification_message is not None:\n
mapping_dict = {\'computer_title\':computer.getTitle(),\n
mapping_dict = {\'computer_title\':computer.getTitle(),\n
...
@@ -111,13 +113,16 @@ if not person.Person_isServiceProvider():\n
...
@@ -111,13 +113,16 @@ if not person.Person_isServiceProvider():\n
else:\n
else:\n
message = request_description\n
message = request_description\n
\n
\n
support_request.SupportRequest_trySendNotificationMessage(request_title,\n
event =
support_request.SupportRequest_trySendNotificationMessage(request_title,\n
message, person.getRelativeUrl())\n
message, person.getRelativeUrl())\n
\n
if event is not None:\n
computer.edit(**edit_kw)\n
</string>
</value>
</string>
</value>
</item>
</item>
<item>
<item>
<key>
<string>
_params
</string>
</key>
<key>
<string>
_params
</string>
</key>
<value>
<string></string>
</value>
<value>
<string>
target_allocation_scope=\'open/personal\', notification_message_reference=\'slapos-crm-computer_allocation_scope.notification\'
</string>
</value>
</item>
</item>
<item>
<item>
<key>
<string>
id
</string>
</key>
<key>
<string>
id
</string>
</key>
...
...
master/bt5/slapos_crm/SkinTemplateItem/portal_skins/slapos_crm_monitoring/Computer_checkAndUpdatePersonalAllocationScope.xml
0 → 100644
View file @
42e72e67
<?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>
_body
</string>
</key>
<value>
<string>
context.Computer_checkAndUpdateAllocationScope(\n
target_allocation_scope = \'close/termination\',\n
notification_message_reference=\'slapos-crm-computer_personal_allocation_scope.notification\')\n
</string>
</value>
</item>
<item>
<key>
<string>
_params
</string>
</key>
<value>
<string>
**kw
</string>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
Computer_checkAndUpdatePersonalAllocationScope
</string>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
master/bt5/slapos_crm/TestTemplateItem/testSlapOSCRMSkins.py
View file @
42e72e67
...
@@ -1867,7 +1867,8 @@ class TestSlapOSComputer_notifyWrongAllocationScope(testSlapOSMixin):
...
@@ -1867,7 +1867,8 @@ class TestSlapOSComputer_notifyWrongAllocationScope(testSlapOSMixin):
'context.portal_workflow.doActionFor('
\
'context.portal_workflow.doActionFor('
\
'context, action="edit_action", '
\
'context, action="edit_action", '
\
'comment="Visited by SupportRequest_trySendNotificationMessage '
\
'comment="Visited by SupportRequest_trySendNotificationMessage '
\
'%s %s %s %s" % (message_title, message, source_relative_url, interval_of_day))'
)
'%s %s %s %s" % (message_title, message, source_relative_url, interval_of_day))
\
n
'
\
'return 1'
)
def
test_computerNotAllowedAllocationScope_OpenPublic
(
self
):
def
test_computerNotAllowedAllocationScope_OpenPublic
(
self
):
computer
=
self
.
_makeComputer
(
self
.
new_id
)
computer
=
self
.
_makeComputer
(
self
.
new_id
)
person
=
computer
.
getSourceAdministrationValue
()
person
=
computer
.
getSourceAdministrationValue
()
...
@@ -1899,7 +1900,8 @@ class TestSlapOSComputer_notifyWrongAllocationScope(testSlapOSMixin):
...
@@ -1899,7 +1900,8 @@ class TestSlapOSComputer_notifyWrongAllocationScope(testSlapOSMixin):
'context.portal_workflow.doActionFor('
\
'context.portal_workflow.doActionFor('
\
'context, action="edit_action", '
\
'context, action="edit_action", '
\
'comment="Visited by SupportRequest_trySendNotificationMessage '
\
'comment="Visited by SupportRequest_trySendNotificationMessage '
\
'%s %s %s %s" % (message_title, message, source_relative_url, interval_of_day))'
)
'%s %s %s %s" % (message_title, message, source_relative_url, interval_of_day))
\
n
'
\
'return 1'
)
def
test_computerNotAllowedAllocationScope_OpenFriend
(
self
):
def
test_computerNotAllowedAllocationScope_OpenFriend
(
self
):
computer
=
self
.
_makeComputer
(
self
.
new_id
)
computer
=
self
.
_makeComputer
(
self
.
new_id
)
person
=
computer
.
getSourceAdministrationValue
()
person
=
computer
.
getSourceAdministrationValue
()
...
@@ -1921,8 +1923,40 @@ class TestSlapOSComputer_notifyWrongAllocationScope(testSlapOSMixin):
...
@@ -1921,8 +1923,40 @@ class TestSlapOSComputer_notifyWrongAllocationScope(testSlapOSMixin):
(
'We have changed allocation scope for %s'
%
computer
.
getReference
(),
(
'We have changed allocation scope for %s'
%
computer
.
getReference
(),
'Test NM content
\
n
%s
\
n
'
%
computer
.
getReference
(),
person
.
getRelativeUrl
(),
'1'
),
'Test NM content
\
n
%s
\
n
'
%
computer
.
getReference
(),
person
.
getRelativeUrl
(),
'1'
),
ticket
.
workflow_history
[
'edit_workflow'
][
-
1
][
'comment'
])
ticket
.
workflow_history
[
'edit_workflow'
][
-
1
][
'comment'
])
@
simulate
(
'NotificationTool_getDocumentValue'
,
'reference=None'
,
'assert reference == "slapos-crm-computer_personal_allocation_scope.notification"
\
n
'
\
'return context.restrictedTraverse('
\
'context.REQUEST["test_computerToCloseAllocationScope_OpenPersonal"])'
)
@
simulate
(
'SupportRequest_trySendNotificationMessage'
,
'message_title, message, source_relative_url, interval_of_day=1'
,
'context.portal_workflow.doActionFor('
\
'context, action="edit_action", '
\
'comment="Visited by SupportRequest_trySendNotificationMessage '
\
'%s %s %s %s" % (message_title, message, source_relative_url, interval_of_day))
\
n
'
\
'return 1'
)
def
test_computerToCloseAllocationScope_OpenPersonal
(
self
):
computer
=
self
.
_makeComputer
(
self
.
new_id
)
person
=
computer
.
getSourceAdministrationValue
()
self
.
portal
.
REQUEST
[
'test_computerToCloseAllocationScope_OpenPersonal'
]
=
\
self
.
_makeNotificationMessage
(
computer
.
getReference
())
friend_person
=
self
.
_makePerson
(
self
.
generateNewId
())
computer
.
edit
(
allocation_scope
=
'open/personal'
,
destination_section
=
friend_person
.
getRelativeUrl
())
computer
.
Computer_checkAndUpdatePersonalAllocationScope
()
self
.
tic
()
self
.
assertEquals
(
computer
.
getAllocationScope
(),
'close/termination'
)
ticket
=
self
.
_getGeneratedSupportRequest
(
computer
)
self
.
assertEquals
(
ticket
.
getSimulationState
(),
'suspended'
)
self
.
assertEqual
(
'Visited by SupportRequest_trySendNotificationMessage '
\
'%s %s %s %s'
%
\
(
'We have changed allocation scope for %s'
%
computer
.
getReference
(),
'Test NM content
\
n
%s
\
n
'
%
computer
.
getReference
(),
person
.
getRelativeUrl
(),
'1'
),
ticket
.
workflow_history
[
'edit_workflow'
][
-
1
][
'comment'
])
def
test_computerNormalAllocationScope_OpenPersonal
(
self
):
def
test_computerNormalAllocationScope_OpenPersonal
(
self
):
computer
=
self
.
_makeComputer
(
self
.
new_id
)
computer
=
self
.
_makeComputer
(
self
.
new_id
)
person
=
computer
.
getSourceAdministrationValue
()
person
=
computer
.
getSourceAdministrationValue
()
...
@@ -2216,4 +2250,4 @@ class TestSlapOSComputer_CheckState(testSlapOSMixin):
...
@@ -2216,4 +2250,4 @@ class TestSlapOSComputer_CheckState(testSlapOSMixin):
ticket_title
.
replace
(
'[MONITORING] '
,
''
),
ticket_title
.
replace
(
'[MONITORING] '
,
''
),
'Test NM content
\
n
%s
\
n
'
%
instance
.
getReference
(),
'Test NM content
\
n
%s
\
n
'
%
instance
.
getReference
(),
person_url
,
message_interval_per_day
),
person_url
,
message_interval_per_day
),
ticket
.
workflow_history
[
'edit_workflow'
][
-
1
][
'comment'
])
ticket
.
workflow_history
[
'edit_workflow'
][
-
1
][
'comment'
])
\ No newline at end of file
master/bt5/slapos_crm/TestTemplateItem/testSlapOSCRMSupportRequestGeneration.py
View file @
42e72e67
...
@@ -79,7 +79,7 @@ class TestSlapOSCloudSupportRequestGeneration(testSlapOSMixin):
...
@@ -79,7 +79,7 @@ class TestSlapOSCloudSupportRequestGeneration(testSlapOSMixin):
computer
.
validate
()
computer
.
validate
()
return
computer
return
computer
def
_makeComputerPartitions
(
self
,
computer
):
def
_makeComputerPartitions
(
self
,
computer
):
for
i
in
range
(
1
,
5
):
for
i
in
range
(
1
,
5
):
id_
=
'partition%s'
%
(
i
,
)
id_
=
'partition%s'
%
(
i
,
)
...
@@ -366,8 +366,6 @@ class TestSlapOSCloudSupportRequestGeneration(testSlapOSMixin):
...
@@ -366,8 +366,6 @@ class TestSlapOSCloudSupportRequestGeneration(testSlapOSMixin):
)
)
self
.
assertEqual
(
event
.
getTitle
(),
title
)
self
.
assertEqual
(
event
.
getTitle
(),
title
)
def
test_Computer_checkState_empty_cache
(
self
):
def
test_Computer_checkState_empty_cache
(
self
):
computer
=
self
.
_makeComputer
(
self
.
new_id
)
computer
=
self
.
_makeComputer
(
self
.
new_id
)
...
@@ -837,6 +835,7 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by C
...
@@ -837,6 +835,7 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by C
self
.
assertEqual
(
'Visited by Computer_checkAndUpdateAllocationScope'
,
self
.
assertEqual
(
'Visited by Computer_checkAndUpdateAllocationScope'
,
computer
.
workflow_history
[
'edit_workflow'
][
-
1
][
'comment'
])
computer
.
workflow_history
[
'edit_workflow'
][
-
1
][
'comment'
])
def
test_Alarm_notAllowedAllocationScope_OpenFriend
(
self
):
def
test_Alarm_notAllowedAllocationScope_OpenFriend
(
self
):
computer
=
self
.
_makeComputer
(
self
.
new_id
)
computer
=
self
.
_makeComputer
(
self
.
new_id
)
...
@@ -867,7 +866,53 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by C
...
@@ -867,7 +866,53 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by C
self
.
assertNotEqual
(
'Visited by Computer_checkAndUpdateAllocationScope'
,
self
.
assertNotEqual
(
'Visited by Computer_checkAndUpdateAllocationScope'
,
computer
.
workflow_history
[
'edit_workflow'
][
-
1
][
'comment'
])
computer
.
workflow_history
[
'edit_workflow'
][
-
1
][
'comment'
])
def
test_Alarm_AllowedAllocationScope_OpenPersonal_old_computer
(
self
):
computer
=
self
.
_makeComputer
(
self
.
new_id
)
computer
.
edit
(
allocation_scope
=
'open/personal'
)
def
getModificationDate
(
self
):
return
DateTime
()
-
50
from
Products.ERP5Type.Base
import
Base
self
.
_simulateComputer_checkAndUpdateAllocationScope
()
original_get_modification
=
Base
.
getModificationDate
Base
.
getModificationDate
=
getModificationDate
try
:
self
.
portal
.
portal_alarms
.
slapos_crm_check_update_allocation_scope
.
activeSense
()
self
.
tic
()
finally
:
Base
.
getModificationDate
=
original_get_modification
self
.
_dropComputer_checkAndUpdateAllocationScope
()
self
.
assertEqual
(
'Visited by Computer_checkAndUpdateAllocationScope'
,
computer
.
workflow_history
[
'edit_workflow'
][
-
1
][
'comment'
])
def
test_Alarm_AllowedAllocationScope_OpenPersonalWithSoftwareInstallation
(
self
):
computer
=
self
.
_makeComputer
(
self
.
new_id
)
computer
.
edit
(
allocation_scope
=
'open/personal'
)
software_installation
=
self
.
_makeSoftwareInstallation
(
self
.
new_id
,
computer
,
"http://..."
)
def
getModificationDate
(
self
):
return
DateTime
()
-
50
from
Products.ERP5Type.Base
import
Base
self
.
_simulateComputer_checkAndUpdateAllocationScope
()
original_get_modification
=
Base
.
getModificationDate
Base
.
getModificationDate
=
getModificationDate
try
:
self
.
portal
.
portal_alarms
.
slapos_crm_check_update_allocation_scope
.
activeSense
()
self
.
tic
()
finally
:
Base
.
getModificationDate
=
original_get_modification
self
.
_dropComputer_checkAndUpdateAllocationScope
()
self
.
assertNotEqual
(
'Visited by Computer_checkAndUpdateAllocationScope'
,
computer
.
workflow_history
[
'edit_workflow'
][
-
1
][
'comment'
])
def
_simulateHostingSubscription_checkSofwareInstanceState
(
self
):
def
_simulateHostingSubscription_checkSofwareInstanceState
(
self
):
script_name
=
'HostingSubscription_checkSofwareInstanceAllocationState'
script_name
=
'HostingSubscription_checkSofwareInstanceAllocationState'
if
script_name
in
self
.
portal
.
portal_skins
.
custom
.
objectIds
():
if
script_name
in
self
.
portal
.
portal_skins
.
custom
.
objectIds
():
...
@@ -902,4 +947,4 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by H
...
@@ -902,4 +947,4 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by H
self
.
assertEqual
(
'Visited by HostingSubscription_checkSofwareInstanceAllocationState'
,
self
.
assertEqual
(
'Visited by HostingSubscription_checkSofwareInstanceAllocationState'
,
host_sub
.
workflow_history
[
'edit_workflow'
][
-
1
][
'comment'
])
host_sub
.
workflow_history
[
'edit_workflow'
][
-
1
][
'comment'
])
\ No newline at end of file
master/bt5/slapos_crm/bt/revision
View file @
42e72e67
49
51
\ No newline at end of file
master/bt5/slapos_crm/bt/template_path_list
View file @
42e72e67
event_module/slapos_crm_web_message_template
event_module/slapos_crm_web_message_template
person_module/allocation_tester
person_module/allocation_tester
portal_alarms/slapos_check_cloud_is_full
portal_alarms/slapos_check_computer_state
portal_alarms/slapos_check_computer_state
portal_alarms/slapos_check_software_instance_state
portal_alarms/slapos_check_software_instance_state
portal_alarms/slapos_crm_cancel_invoice
portal_alarms/slapos_crm_cancel_invoice
...
...
master/bt5/slapos_erp5/PortalTypeRolesTemplateItem/Restricted%20Access%20Token.xml
View file @
42e72e67
<type_roles>
<type_roles>
<role
id=
'Auditor'
>
<property
id=
'title'
>
Agent as auditor
</property>
<property
id=
'base_category_script'
>
ERP5Type_getSecurityCategoryFromContent
</property>
<multi_property
id=
'base_category'
>
agent
</multi_property>
</role>
<role
id=
'Assignor'
>
<role
id=
'Assignor'
>
<property
id=
'title'
>
Group company
</property>
<property
id=
'title'
>
Group company
</property>
<multi_property
id=
'category'
>
group/company
</multi_property>
<multi_property
id=
'category'
>
group/company
</multi_property>
...
...
master/bt5/slapos_erp5/PortalTypeWorkflowChainTemplateItem/workflow_chain_type.xml
View file @
42e72e67
...
@@ -35,6 +35,10 @@
...
@@ -35,6 +35,10 @@
<type>
Person
</type>
<type>
Person
</type>
<workflow>
local_permission_slapos_interaction_workflow
</workflow>
<workflow>
local_permission_slapos_interaction_workflow
</workflow>
</chain>
</chain>
<chain>
<type>
Restricted Access Token
</type>
<workflow>
local_permission_slapos_interaction_workflow
</workflow>
</chain>
<chain>
<chain>
<type>
Sale Invoice Transaction
</type>
<type>
Sale Invoice Transaction
</type>
<workflow>
local_permission_slapos_interaction_workflow
</workflow>
<workflow>
local_permission_slapos_interaction_workflow
</workflow>
...
...
master/bt5/slapos_erp5/WorkflowTemplateItem/portal_workflow/local_permission_slapos_interaction_workflow/interactions/RestrictedAccessToken_edit.xml
0 → 100644
View file @
42e72e67
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"InteractionDefinition"
module=
"Products.ERP5.Interaction"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
actbox_category
</string>
</key>
<value>
<string>
workflow
</string>
</value>
</item>
<item>
<key>
<string>
actbox_name
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
actbox_url
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
activate_script_name
</string>
</key>
<value>
<tuple/>
</value>
</item>
<item>
<key>
<string>
after_script_name
</string>
</key>
<value>
<list>
<string>
Base_updateAllLocalRoles
</string>
</list>
</value>
</item>
<item>
<key>
<string>
before_commit_script_name
</string>
</key>
<value>
<tuple/>
</value>
</item>
<item>
<key>
<string>
description
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
guard
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
RestrictedAccessToken_edit
</string>
</value>
</item>
<item>
<key>
<string>
method_id
</string>
</key>
<value>
<list>
<string>
_setAgent.*
</string>
</list>
</value>
</item>
<item>
<key>
<string>
once_per_transaction
</string>
</key>
<value>
<int>
0
</int>
</value>
</item>
<item>
<key>
<string>
portal_type_filter
</string>
</key>
<value>
<list>
<string>
Restricted Access Token
</string>
</list>
</value>
</item>
<item>
<key>
<string>
script_name
</string>
</key>
<value>
<tuple/>
</value>
</item>
<item>
<key>
<string>
temporary_document_disallowed
</string>
</key>
<value>
<int>
1
</int>
</value>
</item>
<item>
<key>
<string>
title
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
trigger_type
</string>
</key>
<value>
<int>
2
</int>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
master/bt5/slapos_erp5/WorkflowTemplateItem/portal_workflow/local_permission_slapos_interaction_workflow/interactions/UpgradeDecision_edit.xml
0 → 100644
View file @
42e72e67
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"InteractionDefinition"
module=
"Products.ERP5.Interaction"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
actbox_category
</string>
</key>
<value>
<string>
workflow
</string>
</value>
</item>
<item>
<key>
<string>
actbox_name
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
actbox_url
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
activate_script_name
</string>
</key>
<value>
<tuple/>
</value>
</item>
<item>
<key>
<string>
after_script_name
</string>
</key>
<value>
<list>
<string>
Base_updateAllLocalRoles
</string>
</list>
</value>
</item>
<item>
<key>
<string>
before_commit_script_name
</string>
</key>
<value>
<tuple/>
</value>
</item>
<item>
<key>
<string>
description
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
guard
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
UpgradeDecision_edit
</string>
</value>
</item>
<item>
<key>
<string>
method_id
</string>
</key>
<value>
<list>
<string>
_setDestinationSection.*
</string>
</list>
</value>
</item>
<item>
<key>
<string>
once_per_transaction
</string>
</key>
<value>
<int>
0
</int>
</value>
</item>
<item>
<key>
<string>
portal_type_filter
</string>
</key>
<value>
<list>
<string>
Upgrade Decision
</string>
</list>
</value>
</item>
<item>
<key>
<string>
script_name
</string>
</key>
<value>
<tuple/>
</value>
</item>
<item>
<key>
<string>
temporary_document_disallowed
</string>
</key>
<value>
<int>
1
</int>
</value>
</item>
<item>
<key>
<string>
title
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
trigger_type
</string>
</key>
<value>
<int>
2
</int>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
master/bt5/slapos_erp5/bt/revision
View file @
42e72e67
178
181
\ No newline at end of file
master/bt5/slapos_erp5/bt/template_portal_type_workflow_chain_list
View file @
42e72e67
...
@@ -7,6 +7,7 @@ Integration Site | local_permission_slapos_interaction_workflow
...
@@ -7,6 +7,7 @@ Integration Site | local_permission_slapos_interaction_workflow
Payment Transaction | local_permission_slapos_interaction_workflow
Payment Transaction | local_permission_slapos_interaction_workflow
Payzen Event | local_permission_slapos_interaction_workflow
Payzen Event | local_permission_slapos_interaction_workflow
Person | local_permission_slapos_interaction_workflow
Person | local_permission_slapos_interaction_workflow
Restricted Access Token | local_permission_slapos_interaction_workflow
Sale Invoice Transaction | local_permission_slapos_interaction_workflow
Sale Invoice Transaction | local_permission_slapos_interaction_workflow
Sale Packing List | local_permission_slapos_interaction_workflow
Sale Packing List | local_permission_slapos_interaction_workflow
Slave Instance | local_permission_slapos_interaction_workflow
Slave Instance | local_permission_slapos_interaction_workflow
...
...
master/bt5/slapos_
crm/PathTemplateItem/portal_alarms/slapos_check_cloud_is_full
.xml
→
master/bt5/slapos_
pdm/PathTemplateItem/portal_alarms/slapos_pdm_upgrade_decision_process_stopped
.xml
View file @
42e72e67
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
<dictionary>
<dictionary>
<item>
<item>
<key>
<string>
active_sense_method_id
</string>
</key>
<key>
<string>
active_sense_method_id
</string>
</key>
<value>
<string>
Alarm_
checkCloudIsFull
</string>
</value>
<value>
<string>
Alarm_
processStoppedUpgradeDecision
</string>
</value>
</item>
</item>
<item>
<item>
<key>
<string>
description
</string>
</key>
<key>
<string>
description
</string>
</key>
...
@@ -22,7 +22,13 @@
...
@@ -22,7 +22,13 @@
</item>
</item>
<item>
<item>
<key>
<string>
id
</string>
</key>
<key>
<string>
id
</string>
</key>
<value>
<string>
slapos_check_cloud_is_full
</string>
</value>
<value>
<string>
slapos_pdm_upgrade_decision_process_stopped
</string>
</value>
</item>
<item>
<key>
<string>
periodicity_day_frequency
</string>
</key>
<value>
<none/>
</value>
</item>
</item>
<item>
<item>
<key>
<string>
periodicity_hour
</string>
</key>
<key>
<string>
periodicity_hour
</string>
</key>
...
@@ -32,7 +38,9 @@
...
@@ -32,7 +38,9 @@
</item>
</item>
<item>
<item>
<key>
<string>
periodicity_hour_frequency
</string>
</key>
<key>
<string>
periodicity_hour_frequency
</string>
</key>
<value>
<int>
1
</int>
</value>
<value>
<none/>
</value>
</item>
</item>
<item>
<item>
<key>
<string>
periodicity_minute
</string>
</key>
<key>
<string>
periodicity_minute
</string>
</key>
...
@@ -42,9 +50,7 @@
...
@@ -42,9 +50,7 @@
</item>
</item>
<item>
<item>
<key>
<string>
periodicity_minute_frequency
</string>
</key>
<key>
<string>
periodicity_minute_frequency
</string>
</key>
<value>
<value>
<int>
5
</int>
</value>
<none/>
</value>
</item>
</item>
<item>
<item>
<key>
<string>
periodicity_month
</string>
</key>
<key>
<string>
periodicity_month
</string>
</key>
...
@@ -70,7 +76,7 @@
...
@@ -70,7 +76,7 @@
</tuple>
</tuple>
<state>
<state>
<tuple>
<tuple>
<float>
137760864
0.0
</float>
<float>
366
0.0
</float>
<string>
GMT
</string>
<string>
GMT
</string>
</tuple>
</tuple>
</state>
</state>
...
@@ -87,15 +93,9 @@
...
@@ -87,15 +93,9 @@
<key>
<string>
portal_type
</string>
</key>
<key>
<string>
portal_type
</string>
</key>
<value>
<string>
Alarm
</string>
</value>
<value>
<string>
Alarm
</string>
</value>
</item>
</item>
<item>
<key>
<string>
sense_method_id
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<item>
<key>
<string>
title
</string>
</key>
<key>
<string>
title
</string>
</key>
<value>
<string>
Check if vifib cloud is full
</string>
</value>
<value>
<string>
Process Stopped Upgrade Decisions
</string>
</value>
</item>
</item>
</dictionary>
</dictionary>
</pickle>
</pickle>
...
...
master/bt5/slapos_
crm/SkinTemplateItem/portal_skins/slapos_crm_monitoring/Alarm_checkCloudIsFull
.xml
→
master/bt5/slapos_
pdm/SkinTemplateItem/portal_skins/slapos_pdm/Alarm_processStoppedUpgradeDecision
.xml
View file @
42e72e67
...
@@ -51,19 +51,12 @@
...
@@ -51,19 +51,12 @@
<item>
<item>
<key>
<string>
_body
</string>
</key>
<key>
<string>
_body
</string>
</key>
<value>
<string>
portal = context.getPortalObject()\n
<value>
<string>
portal = context.getPortalObject()\n
\n
portal.portal_catalog.searchAndActivate(\n
software_release_preference = portal.portal_preferences.getPreferredSoftwareReleaseToTestForSpace()\n
portal_type=\'Upgrade Decision\',\n
\n
simulation_state=\'stopped\',\n
if software_release_preference != \'\':\n
method_id=\'UpgradeDecision_notifyDelivered\',\n
software_release_list = software_release_preference.split("\\n")\n
activate_kw={\'tag\': tag }\n
\n
)\n
portal.portal_catalog.searchAndActivate(\n
portal_type = \'Software Release\',\n
url_string = software_release_list,\n
\n
method_id = \'SoftwareRelease_testForAllocation\',\n
activate_kw = {\'tag\':tag} \n
)\n
\n
\n
context.activate(after_tag=tag).getId()\n
context.activate(after_tag=tag).getId()\n
</string>
</value>
</string>
</value>
...
@@ -74,7 +67,7 @@ context.activate(after_tag=tag).getId()\n
...
@@ -74,7 +67,7 @@ context.activate(after_tag=tag).getId()\n
</item>
</item>
<item>
<item>
<key>
<string>
id
</string>
</key>
<key>
<string>
id
</string>
</key>
<value>
<string>
Alarm_
checkCloudIsFull
</string>
</value>
<value>
<string>
Alarm_
processStoppedUpgradeDecision
</string>
</value>
</item>
</item>
</dictionary>
</dictionary>
</pickle>
</pickle>
...
...
master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareRelease_createUpgradeDecision.xml
View file @
42e72e67
...
@@ -74,11 +74,12 @@ if not person_url:\n
...
@@ -74,11 +74,12 @@ if not person_url:\n
\n
\n
upgrade_decision = portal.upgrade_decision_module.\\\n
upgrade_decision = portal.upgrade_decision_module.\\\n
template_upgrade_decision.Base_createCloneDocument(batch_mode=1)\n
template_upgrade_decision.Base_createCloneDocument(batch_mode=1)\n
upgrade_decision.edit(\n
\n
title=title,\n
upgrade_decision.edit(title=title)\n
destination_section=person_url,\n
\n
destination_decision=person_url\n
upgrade_decision.setDestinationSection(person_url)\n
)\n
upgrade_decision.setDestinationDecision(person_url)\n
\n
decision_line_list = upgrade_decision.contentValues(\n
decision_line_list = upgrade_decision.contentValues(\n
portal_type=\'Upgrade Decision Line\')\n
portal_type=\'Upgrade Decision Line\')\n
if len(decision_line_list) >
0:\n
if len(decision_line_list) >
0:\n
...
...
master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/UpgradeDecision_getComputerNotificationMessage.xml
0 → 100644
View file @
42e72e67
<?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>
_body
</string>
</key>
<value>
<string>
portal = context.getPortalObject()\n
\n
notification_message = portal.portal_notifications.getDocumentValue(\n
reference=\'slapos-upgrade-computer.notification\')\n
\n
title = "New Software available for Installation at %s" % computer.getTitle()\n
mapping_dict = {\'software_product_title\': software_product_title,\n
\'computer_title\': computer.getTitle(),\n
\'computer_reference\': computer.getReference(),\n
\'software_release_name\': software_release.getTitle(),\n
\'software_release_reference\': software_release.getReference(),\n
\'upgrade_accept_link\': \n
\'Base_acceptUpgradeDecision?reference=%s\' % reference,\n
\'upgrade_reject_link\':\n
\'Base_rejectUpgradeDecision?reference=%s\' % reference,\n
\'new_software_release_url\': software_release.getUrlString(),\n
}\n
\n
\n
if notification_message is not None:\n
message = notification_message.asEntireHTML(\n
substitution_method_parameter_dict={\'mapping_dict\': mapping_dict})\n
else:\n
raise ValueError("No Notification Message")\n
\n
return title, message\n
</string>
</value>
</item>
<item>
<key>
<string>
_params
</string>
</key>
<value>
<string>
computer
</string>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
UpgradeDecision_getComputerNotificationMessage
</string>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
master/bt5/slapos_
crm/SkinTemplateItem/portal_skins/slapos_crm_monitoring/SoftwareRelease_testForAllocation
.xml
→
master/bt5/slapos_
pdm/SkinTemplateItem/portal_skins/slapos_pdm/UpgradeDecision_isUpgradeFinished
.xml
View file @
42e72e67
...
@@ -50,34 +50,34 @@
...
@@ -50,34 +50,34 @@
</item>
</item>
<item>
<item>
<key>
<string>
_body
</string>
</key>
<key>
<string>
_body
</string>
</key>
<value>
<string
>
portal = context.getPortalObject()\n
<value>
<string
encoding=
"cdata"
>
<![CDATA[
software_release = context\n
software_release_url = software_release.getUrlString
()\n
portal = context.getPortalObject
()\n
\n
\n
user = portal.person_module.allocation_tester\n
hosting_subscription = context.UpgradeDecision_getHostingSubscription()\n
computer = context.UpgradeDecision_getComputer()\n
software_release = context.UpgradeDecision_getSoftwareRelease()\n
\n
\n
result = user.Person_restrictMethodAsShadowUser(\n
if hosting_subscription is not None:\n
shadow_document=user,\n
if hosting_subscription.getUrlString() == software_release.getUrlString():\n
callable_object=user.Person_findPartition,\n
return True\n
argument_list=[\n
software_release_url,\n
\'\',\n
\'Software Instance\',\n
{}\n
],\n
argument_dict={\n
\'test_mode\': True})\n
\n
\n
if not result:\n
elif computer is not None:\n
title = "Can\'t allocate new instances for software release %s" % software_release_url\n
full_software_release_list = [si for si in \n
description = "Need more public computers that can instanciate the software release %s" % software_release_url\n
portal.portal_catalog(\n
portal_type=\'Software Installation\',\n
url_string=software_release.getUrlString(),\n
default_aggregate_uid=computer.getUid(),\n
validation_state=\'validated\'\n
) if si.getSlapState() == \'start_requested\']\n
\n
\n
return software_release.Base_generateSupportRequestForSlapOS(\n
if len(full_software_release_list) >
0:\n
title,\n
return True\n
description,\n
\n
software_release.getRelativeUrl()\n
return False\n
)\n
</string>
</value>
]]>
</string>
</value>
</item>
</item>
<item>
<item>
<key>
<string>
_params
</string>
</key>
<key>
<string>
_params
</string>
</key>
...
@@ -85,7 +85,7 @@ if not result:\n
...
@@ -85,7 +85,7 @@ if not result:\n
</item>
</item>
<item>
<item>
<key>
<string>
id
</string>
</key>
<key>
<string>
id
</string>
</key>
<value>
<string>
SoftwareRelease_testForAllocation
</string>
</value>
<value>
<string>
UpgradeDecision_isUpgradeFinished
</string>
</value>
</item>
</item>
</dictionary>
</dictionary>
</pickle>
</pickle>
...
...
master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/UpgradeDecision_notifyDelivered.xml
0 → 100644
View file @
42e72e67
<?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>
_body
</string>
</key>
<value>
<string>
from DateTime import DateTime\n
\n
if context.getSimulationState() != \'stopped\':\n
return \n
\n
if context.UpgradeDecision_isUpgradeFinished():\n
return \n
\n
portal = context.getPortalObject()\n
\n
person = context.getDestinationDecisionValue(portal_type="Person")\n
if not person:\n
raise ValueError("Inconsistent Upgrade Decision, No Destination Decision")\n
\n
hosting_subscription = context.UpgradeDecision_getHostingSubscription()\n
computer = context.UpgradeDecision_getComputer()\n
software_release = context.UpgradeDecision_getSoftwareRelease()\n
software_product_title = software_release.getAggregateTitle(\n
portal_type="Software Product")\n
\n
reference = context.getReference()\n
\n
mapping_dict = {\n
\'software_product_title\': software_product_title,\n
\'software_release_name\': software_release.getTitle(),\n
\'software_release_reference\': software_release.getReference(),\n
\'new_software_release_url\': software_release.getUrlString(),\n
}\n
\n
if hosting_subscription is not None:\n
notification_message_reference = \'slapos-upgrade-delivered-hosting-subscription.notification\'\n
title = "Upgrade Processed for %s (%s)" % (hosting_subscription.getTitle(), \n
software_release.getReference())\n
mapping_dict.update(**{\n
\'hosting_subscription_title\': hosting_subscription.getTitle(),\n
\'old_software_release_url\': hosting_subscription.getUrlString()})\n
\n
elif computer is not None:\n
\n
notification_message_reference = \'slapos-upgrade-delivered-computer.notification\' \n
\n
title = "Upgrade processed at %s for %s" % (computer.getTitle(), software_release.getReference()) \n
mapping_dict.update(**{\'computer_title\': computer.getTitle(),\n
\'computer_reference\': computer.getReference()})\n
\n
\n
if notification_message_reference is None:\n
raise ValueError("No Notification Message")\n
\n
notification_message = portal.portal_notifications.getDocumentValue(\n
reference=notification_message_reference)\n
\n
message = notification_message.asEntireHTML(\n
substitution_method_parameter_dict={\'mapping_dict\': mapping_dict})\n
\n
event = context.SupportRequest_trySendNotificationMessage(title,\n
message, person.getRelativeUrl())\n
\n
if event is not None:\n
context.deliver()\n
</string>
</value>
</item>
<item>
<key>
<string>
_params
</string>
</key>
<value>
<string>
**kw
</string>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
UpgradeDecision_notifyDelivered
</string>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
master/bt5/slapos_pdm/TestTemplateItem/testSlapOSPDMAlarm.py
View file @
42e72e67
...
@@ -87,6 +87,23 @@ return %s
...
@@ -87,6 +87,23 @@ return %s
upgrade_decision
.
workflow_history
[
'edit_workflow'
][
-
1
][
'comment'
])
upgrade_decision
.
workflow_history
[
'edit_workflow'
][
-
1
][
'comment'
])
def
test_alarm_upgrade_decision_process_stopped
(
self
):
upgrade_decision
=
self
.
_makeUpgradeDecision
()
upgrade_decision
.
start
()
upgrade_decision
.
stop
()
self
.
tic
()
self
.
_simulateScript
(
'UpgradeDecision_notifyDelivered'
)
try
:
self
.
portal
.
portal_alarms
.
slapos_pdm_upgrade_decision_process_stopped
.
\
activeSense
()
self
.
tic
()
finally
:
self
.
_dropScript
(
'UpgradeDecision_notifyDelivered'
)
self
.
assertEqual
(
'Visited by UpgradeDecision_notifyDelivered'
,
upgrade_decision
.
workflow_history
[
'edit_workflow'
][
-
1
][
'comment'
])
def
test_alarm_computer_create_upgrade_decision
(
self
):
def
test_alarm_computer_create_upgrade_decision
(
self
):
computer
=
self
.
_makeComputer
(
self
.
new_id
)
computer
=
self
.
_makeComputer
(
self
.
new_id
)
computer
.
edit
(
allocation_scope
=
'open/public'
)
computer
.
edit
(
allocation_scope
=
'open/public'
)
...
...
master/bt5/slapos_pdm/TestTemplateItem/testSlapOSPDMSkins.py
View file @
42e72e67
...
@@ -1394,6 +1394,37 @@ class TestSlapOSPDMSkins(testSlapOSMixin):
...
@@ -1394,6 +1394,37 @@ class TestSlapOSPDMSkins(testSlapOSMixin):
"?portal_status_message=Upgrade%20Decision%20is%20already%20Rejected%21"
),
"?portal_status_message=Upgrade%20Decision%20is%20already%20Rejected%21"
),
"%s contains the wrong message"
%
redirect_url
)
"%s contains the wrong message"
%
redirect_url
)
def
testUpgradeDecision_isUpgradeFinished_computer
(
self
):
computer
=
self
.
_makeComputer
(
self
.
new_id
)
software_release
=
self
.
_makeSoftwareRelease
(
self
.
new_id
)
upgrade_decision
=
self
.
_makeUpgradeDecision
()
upgrade_decision_line
=
self
.
_makeUpgradeDecisionLine
(
upgrade_decision
)
upgrade_decision_line
.
setAggregateValueList
([
software_release
,
computer
])
upgrade_decision
.
confirm
()
upgrade_decision
.
stop
()
self
.
assertFalse
(
upgrade_decision
.
UpgradeDecision_isUpgradeFinished
())
self
.
_makeSoftwareInstallation
(
self
.
new_id
,
computer
,
software_release
.
getUrlString
())
self
.
tic
()
self
.
assertTrue
(
upgrade_decision
.
UpgradeDecision_isUpgradeFinished
())
def
testUpgradeDecision_isUpgradeFinished_hosting_subscription
(
self
):
hosting_subscription
=
self
.
_makeHostingSubscription
(
self
.
new_id
)
software_release
=
self
.
_makeSoftwareRelease
(
self
.
new_id
)
upgrade_decision
=
self
.
_makeUpgradeDecision
()
upgrade_decision_line
=
self
.
_makeUpgradeDecisionLine
(
upgrade_decision
)
upgrade_decision_line
.
setAggregateValueList
([
software_release
,
hosting_subscription
])
upgrade_decision
.
confirm
()
upgrade_decision
.
stop
()
self
.
assertFalse
(
upgrade_decision
.
UpgradeDecision_isUpgradeFinished
())
hosting_subscription
.
setUrlString
(
software_release
.
getUrlString
())
self
.
assertTrue
(
upgrade_decision
.
UpgradeDecision_isUpgradeFinished
())
@
simulate
(
'NotificationTool_getDocumentValue'
,
@
simulate
(
'NotificationTool_getDocumentValue'
,
'reference=None'
,
'reference=None'
,
'assert reference == "slapos-upgrade-computer.notification"
\
n
'
\
'assert reference == "slapos-upgrade-computer.notification"
\
n
'
\
...
@@ -1524,4 +1555,134 @@ ${new_software_release_url}""",
...
@@ -1524,4 +1555,134 @@ ${new_software_release_url}""",
self
.
assertEquals
(
event
.
getSimulationState
(),
"delivered"
)
self
.
assertEquals
(
event
.
getSimulationState
(),
"delivered"
)
\ No newline at end of file
@
simulate
(
'NotificationTool_getDocumentValue'
,
'reference=None'
,
'assert reference == "slapos-upgrade-delivered-computer.notification"
\
n
'
\
'return context.restrictedTraverse('
\
'context.REQUEST["testUpgradeDecision_notifyDelivered_computer"])'
)
@
simulate
(
'UpgradeDecision_isUpgradeFinished'
,
''
,
'return 0'
)
def
testUpgradeDecision_notifyDelivered_computer
(
self
):
person
=
self
.
_makePerson
(
self
.
new_id
)
computer
=
self
.
_makeComputer
(
self
.
new_id
)
software_release
=
self
.
_makeSoftwareRelease
(
self
.
new_id
)
software_product
=
self
.
_makeSoftwareProduct
(
self
.
new_id
)
software_release
.
setAggregateValue
(
software_product
)
upgrade_decision
=
self
.
_makeUpgradeDecision
()
upgrade_decision
.
edit
(
destination_decision_value
=
person
)
upgrade_decision_line
=
self
.
_makeUpgradeDecisionLine
(
upgrade_decision
)
upgrade_decision_line
.
setAggregateValueList
([
software_release
,
computer
])
notification_message
=
self
.
portal
.
notification_message_module
.
newContent
(
portal_type
=
"Notification Message"
,
title
=
'Test NM title %s'
%
self
.
new_id
,
text_content_substitution_mapping_method_id
=
"NotificationMessage_getSubstitutionMappingDictFromArgument"
,
text_content
=
"""${software_product_title}
${computer_title}
${computer_reference}
${software_release_name}
${software_release_reference}
${new_software_release_url}"""
,
content_type
=
'text/html'
,
)
self
.
portal
.
REQUEST
\
[
'testUpgradeDecision_notifyDelivered_computer'
]
=
\
notification_message
.
getRelativeUrl
()
self
.
tic
()
self
.
assertEquals
(
None
,
upgrade_decision
.
UpgradeDecision_notifyDelivered
())
upgrade_decision
.
start
()
upgrade_decision
.
stop
()
self
.
tic
()
self
.
assertEquals
(
None
,
upgrade_decision
.
UpgradeDecision_notifyDelivered
())
self
.
tic
()
self
.
assertEquals
(
upgrade_decision
.
getSimulationState
(),
'delivered'
)
self
.
assertEquals
(
len
(
upgrade_decision
.
getFollowUpRelatedValueList
()),
1
)
event
=
upgrade_decision
.
getFollowUpRelatedValue
()
self
.
assertEquals
(
event
.
getTitle
(),
"Upgrade processed at %s for %s"
%
(
computer
.
getTitle
(),
software_release
.
getReference
()))
self
.
assertEqual
(
event
.
getTextContent
().
splitlines
(),
[
software_product
.
getTitle
(),
computer
.
getTitle
(),
computer
.
getReference
(),
software_release
.
getTitle
(),
software_release
.
getReference
(),
software_release
.
getUrlString
()])
self
.
assertEquals
(
event
.
getSimulationState
(),
"delivered"
)
@
simulate
(
'NotificationTool_getDocumentValue'
,
'reference=None'
,
'assert reference == "slapos-upgrade-delivered-hosting-subscription.notification"
\
n
'
\
'return context.restrictedTraverse('
\
'context.REQUEST["testUpgradeDecision_notifyDelivered_hosting_subscription"])'
)
@
simulate
(
'UpgradeDecision_isUpgradeFinished'
,
''
,
'return 0'
)
def
testUpgradeDecision_notifyDelivered_hosting_subscription
(
self
):
person
=
self
.
_makePerson
(
self
.
new_id
)
hosting_subscription
=
self
.
_makeHostingSubscription
(
self
.
new_id
)
software_release
=
self
.
_makeSoftwareRelease
(
self
.
new_id
)
software_product
=
self
.
_makeSoftwareProduct
(
self
.
new_id
)
software_release
.
setAggregateValue
(
software_product
)
upgrade_decision
=
self
.
_makeUpgradeDecision
()
upgrade_decision
.
edit
(
destination_decision_value
=
person
)
upgrade_decision_line
=
self
.
_makeUpgradeDecisionLine
(
upgrade_decision
)
upgrade_decision_line
.
setAggregateValueList
([
software_release
,
hosting_subscription
])
old_url
=
hosting_subscription
.
getUrlString
()
notification_message
=
self
.
portal
.
notification_message_module
.
newContent
(
portal_type
=
"Notification Message"
,
title
=
'Test NM title %s'
%
self
.
new_id
,
text_content_substitution_mapping_method_id
=
"NotificationMessage_getSubstitutionMappingDictFromArgument"
,
text_content
=
"""${software_product_title}
${hosting_subscription_title}
${old_software_release_url}
${software_release_name}
${software_release_reference}
${new_software_release_url}"""
,
content_type
=
'text/html'
,
)
self
.
portal
.
REQUEST
\
[
'testUpgradeDecision_notifyDelivered_hosting_subscription'
]
=
\
notification_message
.
getRelativeUrl
()
self
.
tic
()
self
.
assertEquals
(
None
,
upgrade_decision
.
UpgradeDecision_notifyDelivered
())
upgrade_decision
.
start
()
upgrade_decision
.
stop
()
self
.
tic
()
self
.
assertEquals
(
None
,
upgrade_decision
.
UpgradeDecision_notifyDelivered
())
self
.
tic
()
self
.
assertEquals
(
upgrade_decision
.
getSimulationState
(),
'delivered'
)
self
.
assertEquals
(
len
(
upgrade_decision
.
getFollowUpRelatedValueList
()),
1
)
event
=
upgrade_decision
.
getFollowUpRelatedValue
()
self
.
assertEquals
(
event
.
getTitle
(),
"Upgrade Processed for %s (%s)"
%
(
hosting_subscription
.
getTitle
(),
software_release
.
getReference
()))
self
.
assertEqual
(
event
.
getTextContent
().
splitlines
(),
[
software_product
.
getTitle
(),
hosting_subscription
.
getTitle
(),
old_url
,
software_release
.
getTitle
(),
software_release
.
getReference
(),
software_release
.
getUrlString
()])
self
.
assertEquals
(
event
.
getSimulationState
(),
"delivered"
)
master/bt5/slapos_pdm/bt/revision
View file @
42e72e67
32
37
\ No newline at end of file
master/bt5/slapos_pdm/bt/template_path_list
View file @
42e72e67
...
@@ -3,6 +3,7 @@ portal_alarms/slapos_pdm_computer_create_upgrade_decision
...
@@ -3,6 +3,7 @@ portal_alarms/slapos_pdm_computer_create_upgrade_decision
portal_alarms/slapos_pdm_hosting_subscription_create_upgrade_decision
portal_alarms/slapos_pdm_hosting_subscription_create_upgrade_decision
portal_alarms/slapos_pdm_upgrade_decision_process_planned
portal_alarms/slapos_pdm_upgrade_decision_process_planned
portal_alarms/slapos_pdm_upgrade_decision_process_started
portal_alarms/slapos_pdm_upgrade_decision_process_started
portal_alarms/slapos_pdm_upgrade_decision_process_stopped
software_product_module/template_software_product
software_product_module/template_software_product
software_release_module/template_software_release
software_release_module/template_software_release
upgrade_decision_module/template_upgrade_decision
upgrade_decision_module/template_upgrade_decision
\ No newline at end of file
master/bt5/slapos_web/SkinTemplateItem/portal_skins/slapos_rss/WebSection_getUserRssTicketList.xml
View file @
42e72e67
...
@@ -51,8 +51,8 @@
...
@@ -51,8 +51,8 @@
<item>
<item>
<key>
<string>
_body
</string>
</key>
<key>
<string>
_body
</string>
</key>
<value>
<string>
portal = context.getPortalObject()\n
<value>
<string>
portal = context.getPortalObject()\n
kw[\'portal_type\'] = ["Support Request", "Regularisation Request"]\n
kw[\'portal_type\'] = ["Support Request", "Regularisation Request"
, "Upgrader Decision"
]\n
kw[\'simulation_state\'] = [\'validated\',\'submitted\']
\n
\n
\n
\n
person = portal.ERP5Site_getAuthenticatedMemberPersonValue()\n
person = portal.ERP5Site_getAuthenticatedMemberPersonValue()\n
if person:\n
if person:\n
...
...
master/bt5/slapos_web/SkinTemplateItem/portal_skins/vifib_hosting/Base_generateRssRestrictedAccessTokenFromJS.xml
View file @
42e72e67
...
@@ -57,6 +57,9 @@ import json\n
...
@@ -57,6 +57,9 @@ import json\n
portal = context.getPortalObject()\n
portal = context.getPortalObject()\n
person = portal.ERP5Site_getAuthenticatedMemberPersonValue()\n
person = portal.ERP5Site_getAuthenticatedMemberPersonValue()\n
\n
\n
if person is None:\n
raise ValueError("User Not Found")\n
\n
web_site = context.getWebSiteValue()\n
web_site = context.getWebSiteValue()\n
request_url = "%s/%s" % (web_site.absolute_url(), "feed")\n
request_url = "%s/%s" % (web_site.absolute_url(), "feed")\n
\n
\n
...
@@ -69,22 +72,24 @@ for token_item in portal.portal_catalog(\n
...
@@ -69,22 +72,24 @@ for token_item in portal.portal_catalog(\n
):\n
):\n
if token_item.getUrlString() == request_url:\n
if token_item.getUrlString() == request_url:\n
access_token = token_item\n
access_token = token_item\n
reference = access_token.getReference()\n
break;\n
break;\n
\n
\n
if access_token is None:\n
if access_token is None:\n
access_token = portal.access_token_module.newContent(\n
access_token = portal.access_token_module.newContent(\n
portal_type="Restricted Access Token",\n
portal_type="Restricted Access Token",\n
agent_value=person,\n
url_string=request_url,\n
url_string=request_url,\n
url_method="GET",\n
url_method="GET",\n
)\n
)\n
access_token.setAgentValue(person)\n
reference = access_token.getReference() \n
access_token.validate()\n
access_token.validate()\n
\n
\n
url = "%s/%s?portal_skin=RSS&access_token=%s&access_token_secret=%s" % (\n
url = "%s/%s?portal_skin=RSS&access_token=%s&access_token_secret=%s" % (\n
web_site.absolute_url(),\n
web_site.absolute_url(),\n
"feed",\n
"feed",\n
access_token.getId(),\n
access_token.getId(),\n
access_token.getReference()
)\n
reference
)\n
\n
\n
request = context.REQUEST\n
request = context.REQUEST\n
response = request.RESPONSE\n
response = request.RESPONSE\n
...
...
master/bt5/slapos_web/bt/revision
View file @
42e72e67
63
65
\ No newline at end of file
slapos/collect/__init__.py
View file @
42e72e67
...
@@ -79,7 +79,7 @@ def do_collect(conf):
...
@@ -79,7 +79,7 @@ def do_collect(conf):
raise
raise
log_directory
=
"%s/var/data-log"
%
conf
.
get
(
"slapos"
,
"instance_root"
)
log_directory
=
"%s/var/data-log"
%
conf
.
get
(
"slapos"
,
"instance_root"
)
mkdir_p
(
log_directory
)
mkdir_p
(
log_directory
,
0o755
)
database
=
Database
(
log_directory
)
database
=
Database
(
log_directory
)
computer
=
Computer
(
ComputerSnapshot
())
computer
=
Computer
(
ComputerSnapshot
())
...
...
slapos/grid/slapgrid.py
View file @
42e72e67
...
@@ -37,6 +37,7 @@ import subprocess
...
@@ -37,6 +37,7 @@ import subprocess
import
sys
import
sys
import
tempfile
import
tempfile
import
time
import
time
import
stat
import
traceback
import
traceback
import
warnings
import
warnings
import
logging
import
logging
...
@@ -352,8 +353,17 @@ class Slapgrid(object):
...
@@ -352,8 +353,17 @@ class Slapgrid(object):
raise
OSError
(
'%s does not exist.'
%
self
.
instance_root
)
raise
OSError
(
'%s does not exist.'
%
self
.
instance_root
)
# Creates everything needed
# Creates everything needed
# Create directory accessible for the instances.
var_directory
=
os
.
path
.
join
(
self
.
instance_root
,
'var'
)
if
not
os
.
path
.
isdir
(
var_directory
):
os
.
mkdir
(
var_directory
)
os
.
chmod
(
var_directory
,
stat
.
S_IRWXU
|
stat
.
S_IROTH
|
stat
.
S_IXOTH
|
\
stat
.
S_IRGRP
|
stat
.
S_IXGRP
)
mkdir_p
(
os
.
path
.
join
(
self
.
instance_root
,
'var'
),
0o755
)
# Creates instance_root structure
# Creates instance_root structure
createPrivateDirectory
(
os
.
path
.
join
(
self
.
instance_root
,
'var'
))
createPrivateDirectory
(
os
.
path
.
join
(
self
.
instance_root
,
'var'
,
'log'
))
createPrivateDirectory
(
os
.
path
.
join
(
self
.
instance_root
,
'var'
,
'log'
))
createPrivateDirectory
(
os
.
path
.
join
(
self
.
instance_root
,
'var'
,
'run'
))
createPrivateDirectory
(
os
.
path
.
join
(
self
.
instance_root
,
'var'
,
'run'
))
...
...
slapos/proxy/schema.sql
View file @
42e72e67
--version:10
--version:11
CREATE
TABLE
IF
NOT
EXISTS
software
%
(
version
)
s
(
url
VARCHAR
(
255
)
UNIQUE
);
CREATE
TABLE
IF
NOT
EXISTS
software
%
(
version
)
s
(
url
VARCHAR
(
255
),
computer_reference
VARCHAR
(
255
)
DEFAULT
'%(computer)s'
,
CONSTRAINT
uniq
PRIMARY
KEY
(
url
,
computer_reference
)
);
CREATE
TABLE
IF
NOT
EXISTS
computer
%
(
version
)
s
(
CREATE
TABLE
IF
NOT
EXISTS
computer
%
(
version
)
s
(
reference
VARCHAR
(
255
)
DEFAULT
'%(computer)s'
,
address
VARCHAR
(
255
),
address
VARCHAR
(
255
),
netmask
VARCHAR
(
255
),
netmask
VARCHAR
(
255
),
CONSTRAINT
uniq
PRIMARY
KEY
(
address
,
netmask
));
CONSTRAINT
uniq
PRIMARY
KEY
(
reference
)
);
CREATE
TABLE
IF
NOT
EXISTS
partition
%
(
version
)
s
(
CREATE
TABLE
IF
NOT
EXISTS
partition
%
(
version
)
s
(
reference
VARCHAR
(
255
)
UNIQUE
,
reference
VARCHAR
(
255
),
computer_reference
VARCHAR
(
255
)
DEFAULT
'%(computer)s'
,
slap_state
VARCHAR
(
255
)
DEFAULT
'free'
,
slap_state
VARCHAR
(
255
)
DEFAULT
'free'
,
software_release
VARCHAR
(
255
),
software_release
VARCHAR
(
255
),
xml
TEXT
,
xml
TEXT
,
...
@@ -16,11 +24,13 @@ CREATE TABLE IF NOT EXISTS partition%(version)s (
...
@@ -16,11 +24,13 @@ CREATE TABLE IF NOT EXISTS partition%(version)s (
partition_reference
VARCHAR
(
255
),
partition_reference
VARCHAR
(
255
),
requested_by
VARCHAR
(
255
),
-- only used for debugging,
requested_by
VARCHAR
(
255
),
-- only used for debugging,
-- slapproxy does not support proper scope
-- slapproxy does not support proper scope
requested_state
VARCHAR
(
255
)
NOT
NULL
DEFAULT
'started'
requested_state
VARCHAR
(
255
)
NOT
NULL
DEFAULT
'started'
,
CONSTRAINT
uniq
PRIMARY
KEY
(
reference
,
computer_reference
)
);
);
CREATE
TABLE
IF
NOT
EXISTS
slave
%
(
version
)
s
(
CREATE
TABLE
IF
NOT
EXISTS
slave
%
(
version
)
s
(
reference
VARCHAR
(
255
)
UNIQUE
,
reference
VARCHAR
(
255
),
computer_reference
VARCHAR
(
255
)
DEFAULT
'%(computer)s'
,
connection_xml
TEXT
,
connection_xml
TEXT
,
hosted_by
VARCHAR
(
255
),
hosted_by
VARCHAR
(
255
),
asked_by
VARCHAR
(
255
)
-- only used for debugging,
asked_by
VARCHAR
(
255
)
-- only used for debugging,
...
@@ -29,7 +39,9 @@ CREATE TABLE IF NOT EXISTS slave%(version)s (
...
@@ -29,7 +39,9 @@ CREATE TABLE IF NOT EXISTS slave%(version)s (
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
),
computer_reference
VARCHAR
(
255
)
DEFAULT
'%(computer)s'
,
reference
VARCHAR
(
255
),
reference
VARCHAR
(
255
),
address
VARCHAR
(
255
),
address
VARCHAR
(
255
),
netmask
VARCHAR
(
255
)
netmask
VARCHAR
(
255
)
);
);
slapos/proxy/views.py
View file @
42e72e67
...
@@ -73,12 +73,15 @@ def dict2xml(dictionary):
...
@@ -73,12 +73,15 @@ def dict2xml(dictionary):
def
partitiondict2partition
(
partition
):
def
partitiondict2partition
(
partition
):
slap_partition
=
ComputerPartition
(
app
.
config
[
'computer_id'
],
for
key
,
value
in
partition
.
iteritems
():
if
type
(
value
)
is
unicode
:
partition
[
key
]
=
value
.
encode
()
slap_partition
=
ComputerPartition
(
partition
[
'computer_reference'
],
partition
[
'reference'
])
partition
[
'reference'
])
slap_partition
.
_software_release_document
=
None
slap_partition
.
_software_release_document
=
None
slap_partition
.
_requested_state
=
'destroyed'
slap_partition
.
_requested_state
=
'destroyed'
slap_partition
.
_need_modification
=
0
slap_partition
.
_need_modification
=
0
slap_partition
.
_instance_guid
=
partition
[
'reference'
]
slap_partition
.
_instance_guid
=
'%s-%s'
%
(
partition
[
'computer_reference'
],
partition
[
'reference'
])
if
partition
[
'software_release'
]:
if
partition
[
'software_release'
]:
slap_partition
.
_need_modification
=
1
slap_partition
.
_need_modification
=
1
...
@@ -86,8 +89,8 @@ def partitiondict2partition(partition):
...
@@ -86,8 +89,8 @@ def partitiondict2partition(partition):
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'
,
for
address
in
execute_db
(
'partition_network'
,
'SELECT * FROM %s WHERE partition_reference=?'
,
'SELECT * FROM %s WHERE partition_reference=?
AND computer_reference=?
'
,
[
partition
[
'reference'
]]):
[
partition
[
'reference'
]
,
partition
[
'computer_reference'
]
]):
address_list
.
append
((
address
[
'reference'
],
address
[
'address'
]))
address_list
.
append
((
address
[
'reference'
],
address
[
'address'
]))
slap_partition
.
_parameter_dict
[
'ip_list'
]
=
address_list
slap_partition
.
_parameter_dict
[
'ip_list'
]
=
address_list
slap_partition
.
_parameter_dict
[
'slap_software_type'
]
=
\
slap_partition
.
_parameter_dict
[
'slap_software_type'
]
=
\
...
@@ -95,17 +98,24 @@ def partitiondict2partition(partition):
...
@@ -95,17 +98,24 @@ def partitiondict2partition(partition):
if
partition
[
'slave_instance_list'
]
is
not
None
:
if
partition
[
'slave_instance_list'
]
is
not
None
:
slap_partition
.
_parameter_dict
[
'slave_instance_list'
]
=
\
slap_partition
.
_parameter_dict
[
'slave_instance_list'
]
=
\
xml_marshaller
.
xml_marshaller
.
loads
(
partition
[
'slave_instance_list'
])
xml_marshaller
.
xml_marshaller
.
loads
(
partition
[
'slave_instance_list'
])
else
:
slap_partition
.
_parameter_dict
[
'slave_instance_list'
]
=
[]
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
=
partition
[
'computer_reference
'
])
return
slap_partition
return
slap_partition
def
execute_db
(
table
,
query
,
args
=
(),
one
=
False
):
def
execute_db
(
table
,
query
,
args
=
(),
one
=
False
,
db_version
=
None
,
log
=
False
):
if
not
db_version
:
db_version
=
DB_VERSION
query
=
query
%
(
table
+
db_version
,)
if
log
:
print
query
try
:
try
:
cur
=
g
.
db
.
execute
(
query
%
(
table
+
DB_VERSION
,)
,
args
)
cur
=
g
.
db
.
execute
(
query
,
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
...
@@ -117,15 +127,66 @@ def execute_db(table, query, args=(), one=False):
...
@@ -117,15 +127,66 @@ def execute_db(table, query, args=(), one=False):
def
connect_db
():
def
connect_db
():
return
sqlite3
.
connect
(
app
.
config
[
'DATABASE_URI'
])
return
sqlite3
.
connect
(
app
.
config
[
'DATABASE_URI'
])
def
_getTableList
():
return
g
.
db
.
execute
(
"SELECT name FROM sqlite_master WHERE type='table' ORDER BY Name"
).
fetchall
()
@
app
.
before_request
def
_getCurrentDatabaseSchemaVersion
():
def
before_request
():
"""
g
.
db
=
connect_db
()
Return version of database schema.
As there is no actual definition of version, analyse
name of all tables (containing version) and take the
highest version (as several versions can live in the db).
"""
# XXX: define an actual version and proper migration/repair procedure.
version
=
-
1
for
table_name
in
_getTableList
():
try
:
table_version
=
int
(
table_name
[
0
][
-
2
:])
except
ValueError
:
table_version
=
int
(
table_name
[
0
][
-
1
:])
if
table_version
>
version
:
version
=
table_version
return
str
(
version
)
def
_upgradeDatabaseIfNeeded
():
"""
Analyses current database compared to defined schema,
and adapt tables/data it if needed.
"""
current_schema_version
=
_getCurrentDatabaseSchemaVersion
()
# If version of current database is not old, do nothing
if
current_schema_version
==
DB_VERSION
:
return
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
,
computer
=
app
.
config
[
'computer_id'
]
)
g
.
db
.
cursor
().
executescript
(
schema
)
g
.
db
.
cursor
().
executescript
(
schema
)
g
.
db
.
commit
()
g
.
db
.
commit
()
if
current_schema_version
==
'-1'
:
return
# Migrate all data to new tables
app
.
logger
.
info
(
'Old schema detected: Migrating old tables...'
)
app
.
logger
.
info
(
'Note that old tables are not alterated.'
)
for
table
in
(
'software'
,
'computer'
,
'partition'
,
'slave'
,
'partition_network'
):
for
row
in
execute_db
(
table
,
'SELECT * from %s'
,
db_version
=
current_schema_version
):
columns
=
', '
.
join
(
row
.
keys
())
placeholders
=
':'
+
', :'
.
join
(
row
.
keys
())
query
=
'INSERT INTO %s (%s) VALUES (%s)'
%
(
'%s'
,
columns
,
placeholders
)
execute_db
(
table
,
query
,
row
,
log
=
True
)
g
.
db
.
commit
()
is_schema_already_executed
=
False
@
app
.
before_request
def
before_request
():
g
.
db
=
connect_db
()
global
is_schema_already_executed
if
not
is_schema_already_executed
:
_upgradeDatabaseIfNeeded
()
is_schema_already_executed
=
True
@
app
.
after_request
@
app
.
after_request
def
after_request
(
response
):
def
after_request
(
response
):
...
@@ -141,37 +202,39 @@ def getComputerInformation():
...
@@ -141,37 +202,39 @@ def getComputerInformation():
@
app
.
route
(
'/getFullComputerInformation'
,
methods
=
[
'GET'
])
@
app
.
route
(
'/getFullComputerInformation'
,
methods
=
[
'GET'
])
def
getFullComputerInformation
():
def
getFullComputerInformation
():
computer_id
=
request
.
args
[
'computer_id'
]
computer_id
=
request
.
args
[
'computer_id'
]
if
app
.
config
[
'computer_id'
]
==
computer_id
:
computer_list
=
execute_db
(
'computer'
,
'SELECT * FROM %s WHERE reference=?'
,
[
computer_id
])
slap_computer
=
Computer
(
computer_id
)
if
len
(
computer_list
)
!=
1
:
slap_computer
.
_software_release_list
=
[]
# Backward compatibility
for
sr
in
execute_db
(
'software'
,
'select * from %s'
):
if
computer_id
!=
app
.
config
[
'computer_id'
]:
slap_computer
.
_software_release_list
.
append
(
SoftwareRelease
(
raise
NotFoundError
(
'%s is not registered.'
%
computer_id
)
software_release
=
sr
[
'url'
],
computer_guid
=
computer_id
))
slap_computer
=
Computer
(
computer_id
)
slap_computer
.
_computer_partition_list
=
[]
slap_computer
.
_software_release_list
=
[]
for
partition
in
execute_db
(
'partition'
,
'SELECT * FROM %s'
):
for
sr
in
execute_db
(
'software'
,
'select * from %s WHERE computer_reference=?'
,
[
computer_id
]):
slap_computer
.
_computer_partition_list
.
append
(
partitiondict2partition
(
slap_computer
.
_software_release_list
.
append
(
SoftwareRelease
(
partition
))
software_release
=
sr
[
'url'
],
computer_guid
=
computer_id
))
return
xml_marshaller
.
xml_marshaller
.
dumps
(
slap_computer
)
slap_computer
.
_computer_partition_list
=
[]
else
:
for
partition
in
execute_db
(
'partition'
,
'SELECT * FROM %s WHERE computer_reference=?'
,
[
computer_id
]):
raise
NotFoundError
(
'Only accept request for: %s'
%
app
.
config
[
'computer_id'
])
slap_computer
.
_computer_partition_list
.
append
(
partitiondict2partition
(
partition
))
return
xml_marshaller
.
xml_marshaller
.
dumps
(
slap_computer
)
@
app
.
route
(
'/setComputerPartitionConnectionXml'
,
methods
=
[
'POST'
])
@
app
.
route
(
'/setComputerPartitionConnectionXml'
,
methods
=
[
'POST'
])
def
setComputerPartitionConnectionXml
():
def
setComputerPartitionConnectionXml
():
slave_reference
=
request
.
form
[
'slave_reference'
].
encode
()
slave_reference
=
request
.
form
[
'slave_reference'
].
encode
()
computer_partition_id
=
request
.
form
[
'computer_partition_id'
]
computer_partition_id
=
request
.
form
[
'computer_partition_id'
].
encode
()
connection_xml
=
request
.
form
[
'connection_xml'
]
computer_id
=
request
.
form
[
'computer_id'
].
encode
()
connection_xml
=
request
.
form
[
'connection_xml'
].
encode
()
connection_dict
=
xml_marshaller
.
xml_marshaller
.
loads
(
connection_dict
=
xml_marshaller
.
xml_marshaller
.
loads
(
connection_xml
.
encode
()
)
connection_xml
)
connection_xml
=
dict2xml
(
connection_dict
)
connection_xml
=
dict2xml
(
connection_dict
)
if
slave_reference
==
'None'
:
if
slave_reference
==
'None'
:
query
=
'UPDATE %s SET connection_xml=? WHERE reference=?'
query
=
'UPDATE %s SET connection_xml=? WHERE reference=?
AND computer_reference=?
'
argument_list
=
[
connection_xml
,
computer_partition_id
.
encode
()
]
argument_list
=
[
connection_xml
,
computer_partition_id
,
computer_id
]
execute_db
(
'partition'
,
query
,
argument_list
)
execute_db
(
'partition'
,
query
,
argument_list
)
return
'done'
return
'done'
else
:
else
:
query
=
'UPDATE %s SET connection_xml=? , hosted_by=? WHERE reference=?'
query
=
'UPDATE %s SET connection_xml=? , hosted_by=? WHERE reference=?'
argument_list
=
[
connection_xml
,
computer_partition_id
.
encode
(),
argument_list
=
[
connection_xml
,
computer_partition_id
,
slave_reference
]
slave_reference
]
execute_db
(
'slave'
,
query
,
argument_list
)
execute_db
(
'slave'
,
query
,
argument_list
)
return
'done'
return
'done'
...
@@ -223,47 +286,41 @@ def useComputer():
...
@@ -223,47 +286,41 @@ def useComputer():
def
loadComputerConfigurationFromXML
():
def
loadComputerConfigurationFromXML
():
xml
=
request
.
form
[
'xml'
]
xml
=
request
.
form
[
'xml'
]
computer_dict
=
xml_marshaller
.
xml_marshaller
.
loads
(
str
(
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(:reference, :address, :netmask)'
,
execute_db
(
'computer'
,
'INSERT OR REPLACE INTO %s values(:address, :netmask)'
,
computer_dict
)
computer_dict
)
for
partition
in
computer_dict
[
'partition_list'
]:
for
partition
in
computer_dict
[
'partition_list'
]:
partition
[
'computer_reference'
]
=
computer_dict
[
'reference'
]
execute_db
(
'partition'
,
'INSERT OR IGNORE INTO %s (reference, computer_reference) values(:reference, :computer_reference)'
,
partition
)
execute_db
(
'partition'
,
'INSERT OR IGNORE INTO %s (reference) values(:reference)'
,
partition
)
execute_db
(
'partition_network'
,
'DELETE FROM %s WHERE partition_reference = ? AND computer_reference = ?'
,
execute_db
(
'partition_network'
,
'DELETE FROM %s WHERE partition_reference = ?'
,
[
partition
[
'reference'
]])
[
partition
[
'reference'
],
partition
[
'computer_reference'
]])
for
address
in
partition
[
'address_list'
]:
for
address
in
partition
[
'address_list'
]:
address
[
'reference'
]
=
partition
[
'tap'
][
'name'
]
address
[
'reference'
]
=
partition
[
'tap'
][
'name'
]
address
[
'partition_reference'
]
=
partition
[
'reference'
]
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
)
address
[
'computer_reference'
]
=
partition
[
'computer_reference'
]
execute_db
(
'partition_network'
,
'INSERT OR REPLACE INTO %s (reference, partition_reference, computer_reference, address, netmask) values(:reference, :partition_reference, :computer_reference, :addr, :netmask)'
,
address
)
return
'done'
return
'done'
else
:
raise
UnauthorizedError
(
'Only accept request for: %s'
%
app
.
config
[
'computer_id'
])
@
app
.
route
(
'/registerComputerPartition'
,
methods
=
[
'GET'
])
@
app
.
route
(
'/registerComputerPartition'
,
methods
=
[
'GET'
])
def
registerComputerPartition
():
def
registerComputerPartition
():
computer_reference
=
request
.
args
[
'computer_reference'
]
computer_reference
=
request
.
args
[
'computer_reference'
].
encode
()
computer_partition_reference
=
request
.
args
[
'computer_partition_reference'
]
computer_partition_reference
=
request
.
args
[
'computer_partition_reference'
].
encode
()
if
app
.
config
[
'computer_id'
]
==
computer_reference
:
partition
=
execute_db
(
'partition'
,
'SELECT * FROM %s WHERE reference=? and computer_reference=?'
,
partition
=
execute_db
(
'partition'
,
'SELECT * FROM %s WHERE reference=?'
,
[
computer_partition_reference
,
computer_reference
],
one
=
True
)
[
computer_partition_reference
.
encode
()],
one
=
True
)
if
partition
is
None
:
if
partition
is
None
:
raise
UnauthorizedError
raise
UnauthorizedError
return
xml_marshaller
.
xml_marshaller
.
dumps
(
return
xml_marshaller
.
xml_marshaller
.
dumps
(
partitiondict2partition
(
partition
))
partitiondict2partition
(
partition
))
else
:
raise
UnauthorizedError
(
'Only accept request for: %s'
%
app
.
config
[
'computer_id'
])
@
app
.
route
(
'/supplySupply'
,
methods
=
[
'POST'
])
@
app
.
route
(
'/supplySupply'
,
methods
=
[
'POST'
])
def
supplySupply
():
def
supplySupply
():
url
=
request
.
form
[
'url'
]
url
=
request
.
form
[
'url'
]
computer_id
=
request
.
form
[
'computer_id'
]
computer_id
=
request
.
form
[
'computer_id'
]
if
app
.
config
[
'computer_id'
]
==
computer_id
:
if
request
.
form
[
'state'
]
==
'destroyed'
:
if
request
.
form
[
'state'
]
==
'destroyed'
:
execute_db
(
'software'
,
'DELETE FROM %s WHERE url = ? AND computer_reference=?'
,
execute_db
(
'software'
,
'DELETE FROM %s WHERE url = ?'
,
[
url
])
[
url
,
computer_id
])
else
:
execute_db
(
'software'
,
'INSERT OR REPLACE INTO %s VALUES(?)'
,
[
url
])
else
:
else
:
raise
UnauthorizedError
(
'Only accept request for: %s'
%
app
.
config
[
'computer_id'
])
execute_db
(
'software'
,
'INSERT OR REPLACE INTO %s VALUES(?, ?)'
,
[
url
,
computer_id
])
return
'%r added'
%
url
return
'%r added'
%
url
...
@@ -281,17 +338,22 @@ def requestComputerPartition():
...
@@ -281,17 +338,22 @@ def requestComputerPartition():
def
softwareInstanceRename
():
def
softwareInstanceRename
():
new_name
=
request
.
form
[
'new_name'
].
encode
()
new_name
=
request
.
form
[
'new_name'
].
encode
()
computer_partition_id
=
request
.
form
[
'computer_partition_id'
].
encode
()
computer_partition_id
=
request
.
form
[
'computer_partition_id'
].
encode
()
computer_id
=
request
.
form
[
'computer_id'
].
encode
()
q
=
'UPDATE %s SET partition_reference = ? WHERE reference = ?'
q
=
'UPDATE %s SET partition_reference = ? WHERE reference = ?
AND computer_reference = ?
'
execute_db
(
'partition'
,
q
,
[
new_name
,
computer_partition_id
])
execute_db
(
'partition'
,
q
,
[
new_name
,
computer_partition_id
,
computer_id
])
return
'done'
return
'done'
@
app
.
route
(
'/getComputerPartitionStatus'
,
methods
=
[
'GET'
])
def
getComputerPartitionStatus
():
return
xml_marshaller
.
xml_marshaller
.
dumps
(
'Not implemented.'
)
def
request_not_shared
():
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'
).
encode
()
software_type
=
request
.
form
.
get
(
'software_type'
).
encode
()
partition_reference
=
request
.
form
.
get
(
'partition_reference'
,
''
).
encode
()
partition_reference
=
request
.
form
.
get
(
'partition_reference'
,
''
).
encode
()
filter_kw
=
request
.
form
.
get
(
'filter_xml'
,
None
)
partition_id
=
request
.
form
.
get
(
'computer_partition_id'
,
''
).
encode
()
partition_id
=
request
.
form
.
get
(
'computer_partition_id'
,
''
).
encode
()
partition_parameter_kw
=
request
.
form
.
get
(
'partition_parameter_xml'
,
None
)
partition_parameter_kw
=
request
.
form
.
get
(
'partition_parameter_xml'
,
None
)
requested_state
=
xml_marshaller
.
xml_marshaller
.
loads
(
request
.
form
.
get
(
'state'
).
encode
())
requested_state
=
xml_marshaller
.
xml_marshaller
.
loads
(
request
.
form
.
get
(
'state'
).
encode
())
...
@@ -300,6 +362,11 @@ def request_not_shared():
...
@@ -300,6 +362,11 @@ def request_not_shared():
partition_parameter_kw
.
encode
())
partition_parameter_kw
.
encode
())
else
:
else
:
partition_parameter_kw
=
{}
partition_parameter_kw
=
{}
if
filter_kw
:
filter_kw
=
xml_marshaller
.
xml_marshaller
.
loads
(
filter_kw
.
encode
())
requested_computer_id
=
filter_kw
.
get
(
'computer_guid'
,
app
.
config
[
'computer_id'
])
else
:
requested_computer_id
=
app
.
config
[
'computer_id'
]
instance_xml
=
dict2xml
(
partition_parameter_kw
)
instance_xml
=
dict2xml
(
partition_parameter_kw
)
args
=
[]
args
=
[]
...
@@ -318,9 +385,12 @@ def request_not_shared():
...
@@ -318,9 +385,12 @@ def request_not_shared():
a
(
requested_state
)
a
(
requested_state
)
# If partition doesn't exist: create it and insert parameters
# If partition doesn't exist: create it and insert parameters
# XXX add support for automatic deployment on specific node depending on available SR and partitions on each Node.
# Note: only deploy on default node if SLA not specified
if
partition
is
None
:
if
partition
is
None
:
partition
=
execute_db
(
'partition'
,
partition
=
execute_db
(
'partition'
,
'SELECT * FROM %s WHERE slap_state="free"'
,
(),
one
=
True
)
'SELECT * FROM %s WHERE slap_state="free" and computer_reference=?'
,
[
requested_computer_id
],
one
=
True
)
if
partition
is
None
:
if
partition
is
None
:
app
.
logger
.
warning
(
'No more free computer partition'
)
app
.
logger
.
warning
(
'No more free computer partition'
)
abort
(
404
)
abort
(
404
)
...
@@ -346,30 +416,32 @@ def request_not_shared():
...
@@ -346,30 +416,32 @@ def request_not_shared():
if
instance_xml
:
if
instance_xml
:
q
+=
' ,xml=?'
q
+=
' ,xml=?'
a
(
instance_xml
)
a
(
instance_xml
)
q
+=
' WHERE reference=?'
q
+=
' WHERE reference=?
AND computer_reference=?
'
a
(
partition
[
'reference'
].
encode
())
a
(
partition
[
'reference'
].
encode
())
a
(
partition
[
'computer_reference'
].
encode
())
execute_db
(
'partition'
,
q
,
args
)
execute_db
(
'partition'
,
q
,
args
)
args
=
[]
args
=
[]
partition
=
execute_db
(
'partition'
,
'SELECT * FROM %s WHERE reference=?'
,
partition
=
execute_db
(
'partition'
,
'SELECT * FROM %s WHERE reference=?
and computer_reference=?
'
,
[
partition
[
'reference'
].
encode
()],
one
=
True
)
[
partition
[
'reference'
].
encode
()
,
partition
[
'computer_reference'
].
encode
()
],
one
=
True
)
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
requested_state
:
requested_state
=
'started'
# XXX it should be ComputerPartition, not a SoftwareInstance
# XXX it should be ComputerPartition, not a SoftwareInstance
software_instance
=
SoftwareInstance
(
xml
=
partition
[
'xml'
],
software_instance
=
SoftwareInstance
(
_connection_dict
=
xml2dict
(
partition
[
'connection_xml'
]),
_connection_dict
=
xml2dict
(
partition
[
'connection_xml'
]),
_parameter_dict
=
xml2dict
(
partition
[
'xml'
]),
_parameter_dict
=
xml2dict
(
partition
[
'xml'
]),
connection_xml
=
partition
[
'connection_xml'
],
connection_xml
=
partition
[
'connection_xml'
],
slap_computer_id
=
app
.
config
[
'computer_id'
]
,
slap_computer_id
=
partition
[
'computer_reference'
].
encode
()
,
slap_computer_partition_id
=
partition
[
'reference'
],
slap_computer_partition_id
=
partition
[
'reference'
],
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_instance_list
=
partition
[
'slave_instance_list'
]
,
_instance_guid
=
'%s-%s'
%
(
partition
[
'computer_reference'
].
encode
(),
partition
[
'reference'
])
,
instance_guid
=
partition
[
'reference'
]
,
_requested_state
=
requested_state
,
ip_list
=
address_list
)
ip_list
=
address_list
)
return
xml_marshaller
.
xml_marshaller
.
dumps
(
software_instance
)
return
xml_marshaller
.
xml_marshaller
.
dumps
(
software_instance
)
...
@@ -397,14 +469,20 @@ def request_slave():
...
@@ -397,14 +469,20 @@ def request_slave():
else
:
else
:
partition_parameter_kw
=
{}
partition_parameter_kw
=
{}
filter_kw
=
xml_marshaller
.
xml_marshaller
.
loads
(
request
.
form
.
get
(
'filter_xml'
).
encode
())
filter_kw
=
request
.
form
.
get
(
'filter_xml'
,
None
)
if
filter_kw
:
filter_kw
=
xml_marshaller
.
xml_marshaller
.
loads
(
filter_kw
.
encode
())
requested_computer_id
=
filter_kw
.
get
(
'computer_guid'
,
app
.
config
[
'computer_id'
])
else
:
requested_computer_id
=
app
.
config
[
'computer_id'
]
instance_xml
=
dict2xml
(
partition_parameter_kw
)
instance_xml
=
dict2xml
(
partition_parameter_kw
)
# We will search for a master corresponding to request
# We will search for a master corresponding to request
args
=
[]
args
=
[]
a
=
args
.
append
a
=
args
.
append
q
=
'SELECT * FROM %s WHERE software_release=?'
q
=
'SELECT * FROM %s WHERE software_release=?
and computer_reference=?
'
a
(
software_release
)
a
(
software_release
)
a
(
requested_computer_id
)
if
software_type
:
if
software_type
:
q
+=
' AND software_type=?'
q
+=
' AND software_type=?'
a
(
software_type
)
a
(
software_type
)
...
@@ -433,7 +511,7 @@ def request_slave():
...
@@ -433,7 +511,7 @@ def request_slave():
if
slave_instance_list
is
None
:
if
slave_instance_list
is
None
:
slave_instance_list
=
[]
slave_instance_list
=
[]
else
:
else
:
slave_instance_list
=
xml_marshaller
.
xml_marshaller
.
loads
(
slave_instance_list
)
slave_instance_list
=
xml_marshaller
.
xml_marshaller
.
loads
(
slave_instance_list
.
encode
()
)
for
x
in
slave_instance_list
:
for
x
in
slave_instance_list
:
if
x
[
'slave_reference'
]
==
slave_reference
:
if
x
[
'slave_reference'
]
==
slave_reference
:
slave_instance_list
.
remove
(
x
)
slave_instance_list
.
remove
(
x
)
...
@@ -445,33 +523,34 @@ def request_slave():
...
@@ -445,33 +523,34 @@ def request_slave():
a
=
args
.
append
a
=
args
.
append
q
=
'UPDATE %s SET slave_instance_list=?'
q
=
'UPDATE %s SET slave_instance_list=?'
a
(
xml_marshaller
.
xml_marshaller
.
dumps
(
slave_instance_list
))
a
(
xml_marshaller
.
xml_marshaller
.
dumps
(
slave_instance_list
))
q
+=
' WHERE reference=?'
q
+=
' WHERE reference=?
and computer_reference=?
'
a
(
partition
[
'reference'
].
encode
())
a
(
partition
[
'reference'
].
encode
())
a
(
requested_computer_id
)
execute_db
(
'partition'
,
q
,
args
)
execute_db
(
'partition'
,
q
,
args
)
args
=
[]
args
=
[]
partition
=
execute_db
(
'partition'
,
'SELECT * FROM %s WHERE reference=?'
,
partition
=
execute_db
(
'partition'
,
'SELECT * FROM %s WHERE reference=?
and computer_reference=?
'
,
[
partition
[
'reference'
].
encode
()],
one
=
True
)
[
partition
[
'reference'
].
encode
()
,
requested_computer_id
],
one
=
True
)
# Add slave to slave table if not there
# Add slave to slave table if not there
slave
=
execute_db
(
'slave'
,
'SELECT * FROM %s WHERE reference=?'
,
slave
=
execute_db
(
'slave'
,
'SELECT * FROM %s WHERE reference=?
and computer_reference=?
'
,
[
slave_reference
],
one
=
True
)
[
slave_reference
,
requested_computer_id
],
one
=
True
)
if
slave
is
None
:
if
slave
is
None
:
execute_db
(
'slave'
,
execute_db
(
'slave'
,
'INSERT OR IGNORE INTO %s (reference,
asked_by,hosted_by) values(:
reference,:asked_by,:hosted_by)'
,
'INSERT OR IGNORE INTO %s (reference,
computer_reference,asked_by,hosted_by) values(:reference,:computer_
reference,:asked_by,:hosted_by)'
,
[
slave_reference
,
partition_id
,
partition
[
'reference'
]])
[
slave_reference
,
requested_computer_id
,
partition_id
,
partition
[
'reference'
]])
slave
=
execute_db
(
'slave'
,
'SELECT * FROM %s WHERE reference=?'
,
slave
=
execute_db
(
'slave'
,
'SELECT * FROM %s WHERE reference=?
and computer_reference=?
'
,
[
slave_reference
],
one
=
True
)
[
slave_reference
,
requested_computer_id
],
one
=
True
)
address_list
=
[]
address_list
=
[]
for
address
in
execute_db
(
'partition_network'
,
for
address
in
execute_db
(
'partition_network'
,
'SELECT * FROM %s WHERE partition_reference=?'
,
'SELECT * FROM %s WHERE partition_reference=?
and computer_reference=?
'
,
[
partition
[
'reference'
]]):
[
partition
[
'reference'
]
,
partition
[
'computer_reference'
]
]):
address_list
.
append
((
address
[
'reference'
],
address
[
'address'
]))
address_list
.
append
((
address
[
'reference'
],
address
[
'address'
]))
# XXX it should be ComputerPartition, not a SoftwareInstance
# XXX it should be ComputerPartition, not a SoftwareInstance
software_instance
=
SoftwareInstance
(
_connection_dict
=
xml2dict
(
slave
[
'connection_xml'
]),
software_instance
=
SoftwareInstance
(
_connection_dict
=
xml2dict
(
slave
[
'connection_xml'
]),
xml
=
instance_xml
,
_parameter_dict
=
xml2dict
(
instance_xml
)
,
slap_computer_id
=
app
.
config
[
'computer_id
'
],
slap_computer_id
=
partition
[
'computer_reference
'
],
slap_computer_partition_id
=
slave
[
'hosted_by'
],
slap_computer_partition_id
=
slave
[
'hosted_by'
],
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'
,
...
@@ -495,5 +574,6 @@ def getSoftwareReleaseListFromSoftwareProduct():
...
@@ -495,5 +574,6 @@ def getSoftwareReleaseListFromSoftwareProduct():
software_release_url_list
=
\
software_release_url_list
=
\
[
app
.
config
[
'software_product_list'
][
software_product_reference
]]
[
app
.
config
[
'software_product_list'
][
software_product_reference
]]
else
:
else
:
software_release_url_list
=
[]
software_release_url_list
=
[]
return
xml_marshaller
.
xml_marshaller
.
dumps
(
software_release_url_list
)
return
xml_marshaller
.
xml_marshaller
.
dumps
(
software_release_url_list
)
slapos/tests/slapgrid.py
View file @
42e72e67
...
@@ -34,6 +34,7 @@ import shutil
...
@@ -34,6 +34,7 @@ import shutil
import
signal
import
signal
import
socket
import
socket
import
sys
import
sys
import
stat
import
tempfile
import
tempfile
import
textwrap
import
textwrap
import
time
import
time
...
@@ -535,6 +536,8 @@ class TestSlapgridCPWithMaster(MasterMixin, unittest.TestCase):
...
@@ -535,6 +536,8 @@ class TestSlapgridCPWithMaster(MasterMixin, unittest.TestCase):
self
.
assertEqual
(
self
.
grid
.
processComputerPartitionList
(),
slapgrid
.
SLAPGRID_SUCCESS
)
self
.
assertEqual
(
self
.
grid
.
processComputerPartitionList
(),
slapgrid
.
SLAPGRID_SUCCESS
)
self
.
assertItemsEqual
(
os
.
listdir
(
self
.
instance_root
),
[
'etc'
,
'var'
])
self
.
assertItemsEqual
(
os
.
listdir
(
self
.
instance_root
),
[
'etc'
,
'var'
])
self
.
assertItemsEqual
(
os
.
listdir
(
self
.
software_root
),
[])
self
.
assertItemsEqual
(
os
.
listdir
(
self
.
software_root
),
[])
st
=
os
.
stat
(
os
.
path
.
join
(
self
.
instance_root
,
'var'
))
self
.
assertEquals
(
stat
.
S_IMODE
(
st
.
st_mode
),
0o755
)
def
test_one_partition
(
self
):
def
test_one_partition
(
self
):
computer
=
ComputerForTest
(
self
.
software_root
,
self
.
instance_root
)
computer
=
ComputerForTest
(
self
.
software_root
,
self
.
instance_root
)
...
...
slapos/tests/slapproxy.py
→
slapos/tests/slapproxy
/__init__
.py
View file @
42e72e67
...
@@ -34,11 +34,15 @@ import shutil
...
@@ -34,11 +34,15 @@ import shutil
import
tempfile
import
tempfile
import
unittest
import
unittest
import
xml_marshaller
import
xml_marshaller
from
xml_marshaller.xml_marshaller
import
loads
,
dumps
import
slapos.proxy
import
slapos.proxy
import
slapos.proxy.views
as
views
import
slapos.proxy.views
as
views
import
slapos.slap.slap
import
slapos.slap.slap
import
sqlite3
import
pkg_resources
class
WrongFormat
(
Exception
):
class
WrongFormat
(
Exception
):
pass
pass
...
@@ -104,13 +108,15 @@ database_uri = %(tempdir)s/lib/proxy.db
...
@@ -104,13 +108,15 @@ database_uri = %(tempdir)s/lib/proxy.db
self
.
app_config
=
views
.
app
.
config
self
.
app_config
=
views
.
app
.
config
self
.
app
=
views
.
app
.
test_client
()
self
.
app
=
views
.
app
.
test_client
()
def
add_free_partition
(
self
,
partition_amount
):
def
add_free_partition
(
self
,
partition_amount
,
computer_id
=
None
):
"""
"""
Will simulate a slapformat first run
Will simulate a slapformat first run
and create "partition_amount" partitions
and create "partition_amount" partitions
"""
"""
if
not
computer_id
:
computer_id
=
self
.
computer_id
computer_dict
=
{
computer_dict
=
{
'reference'
:
self
.
computer_id
,
'reference'
:
computer_id
,
'address'
:
'123.456.789'
,
'address'
:
'123.456.789'
,
'netmask'
:
'fffffffff'
,
'netmask'
:
'fffffffff'
,
'partition_list'
:
[],
'partition_list'
:
[],
...
@@ -118,7 +124,11 @@ database_uri = %(tempdir)s/lib/proxy.db
...
@@ -118,7 +124,11 @@ database_uri = %(tempdir)s/lib/proxy.db
for
i
in
range
(
partition_amount
):
for
i
in
range
(
partition_amount
):
partition_example
=
{
partition_example
=
{
'reference'
:
'slappart%s'
%
i
,
'reference'
:
'slappart%s'
%
i
,
'address_list'
:
[],
'address_list'
:
[
{
'addr'
:
'1.2.3.4'
,
'netmask'
:
'255.255.255.255'
},
{
'addr'
:
'4.3.2.1'
,
'netmask'
:
'255.255.255.255'
}
],
'tap'
:
{
'name'
:
'tap0'
},
}
}
computer_dict
[
'partition_list'
].
append
(
partition_example
)
computer_dict
[
'partition_list'
].
append
(
partition_example
)
...
@@ -126,14 +136,16 @@ database_uri = %(tempdir)s/lib/proxy.db
...
@@ -126,14 +136,16 @@ database_uri = %(tempdir)s/lib/proxy.db
'computer_id'
:
self
.
computer_id
,
'computer_id'
:
self
.
computer_id
,
'xml'
:
xml_marshaller
.
xml_marshaller
.
dumps
(
computer_dict
),
'xml'
:
xml_marshaller
.
xml_marshaller
.
dumps
(
computer_dict
),
}
}
self
.
app
.
post
(
'/loadComputerConfigurationFromXML'
,
rv
=
self
.
app
.
post
(
'/loadComputerConfigurationFromXML'
,
data
=
request_dict
)
data
=
request_dict
)
self
.
assertEqual
(
rv
.
_status_code
,
200
)
def
tearDown
(
self
):
def
tearDown
(
self
):
"""
"""
Remove files generated for test
Remove files generated for test
"""
"""
shutil
.
rmtree
(
self
.
_tempdir
,
True
)
shutil
.
rmtree
(
self
.
_tempdir
,
True
)
views
.
is_schema_already_executed
=
False
class
TestInformation
(
BasicMixin
,
unittest
.
TestCase
):
class
TestInformation
(
BasicMixin
,
unittest
.
TestCase
):
...
@@ -243,18 +255,16 @@ class TestInformation(BasicMixin, unittest.TestCase):
...
@@ -243,18 +255,16 @@ class TestInformation(BasicMixin, unittest.TestCase):
)
)
class
MasterMixin
(
BasicMixin
):
class
MasterMixin
(
BasicMixin
,
unittest
.
TestCase
):
"""
"""
Define advanced tool for test proxy simulating behavior slap library tools
Define advanced tool for test proxy simulating behavior slap library tools
"""
"""
def
_requestComputerPartition
(
self
,
software_release
,
software_type
,
partition_reference
,
def
request
(
self
,
software_release
,
software_type
,
partition_reference
,
partition_id
,
partition_id
,
shared
=
False
,
partition_parameter_kw
=
None
,
filter_kw
=
None
,
shared
=
False
,
partition_parameter_kw
=
None
,
filter_kw
=
None
,
state
=
None
):
state
=
None
):
"""
"""
Simulate a request with above parameters
Check parameters, call requestComputerPartition server method and return result
Return response by server (a computer partition or an error)
"""
"""
if
partition_parameter_kw
is
None
:
if
partition_parameter_kw
is
None
:
partition_parameter_kw
=
{}
partition_parameter_kw
=
{}
...
@@ -276,25 +286,33 @@ class MasterMixin(BasicMixin):
...
@@ -276,25 +286,33 @@ class MasterMixin(BasicMixin):
'filter_xml'
:
xml_marshaller
.
xml_marshaller
.
dumps
(
filter_kw
),
'filter_xml'
:
xml_marshaller
.
xml_marshaller
.
dumps
(
filter_kw
),
'state'
:
xml_marshaller
.
xml_marshaller
.
dumps
(
state
),
'state'
:
xml_marshaller
.
xml_marshaller
.
dumps
(
state
),
}
}
rv
=
self
.
app
.
post
(
'/requestComputerPartition'
,
return
self
.
app
.
post
(
'/requestComputerPartition'
,
data
=
request_dict
)
data
=
request_dict
)
def
request
(
self
,
*
args
,
**
kwargs
):
"""
Simulate a request with above parameters
Return response by server (a computer partition or an error)
"""
rv
=
self
.
_requestComputerPartition
(
*
args
,
**
kwargs
)
self
.
assertEqual
(
rv
.
_status_code
,
200
)
xml
=
rv
.
data
xml
=
rv
.
data
try
:
software_instance
=
xml_marshaller
.
xml_marshaller
.
loads
(
xml
)
software_instance
=
xml_marshaller
.
xml_marshaller
.
loads
(
xml
)
except
:
raise
WrongFormat
(
"Could not be parsed by xml_marshaller"
)
computer_partition
=
slapos
.
slap
.
ComputerPartition
(
computer_partition
=
slapos
.
slap
.
ComputerPartition
(
software_instance
.
slap_computer_id
,
software_instance
.
slap_computer_id
,
software_instance
.
slap_computer_partition_id
)
software_instance
.
slap_computer_partition_id
)
if
shared
:
computer_partition
.
_synced
=
True
computer_partition
.
__dict__
.
update
(
software_instance
.
__dict__
)
computer_partition
.
_connection_dict
=
getattr
(
software_instance
,
'_connection_dict'
,
None
)
computer_partition
.
_parameter_dict
=
getattr
(
software_instance
,
'_parameter_dict'
,
None
)
return
computer_partition
return
computer_partition
def
supply
(
self
,
url
,
computer_id
=
None
,
state
=
''
):
if
not
computer_id
:
computer_id
=
self
.
computer_id
request_dict
=
{
'url'
:
url
,
'computer_id'
:
computer_id
,
'state'
:
state
}
rv
=
self
.
app
.
post
(
'/supplySupply'
,
data
=
request_dict
)
# XXX return a Software Release
def
setConnectionDict
(
self
,
partition_id
,
def
setConnectionDict
(
self
,
partition_id
,
connection_dict
,
slave_reference
=
None
):
connection_dict
,
slave_reference
=
None
):
self
.
app
.
post
(
'/setComputerPartitionConnectionXml'
,
data
=
{
self
.
app
.
post
(
'/setComputerPartitionConnectionXml'
,
data
=
{
...
@@ -314,10 +332,20 @@ class MasterMixin(BasicMixin):
...
@@ -314,10 +332,20 @@ class MasterMixin(BasicMixin):
return
instance
return
instance
class
TestRequest
(
MasterMixin
,
unittest
.
TestCase
):
class
TestRequest
(
MasterMixin
):
"""
"""
Set of tests for requests
Set of tests for requests
"""
"""
def
test_request_consistent_parameters
(
self
):
"""
Check that all different parameters related to requests (like instance_guid, state) are set and consistent
"""
self
.
add_free_partition
(
1
)
partition
=
self
.
request
(
'http://sr//'
,
None
,
'MyFirstInstance'
,
'slappart0'
)
self
.
assertEqual
(
partition
.
getState
(),
'started'
)
self
.
assertEqual
(
partition
.
getInstanceGuid
(),
'computer-slappart0'
)
def
test_two_request_one_partition_free
(
self
):
def
test_two_request_one_partition_free
(
self
):
"""
"""
Since slapproxy does not implement scope, providing two partition_id
Since slapproxy does not implement scope, providing two partition_id
...
@@ -325,10 +353,10 @@ class TestRequest(MasterMixin, unittest.TestCase):
...
@@ -325,10 +353,10 @@ class TestRequest(MasterMixin, unittest.TestCase):
"""
"""
self
.
add_free_partition
(
1
)
self
.
add_free_partition
(
1
)
self
.
assertIsInstance
(
self
.
request
(
'http://sr//'
,
None
,
self
.
assertIsInstance
(
self
.
request
(
'http://sr//'
,
None
,
'M
aria
'
,
'slappart2'
),
'M
yFirstInstance
'
,
'slappart2'
),
slapos
.
slap
.
ComputerPartition
)
slapos
.
slap
.
ComputerPartition
)
self
.
assertIsInstance
(
self
.
request
(
'http://sr//'
,
None
,
self
.
assertIsInstance
(
self
.
request
(
'http://sr//'
,
None
,
'M
aria
'
,
'slappart3'
),
'M
yFirstInstance
'
,
'slappart3'
),
slapos
.
slap
.
ComputerPartition
)
slapos
.
slap
.
ComputerPartition
)
def
test_two_request_two_partition_free
(
self
):
def
test_two_request_two_partition_free
(
self
):
...
@@ -338,10 +366,10 @@ class TestRequest(MasterMixin, unittest.TestCase):
...
@@ -338,10 +366,10 @@ class TestRequest(MasterMixin, unittest.TestCase):
"""
"""
self
.
add_free_partition
(
2
)
self
.
add_free_partition
(
2
)
self
.
assertIsInstance
(
self
.
request
(
'http://sr//'
,
None
,
self
.
assertIsInstance
(
self
.
request
(
'http://sr//'
,
None
,
'M
aria
'
,
'slappart2'
),
'M
yFirstInstance
'
,
'slappart2'
),
slapos
.
slap
.
ComputerPartition
)
slapos
.
slap
.
ComputerPartition
)
self
.
assertIsInstance
(
self
.
request
(
'http://sr//'
,
None
,
self
.
assertIsInstance
(
self
.
request
(
'http://sr//'
,
None
,
'M
aria
'
,
'slappart3'
),
'M
yFirstInstance
'
,
'slappart3'
),
slapos
.
slap
.
ComputerPartition
)
slapos
.
slap
.
ComputerPartition
)
def
test_two_same_request_from_one_partition
(
self
):
def
test_two_same_request_from_one_partition
(
self
):
...
@@ -350,8 +378,8 @@ class TestRequest(MasterMixin, unittest.TestCase):
...
@@ -350,8 +378,8 @@ class TestRequest(MasterMixin, unittest.TestCase):
"""
"""
self
.
add_free_partition
(
2
)
self
.
add_free_partition
(
2
)
self
.
assertEqual
(
self
.
assertEqual
(
self
.
request
(
'http://sr//'
,
None
,
'M
aria
'
,
'slappart2'
).
__dict__
,
self
.
request
(
'http://sr//'
,
None
,
'M
yFirstInstance
'
,
'slappart2'
).
__dict__
,
self
.
request
(
'http://sr//'
,
None
,
'M
aria
'
,
'slappart2'
).
__dict__
)
self
.
request
(
'http://sr//'
,
None
,
'M
yFirstInstance
'
,
'slappart2'
).
__dict__
)
def
test_two_requests_with_different_parameters_but_same_reference
(
self
):
def
test_two_requests_with_different_parameters_but_same_reference
(
self
):
"""
"""
...
@@ -362,18 +390,18 @@ class TestRequest(MasterMixin, unittest.TestCase):
...
@@ -362,18 +390,18 @@ class TestRequest(MasterMixin, unittest.TestCase):
wanted_domain1
=
'fou.org'
wanted_domain1
=
'fou.org'
wanted_domain2
=
'carzy.org'
wanted_domain2
=
'carzy.org'
request1
=
self
.
request
(
'http://sr//'
,
None
,
'M
aria
'
,
'slappart2'
,
request1
=
self
.
request
(
'http://sr//'
,
None
,
'M
yFirstInstance
'
,
'slappart2'
,
partition_parameter_kw
=
{
'domain'
:
wanted_domain1
})
partition_parameter_kw
=
{
'domain'
:
wanted_domain1
})
request1_dict
=
request1
.
__dict__
request1_dict
=
request1
.
__dict__
requested_result1
=
self
.
getPartitionInformation
(
requested_result1
=
self
.
getPartitionInformation
(
request1_dict
[
'_partition_id'
])
request1_dict
[
'_partition_id'
])
request2
=
self
.
request
(
'http://sr1//'
,
'Papa'
,
'M
aria
'
,
'slappart2'
,
request2
=
self
.
request
(
'http://sr1//'
,
'Papa'
,
'M
yFirstInstance
'
,
'slappart2'
,
partition_parameter_kw
=
{
'domain'
:
wanted_domain2
})
partition_parameter_kw
=
{
'domain'
:
wanted_domain2
})
request2_dict
=
request2
.
__dict__
request2_dict
=
request2
.
__dict__
requested_result2
=
self
.
getPartitionInformation
(
requested_result2
=
self
.
getPartitionInformation
(
request2_dict
[
'_partition_id'
])
request2_dict
[
'_partition_id'
])
# Test we received same partition
# Test we received same partition
for
key
in
request1_dict
:
for
key
in
[
'_partition_id'
,
'_computer_id'
]
:
self
.
assertEqual
(
request1_dict
[
key
],
request2_dict
[
key
])
self
.
assertEqual
(
request1_dict
[
key
],
request2_dict
[
key
])
# Test that only parameters changed
# Test that only parameters changed
for
key
in
requested_result2
.
__dict__
:
for
key
in
requested_result2
.
__dict__
:
...
@@ -397,8 +425,8 @@ class TestRequest(MasterMixin, unittest.TestCase):
...
@@ -397,8 +425,8 @@ class TestRequest(MasterMixin, unittest.TestCase):
"""
"""
self
.
add_free_partition
(
2
)
self
.
add_free_partition
(
2
)
self
.
assertEqual
(
self
.
assertEqual
(
self
.
request
(
'http://sr//'
,
None
,
'M
aria
'
,
'slappart2'
).
__dict__
,
self
.
request
(
'http://sr//'
,
None
,
'M
yFirstInstance
'
,
'slappart2'
).
__dict__
,
self
.
request
(
'http://sr//'
,
None
,
'M
aria
'
,
'slappart3'
).
__dict__
)
self
.
request
(
'http://sr//'
,
None
,
'M
yFirstInstance
'
,
'slappart3'
).
__dict__
)
def
test_two_different_request_from_one_partition
(
self
):
def
test_two_different_request_from_one_partition
(
self
):
"""
"""
...
@@ -407,16 +435,21 @@ class TestRequest(MasterMixin, unittest.TestCase):
...
@@ -407,16 +435,21 @@ class TestRequest(MasterMixin, unittest.TestCase):
"""
"""
self
.
add_free_partition
(
2
)
self
.
add_free_partition
(
2
)
self
.
assertNotEqual
(
self
.
assertNotEqual
(
self
.
request
(
'http://sr//'
,
None
,
'M
aria
'
,
'slappart2'
).
__dict__
,
self
.
request
(
'http://sr//'
,
None
,
'M
yFirstInstance
'
,
'slappart2'
).
__dict__
,
self
.
request
(
'http://sr//'
,
None
,
'frontend'
,
'slappart2'
).
__dict__
)
self
.
request
(
'http://sr//'
,
None
,
'frontend'
,
'slappart2'
).
__dict__
)
class
TestSlaveRequest
(
MasterMixin
):
"""
Test requests related to slave instances.
"""
def
test_slave_request_no_corresponding_partition
(
self
):
def
test_slave_request_no_corresponding_partition
(
self
):
"""
"""
Slave instance request will fail if no corresponding are found
Slave instance request will fail if no corresponding are found
"""
"""
self
.
add_free_partition
(
2
)
self
.
add_free_partition
(
2
)
with
self
.
assertRaises
(
WrongFormat
):
rv
=
self
.
_requestComputerPartition
(
'http://sr//'
,
None
,
'MyFirstInstance'
,
'slappart2'
,
shared
=
True
)
self
.
request
(
'http://sr//'
,
None
,
'Maria'
,
'slappart2'
,
shared
=
True
)
self
.
assertEqual
(
rv
.
_status_code
,
404
)
def
test_slave_request_set_parameters
(
self
):
def
test_slave_request_set_parameters
(
self
):
"""
"""
...
@@ -429,10 +462,10 @@ class TestRequest(MasterMixin, unittest.TestCase):
...
@@ -429,10 +462,10 @@ class TestRequest(MasterMixin, unittest.TestCase):
self
.
add_free_partition
(
6
)
self
.
add_free_partition
(
6
)
# Provide partition
# Provide partition
master_partition_id
=
self
.
request
(
'http://sr//'
,
None
,
master_partition_id
=
self
.
request
(
'http://sr//'
,
None
,
'M
aria
'
,
'slappart4'
).
_partition_id
'M
yFirstInstance
'
,
'slappart4'
).
_partition_id
# First request of slave instance
# First request of slave instance
wanted_domain
=
'fou.org'
wanted_domain
=
'fou.org'
self
.
request
(
'http://sr//'
,
None
,
'M
aria
'
,
'slappart2'
,
shared
=
True
,
self
.
request
(
'http://sr//'
,
None
,
'M
yFirstInstance
'
,
'slappart2'
,
shared
=
True
,
partition_parameter_kw
=
{
'domain'
:
wanted_domain
})
partition_parameter_kw
=
{
'domain'
:
wanted_domain
})
# Get updated information for master partition
# Get updated information for master partition
master_partition
=
self
.
getPartitionInformation
(
master_partition_id
)
master_partition
=
self
.
getPartitionInformation
(
master_partition_id
)
...
@@ -440,6 +473,17 @@ class TestRequest(MasterMixin, unittest.TestCase):
...
@@ -440,6 +473,17 @@ class TestRequest(MasterMixin, unittest.TestCase):
our_slave
=
master_partition
.
_parameter_dict
[
'slave_instance_list'
][
0
]
our_slave
=
master_partition
.
_parameter_dict
[
'slave_instance_list'
][
0
]
self
.
assertEqual
(
our_slave
.
get
(
'domain'
),
wanted_domain
)
self
.
assertEqual
(
our_slave
.
get
(
'domain'
),
wanted_domain
)
def
test_master_instance_with_no_slave
(
self
):
"""
Test that a master instance with no requested slave
has an empty slave_instance_list parameter.
"""
self
.
add_free_partition
(
6
)
# Provide partition
master_partition_id
=
self
.
request
(
'http://sr//'
,
None
,
'MyMasterInstance'
,
'slappart4'
).
_partition_id
master_partition
=
self
.
getPartitionInformation
(
master_partition_id
)
self
.
assertEqual
(
len
(
master_partition
.
_parameter_dict
[
'slave_instance_list'
]),
0
)
def
test_slave_request_set_parameters_are_updated
(
self
):
def
test_slave_request_set_parameters_are_updated
(
self
):
"""
"""
Parameters sent in slave request must be put in slave master
Parameters sent in slave request must be put in slave master
...
@@ -454,10 +498,10 @@ class TestRequest(MasterMixin, unittest.TestCase):
...
@@ -454,10 +498,10 @@ class TestRequest(MasterMixin, unittest.TestCase):
self
.
add_free_partition
(
6
)
self
.
add_free_partition
(
6
)
# Provide partition
# Provide partition
master_partition_id
=
self
.
request
(
'http://sr//'
,
None
,
master_partition_id
=
self
.
request
(
'http://sr//'
,
None
,
'M
aria
'
,
'slappart4'
).
_partition_id
'M
yFirstInstance
'
,
'slappart4'
).
_partition_id
# First request of slave instance
# First request of slave instance
wanted_domain_1
=
'crazy.org'
wanted_domain_1
=
'crazy.org'
self
.
request
(
'http://sr//'
,
None
,
'M
aria
'
,
'slappart2'
,
shared
=
True
,
self
.
request
(
'http://sr//'
,
None
,
'M
yFirstInstance
'
,
'slappart2'
,
shared
=
True
,
partition_parameter_kw
=
{
'domain'
:
wanted_domain_1
})
partition_parameter_kw
=
{
'domain'
:
wanted_domain_1
})
# Get updated information for master partition
# Get updated information for master partition
master_partition
=
self
.
getPartitionInformation
(
master_partition_id
)
master_partition
=
self
.
getPartitionInformation
(
master_partition_id
)
...
@@ -466,7 +510,7 @@ class TestRequest(MasterMixin, unittest.TestCase):
...
@@ -466,7 +510,7 @@ class TestRequest(MasterMixin, unittest.TestCase):
# Second request of slave instance
# Second request of slave instance
wanted_domain_2
=
'maluco.org'
wanted_domain_2
=
'maluco.org'
self
.
request
(
'http://sr//'
,
None
,
'M
aria
'
,
'slappart2'
,
shared
=
True
,
self
.
request
(
'http://sr//'
,
None
,
'M
yFirstInstance
'
,
'slappart2'
,
shared
=
True
,
partition_parameter_kw
=
{
'domain'
:
wanted_domain_2
})
partition_parameter_kw
=
{
'domain'
:
wanted_domain_2
})
# Get updated information for master partition
# Get updated information for master partition
master_partition
=
self
.
getPartitionInformation
(
master_partition_id
)
master_partition
=
self
.
getPartitionInformation
(
master_partition_id
)
...
@@ -475,6 +519,29 @@ class TestRequest(MasterMixin, unittest.TestCase):
...
@@ -475,6 +519,29 @@ class TestRequest(MasterMixin, unittest.TestCase):
self
.
assertNotEqual
(
our_slave
.
get
(
'domain'
),
wanted_domain_1
)
self
.
assertNotEqual
(
our_slave
.
get
(
'domain'
),
wanted_domain_1
)
self
.
assertEqual
(
our_slave
.
get
(
'domain'
),
wanted_domain_2
)
self
.
assertEqual
(
our_slave
.
get
(
'domain'
),
wanted_domain_2
)
def
test_slave_request_set_connection_parameters
(
self
):
"""
Parameters set in slave instance by master instance must be put in slave instance connection parameters.
1. We request a slave instance
2. We set connection parameters for this slave instance
2. We check parameter is present when we do request() for the slave.
"""
self
.
add_free_partition
(
6
)
# Provide partition
master_partition_id
=
self
.
request
(
'http://sr//'
,
None
,
'MyMasterInstance'
,
'slappart4'
).
_partition_id
# First request of slave instance
self
.
request
(
'http://sr//'
,
None
,
'MySlaveInstance'
,
'slappart2'
,
shared
=
True
)
# Set connection parameter
master_partition
=
self
.
getPartitionInformation
(
master_partition_id
)
# XXX change slave reference to be compatible with multiple nodes
self
.
setConnectionDict
(
partition_id
=
master_partition
.
_partition_id
,
connection_dict
=
{
'foo'
:
'bar'
},
slave_reference
=
master_partition
.
_parameter_dict
[
'slave_instance_list'
][
0
][
'slave_reference'
])
# Get updated information for slave partition
slave_partition
=
self
.
request
(
'http://sr//'
,
None
,
'MySlaveInstance'
,
'slappart2'
,
shared
=
True
)
self
.
assertEqual
(
slave_partition
.
getConnectionParameter
(
'foo'
),
'bar'
)
def
test_slave_request_one_corresponding_partition
(
self
):
def
test_slave_request_one_corresponding_partition
(
self
):
"""
"""
Successfull request slave instance follow these steps:
Successfull request slave instance follow these steps:
...
@@ -489,9 +556,9 @@ class TestRequest(MasterMixin, unittest.TestCase):
...
@@ -489,9 +556,9 @@ class TestRequest(MasterMixin, unittest.TestCase):
self
.
add_free_partition
(
6
)
self
.
add_free_partition
(
6
)
# Provide partition
# Provide partition
master_partition_id
=
self
.
request
(
'http://sr//'
,
None
,
master_partition_id
=
self
.
request
(
'http://sr//'
,
None
,
'M
aria
'
,
'slappart4'
).
_partition_id
'M
yFirstInstance
'
,
'slappart4'
).
_partition_id
# First request of slave instance
# First request of slave instance
name
=
'M
aria
'
name
=
'M
yFirstInstance
'
requester
=
'slappart2'
requester
=
'slappart2'
our_slave
=
self
.
request
(
'http://sr//'
,
None
,
our_slave
=
self
.
request
(
'http://sr//'
,
None
,
name
,
requester
,
shared
=
True
)
name
,
requester
,
shared
=
True
)
...
@@ -510,3 +577,354 @@ class TestRequest(MasterMixin, unittest.TestCase):
...
@@ -510,3 +577,354 @@ class TestRequest(MasterMixin, unittest.TestCase):
name
,
requester
,
shared
=
True
)
name
,
requester
,
shared
=
True
)
self
.
assertIsInstance
(
our_slave
,
slapos
.
slap
.
ComputerPartition
)
self
.
assertIsInstance
(
our_slave
,
slapos
.
slap
.
ComputerPartition
)
self
.
assertEqual
(
slave_address
,
our_slave
.
_connection_dict
)
self
.
assertEqual
(
slave_address
,
our_slave
.
_connection_dict
)
class
TestMultiNodeSupport
(
MasterMixin
):
def
test_multi_node_support_different_software_release_list
(
self
):
"""
Test that two different registered computers have their own
Software Release list.
"""
self
.
add_free_partition
(
6
,
computer_id
=
'COMP-0'
)
self
.
add_free_partition
(
6
,
computer_id
=
'COMP-1'
)
software_release_1_url
=
'http://sr1'
software_release_2_url
=
'http://sr2'
software_release_3_url
=
'http://sr3'
self
.
supply
(
software_release_1_url
,
'COMP-0'
)
self
.
supply
(
software_release_2_url
,
'COMP-1'
)
self
.
supply
(
software_release_3_url
,
'COMP-0'
)
self
.
supply
(
software_release_3_url
,
'COMP-1'
)
computer_default
=
loads
(
self
.
app
.
get
(
'/getFullComputerInformation?computer_id=%s'
%
self
.
computer_id
).
data
)
computer_0
=
loads
(
self
.
app
.
get
(
'/getFullComputerInformation?computer_id=COMP-0'
).
data
)
computer_1
=
loads
(
self
.
app
.
get
(
'/getFullComputerInformation?computer_id=COMP-1'
).
data
)
self
.
assertEqual
(
len
(
computer_default
.
_software_release_list
),
0
)
self
.
assertEqual
(
len
(
computer_0
.
_software_release_list
),
2
)
self
.
assertEqual
(
len
(
computer_1
.
_software_release_list
),
2
)
self
.
assertEqual
(
computer_0
.
_software_release_list
[
0
].
_software_release
,
software_release_1_url
)
self
.
assertEqual
(
computer_0
.
_software_release_list
[
0
].
_computer_guid
,
'COMP-0'
)
self
.
assertEqual
(
computer_0
.
_software_release_list
[
1
].
_software_release
,
software_release_3_url
)
self
.
assertEqual
(
computer_0
.
_software_release_list
[
1
].
_computer_guid
,
'COMP-0'
)
self
.
assertEqual
(
computer_1
.
_software_release_list
[
0
].
_software_release
,
software_release_2_url
)
self
.
assertEqual
(
computer_1
.
_software_release_list
[
0
].
_computer_guid
,
'COMP-1'
)
self
.
assertEqual
(
computer_1
.
_software_release_list
[
1
].
_software_release
,
software_release_3_url
)
self
.
assertEqual
(
computer_1
.
_software_release_list
[
1
].
_computer_guid
,
'COMP-1'
)
def
test_multi_node_support_remove_software_release
(
self
):
"""
Test that removing a software from a Computer doesn't
affect other computer
"""
software_release_url
=
'http://sr'
self
.
add_free_partition
(
6
,
computer_id
=
'COMP-0'
)
self
.
add_free_partition
(
6
,
computer_id
=
'COMP-1'
)
self
.
supply
(
software_release_url
,
'COMP-0'
)
self
.
supply
(
software_release_url
,
'COMP-1'
)
self
.
supply
(
software_release_url
,
'COMP-0'
,
state
=
'destroyed'
)
computer_0
=
loads
(
self
.
app
.
get
(
'/getFullComputerInformation?computer_id=COMP-0'
).
data
)
computer_1
=
loads
(
self
.
app
.
get
(
'/getFullComputerInformation?computer_id=COMP-1'
).
data
)
self
.
assertEqual
(
len
(
computer_0
.
_software_release_list
),
0
)
self
.
assertEqual
(
len
(
computer_1
.
_software_release_list
),
1
)
self
.
assertEqual
(
computer_1
.
_software_release_list
[
0
].
_software_release
,
software_release_url
)
self
.
assertEqual
(
computer_1
.
_software_release_list
[
0
].
_computer_guid
,
'COMP-1'
)
def
test_multi_node_support_instance_default_computer
(
self
):
"""
Test that instance request behaves correctly with default computer
"""
software_release_url
=
'http://sr'
computer_0_id
=
'COMP-0'
computer_1_id
=
'COMP-1'
self
.
add_free_partition
(
6
,
computer_id
=
computer_0_id
)
self
.
add_free_partition
(
6
,
computer_id
=
computer_1_id
)
# Request without SLA -> goes to default computer only.
# It should fail if we didn't registered partitions for default computer
# (default computer is always registered)
rv
=
self
.
_requestComputerPartition
(
'http://sr//'
,
None
,
'MyFirstInstance'
,
'slappart2'
)
self
.
assertEqual
(
rv
.
_status_code
,
404
)
rv
=
self
.
_requestComputerPartition
(
'http://sr//'
,
None
,
'MyFirstInstance'
,
'slappart2'
,
filter_kw
=
{
'computer_guid'
:
self
.
computer_id
})
self
.
assertEqual
(
rv
.
_status_code
,
404
)
# Register default computer: deployment works
self
.
add_free_partition
(
1
)
self
.
request
(
'http://sr//'
,
None
,
'MyFirstInstance'
,
'slappart0'
)
computer_default
=
loads
(
self
.
app
.
get
(
'/getFullComputerInformation?computer_id=%s'
%
self
.
computer_id
).
data
)
self
.
assertEqual
(
len
(
computer_default
.
_software_release_list
),
0
)
# No free space on default computer: request without SLA fails
rv
=
self
.
_requestComputerPartition
(
'http://sr//'
,
None
,
'CanIHasPartition'
,
'slappart2'
,
filter_kw
=
{
'computer_guid'
:
self
.
computer_id
})
self
.
assertEqual
(
rv
.
_status_code
,
404
)
def
test_multi_node_support_instance
(
self
):
"""
Test that instance request behaves correctly with several
registered computers
"""
software_release_url
=
'http://sr'
computer_0_id
=
'COMP-0'
computer_1_id
=
'COMP-1'
software_release_1
=
'http://sr//'
software_release_2
=
'http://othersr//'
self
.
add_free_partition
(
2
,
computer_id
=
computer_1_id
)
# Deploy to first non-default computer using SLA
# It should fail since computer is not registered
rv
=
self
.
_requestComputerPartition
(
software_release_1
,
None
,
'MyFirstInstance'
,
'slappart2'
,
filter_kw
=
{
'computer_guid'
:
computer_0_id
})
self
.
assertEqual
(
rv
.
_status_code
,
404
)
self
.
add_free_partition
(
2
,
computer_id
=
computer_0_id
)
# Deploy to first non-default computer using SLA
partition
=
self
.
request
(
software_release_1
,
None
,
'MyFirstInstance'
,
'slappart0'
,
filter_kw
=
{
'computer_guid'
:
computer_0_id
})
self
.
assertEqual
(
partition
.
getState
(),
'started'
)
self
.
assertEqual
(
partition
.
_partition_id
,
'slappart0'
)
self
.
assertEqual
(
partition
.
_computer_id
,
computer_0_id
)
# All other instances should be empty
computer_0
=
loads
(
self
.
app
.
get
(
'/getFullComputerInformation?computer_id=COMP-0'
).
data
)
computer_1
=
loads
(
self
.
app
.
get
(
'/getFullComputerInformation?computer_id=COMP-1'
).
data
)
self
.
assertEqual
(
computer_0
.
_computer_partition_list
[
0
].
_software_release_document
.
_software_release
,
software_release_1
)
self
.
assertTrue
(
computer_0
.
_computer_partition_list
[
1
].
_software_release_document
==
None
)
self
.
assertTrue
(
computer_1
.
_computer_partition_list
[
0
].
_software_release_document
==
None
)
self
.
assertTrue
(
computer_1
.
_computer_partition_list
[
1
].
_software_release_document
==
None
)
# Deploy to second non-default computer using SLA
partition
=
self
.
request
(
software_release_2
,
None
,
'MySecondInstance'
,
'slappart0'
,
filter_kw
=
{
'computer_guid'
:
computer_1_id
})
self
.
assertEqual
(
partition
.
getState
(),
'started'
)
self
.
assertEqual
(
partition
.
_partition_id
,
'slappart0'
)
self
.
assertEqual
(
partition
.
_computer_id
,
computer_1_id
)
# The two remaining instances should be free, and MyfirstInstance should still be there
computer_0
=
loads
(
self
.
app
.
get
(
'/getFullComputerInformation?computer_id=COMP-0'
).
data
)
computer_1
=
loads
(
self
.
app
.
get
(
'/getFullComputerInformation?computer_id=COMP-1'
).
data
)
self
.
assertEqual
(
computer_0
.
_computer_partition_list
[
0
].
_software_release_document
.
_software_release
,
software_release_1
)
self
.
assertTrue
(
computer_0
.
_computer_partition_list
[
1
].
_software_release_document
==
None
)
self
.
assertEqual
(
computer_1
.
_computer_partition_list
[
0
].
_software_release_document
.
_software_release
,
software_release_2
)
self
.
assertTrue
(
computer_1
.
_computer_partition_list
[
1
].
_software_release_document
==
None
)
def
test_multi_node_support_change_instance_state
(
self
):
"""
Test that destroying an instance (i.e change state) from a Computer doesn't
affect other computer
"""
software_release_url
=
'http://sr'
computer_0_id
=
'COMP-0'
computer_1_id
=
'COMP-1'
self
.
add_free_partition
(
6
,
computer_id
=
computer_0_id
)
self
.
add_free_partition
(
6
,
computer_id
=
computer_1_id
)
partition_first
=
self
.
request
(
'http://sr//'
,
None
,
'MyFirstInstance'
,
'slappart0'
,
filter_kw
=
{
'computer_guid'
:
computer_0_id
})
partition_second
=
self
.
request
(
'http://sr//'
,
None
,
'MySecondInstance'
,
'slappart0'
,
filter_kw
=
{
'computer_guid'
:
computer_1_id
})
partition_first
=
self
.
request
(
'http://sr//'
,
None
,
'MyFirstInstance'
,
'slappart0'
,
filter_kw
=
{
'computer_guid'
:
computer_0_id
},
state
=
'stopped'
)
computer_0
=
loads
(
self
.
app
.
get
(
'/getFullComputerInformation?computer_id=COMP-0'
).
data
)
computer_1
=
loads
(
self
.
app
.
get
(
'/getFullComputerInformation?computer_id=COMP-1'
).
data
)
self
.
assertEqual
(
computer_0
.
_computer_partition_list
[
0
].
getState
(),
'stopped'
)
self
.
assertEqual
(
computer_0
.
_computer_partition_list
[
1
].
getState
(),
'destroyed'
)
self
.
assertEqual
(
computer_1
.
_computer_partition_list
[
0
].
getState
(),
'started'
)
self
.
assertEqual
(
computer_1
.
_computer_partition_list
[
1
].
getState
(),
'destroyed'
)
def
test_multi_node_support_same_reference
(
self
):
"""
Test that requesting an instance with same reference to two
different nodes behaves like master: once an instance is assigned to a node,
changing SLA will not change node.
"""
software_release_url
=
'http://sr'
computer_0_id
=
'COMP-0'
computer_1_id
=
'COMP-1'
self
.
add_free_partition
(
2
,
computer_id
=
computer_0_id
)
self
.
add_free_partition
(
2
,
computer_id
=
computer_1_id
)
partition
=
self
.
request
(
'http://sr//'
,
None
,
'MyFirstInstance'
,
'slappart0'
,
filter_kw
=
{
'computer_guid'
:
computer_0_id
})
partition
=
self
.
request
(
'http://sr//'
,
None
,
'MyFirstInstance'
,
'slappart0'
,
filter_kw
=
{
'computer_guid'
:
computer_1_id
})
self
.
assertEqual
(
partition
.
_computer_id
,
computer_0_id
)
computer_1
=
loads
(
self
.
app
.
get
(
'/getFullComputerInformation?computer_id=COMP-1'
).
data
)
self
.
assertTrue
(
computer_1
.
_computer_partition_list
[
0
].
_software_release_document
==
None
)
self
.
assertTrue
(
computer_1
.
_computer_partition_list
[
1
].
_software_release_document
==
None
)
def
test_multi_node_support_slave_instance
(
self
):
"""
Test that slave instances are correctly deployed if SLA is specified
but deployed only on default computer if not specified (i.e not deployed
if default computer doesn't have corresponding master instance).
"""
computer_0_id
=
'COMP-0'
computer_1_id
=
'COMP-1'
self
.
add_free_partition
(
2
,
computer_id
=
computer_0_id
)
self
.
add_free_partition
(
2
,
computer_id
=
computer_1_id
)
self
.
add_free_partition
(
2
)
self
.
request
(
'http://sr2//'
,
None
,
'MyFirstInstance'
,
'slappart0'
,
filter_kw
=
{
'computer_guid'
:
computer_0_id
})
self
.
request
(
'http://sr//'
,
None
,
'MyOtherInstance'
,
'slappart0'
,
filter_kw
=
{
'computer_guid'
:
computer_1_id
})
# Request slave without SLA: will fail
rv
=
self
.
_requestComputerPartition
(
'http://sr//'
,
None
,
'MySlaveInstance'
,
'slappart2'
,
shared
=
True
)
self
.
assertEqual
(
rv
.
_status_code
,
404
)
# Request slave with SLA on incorrect computer: will fail
rv
=
self
.
_requestComputerPartition
(
'http://sr//'
,
None
,
'MySlaveInstance'
,
'slappart2'
,
shared
=
True
,
filter_kw
=
{
'computer_guid'
:
computer_0_id
})
self
.
assertEqual
(
rv
.
_status_code
,
404
)
# Request computer on correct computer: will succeed
partition
=
self
.
request
(
'http://sr//'
,
None
,
'MySlaveInstance'
,
'slappart2'
,
shared
=
True
,
filter_kw
=
{
'computer_guid'
:
computer_1_id
})
self
.
assertEqual
(
partition
.
_computer_id
,
computer_1_id
)
def
test_multi_node_support_instance_guid
(
self
):
"""
Test that instance_guid support behaves correctly with multiple nodes.
Warning: proxy doesn't gives unique id of instance, but gives instead unique id
of partition.
"""
computer_0_id
=
'COMP-0'
computer_1_id
=
'COMP-1'
self
.
add_free_partition
(
2
,
computer_id
=
computer_0_id
)
self
.
add_free_partition
(
2
,
computer_id
=
computer_1_id
)
self
.
add_free_partition
(
2
)
partition_computer_0
=
self
.
request
(
'http://sr2//'
,
None
,
'MyFirstInstance'
,
'slappart0'
,
filter_kw
=
{
'computer_guid'
:
computer_0_id
})
partition_computer_1
=
self
.
request
(
'http://sr//'
,
None
,
'MyOtherInstance'
,
'slappart0'
,
filter_kw
=
{
'computer_guid'
:
computer_1_id
})
partition_computer_default
=
self
.
request
(
'http://sr//'
,
None
,
'MyThirdInstance'
,
'slappart0'
)
self
.
assertEqual
(
partition_computer_0
.
getInstanceGuid
(),
'COMP-0-slappart0'
)
self
.
assertEqual
(
partition_computer_1
.
getInstanceGuid
(),
'COMP-1-slappart0'
)
self
.
assertEqual
(
partition_computer_default
.
getInstanceGuid
(),
'computer-slappart0'
)
def
test_multi_node_support_getComputerInformation
(
self
):
"""
Test that computer information will not be given if computer is not registered.
Test that it still should work for the 'default' computer specified in slapos config
even if not yet registered.
Test that computer information is given if computer is registered.
"""
new_computer_id
=
'%s42'
%
self
.
computer_id
with
self
.
assertRaises
(
slapos
.
slap
.
NotFoundError
):
self
.
app
.
get
(
'/getComputerInformation?computer_id=%s42'
%
new_computer_id
)
try
:
self
.
app
.
get
(
'/getComputerInformation?computer_id=%s'
%
self
.
computer_id
)
except
slapos
.
slap
.
NotFoundError
:
self
.
fail
(
'Could not fetch informations for default computer.'
)
self
.
add_free_partition
(
1
,
computer_id
=
new_computer_id
)
try
:
self
.
app
.
get
(
'/getComputerInformation?computer_id=%s'
%
new_computer_id
)
except
slapos
.
slap
.
NotFoundError
:
self
.
fail
(
'Could not fetch informations for registered computer.'
)
class
TestMigrateVersion10To11
(
TestInformation
,
TestRequest
,
TestSlaveRequest
,
TestMultiNodeSupport
):
"""
Test that old database version are automatically migrated without failure
"""
def
setUp
(
self
):
super
(
TestMigrateVersion10To11
,
self
).
setUp
()
schema
=
pkg_resources
.
resource_stream
(
'slapos.tests.slapproxy'
,
'database_dump_version_10.sql'
)
schema
=
schema
.
read
()
%
dict
(
version
=
'11'
)
self
.
db
=
sqlite3
.
connect
(
self
.
proxy_db
)
self
.
db
.
cursor
().
executescript
(
schema
)
self
.
db
.
commit
()
def
test_automatic_migration
(
self
):
table_list
=
(
'software11'
,
'computer11'
,
'partition11'
,
'slave11'
,
'partition_network11'
)
for
table
in
table_list
:
self
.
assertRaises
(
sqlite3
.
OperationalError
,
self
.
db
.
execute
,
"SELECT name FROM computer11"
)
# Run a dummy request to cause migration
self
.
app
.
get
(
'/getComputerInformation?computer_id=computer'
)
# Check some partition parameters
self
.
assertEqual
(
loads
(
self
.
app
.
get
(
'/getComputerInformation?computer_id=computer'
).
data
).
_computer_partition_list
[
0
].
_parameter_dict
[
'slap_software_type'
],
'production'
)
# Lower level tests
computer_list
=
self
.
db
.
execute
(
"SELECT * FROM computer11"
).
fetchall
()
self
.
assertEqual
(
computer_list
,
[(
u'computer'
,
u'127.0.0.1'
,
u'255.255.255.255'
)]
)
software_list
=
self
.
db
.
execute
(
"SELECT * FROM software11"
).
fetchall
()
self
.
assertEqual
(
software_list
,
[(
u'/srv/slapgrid//srv//runner/project//slapos/software.cfg'
,
u'computer'
)]
)
partition_list
=
self
.
db
.
execute
(
"select * from partition11"
).
fetchall
()
self
.
assertEqual
(
partition_list
,
[(
u'slappart0'
,
u'computer'
,
u'busy'
,
u'/srv/slapgrid//srv//runner/project//slapos/software.cfg'
,
u'<?xml version=
\
'
1.0
\
'
encoding=
\
'
utf-8
\
'
?>
\
n
<instance>
\
n
<parameter id="json">{
\
n
"site-id": "erp5"
\
n
}
\
n
}</parameter>
\
n
</instance>
\
n
'
,
None
,
None
,
u'production'
,
u'slapos'
,
None
,
u'started'
),
(
u'slappart1'
,
u'computer'
,
u'busy'
,
u'/srv/slapgrid//srv//runner/project//slapos/software.cfg'
,
u"<?xml version='1.0' encoding='utf-8'?>
\
n
<instance/>
\
n
"
,
u'<?xml version=
\
'
1.0
\
'
encoding=
\
'
utf-8
\
'
?>
\
n
<instance>
\
n
<parameter id="url">mysql://127.0.0.1:45678/erp5</parameter>
\
n
</instance>
\
n
'
,
None
,
u'mariadb'
,
u'MariaDB DataBase'
,
u'slappart0'
,
u'started'
),
(
u'slappart2'
,
u'computer'
,
u'busy'
,
u'/srv/slapgrid//srv//runner/project//slapos/software.cfg'
,
u'<?xml version=
\
'
1.0
\
'
encoding=
\
'
utf-8
\
'
?>
\
n
<instance>
\
n
<parameter id="cloudooo-json"></parameter>
\
n
</instance>
\
n
'
,
u'<?xml version=
\
'
1.0
\
'
encoding=
\
'
utf-8
\
'
?>
\
n
<instance>
\
n
<parameter id="url">cloudooo://127.0.0.1:23000/</parameter>
\
n
</instance>
\
n
'
,
None
,
u'cloudooo'
,
u'Cloudooo'
,
u'slappart0'
,
u'started'
),
(
u'slappart3'
,
u'computer'
,
u'busy'
,
u'/srv/slapgrid//srv//runner/project//slapos/software.cfg'
,
u"<?xml version='1.0' encoding='utf-8'?>
\
n
<instance/>
\
n
"
,
u'<?xml version=
\
'
1.0
\
'
encoding=
\
'
utf-8
\
'
?>
\
n
<instance>
\
n
<parameter id="url">memcached://127.0.0.1:11000/</parameter>
\
n
</instance>
\
n
'
,
None
,
u'memcached'
,
u'Memcached'
,
u'slappart0'
,
u'started'
),
(
u'slappart4'
,
u'computer'
,
u'busy'
,
u'/srv/slapgrid//srv//runner/project//slapos/software.cfg'
,
u"<?xml version='1.0' encoding='utf-8'?>
\
n
<instance/>
\
n
"
,
u'<?xml version=
\
'
1.0
\
'
encoding=
\
'
utf-8
\
'
?>
\
n
<instance>
\
n
<parameter id="url">memcached://127.0.0.1:13301/</parameter>
\
n
</instance>
\
n
'
,
None
,
u'kumofs'
,
u'KumoFS'
,
u'slappart0'
,
u'started'
),
(
u'slappart5'
,
u'computer'
,
u'busy'
,
u'/srv/slapgrid//srv//runner/project//slapos/software.cfg'
,
u'<?xml version=
\
'
1.0
\
'
encoding=
\
'
utf-8
\
'
?>
\
n
<instance>
\
n
<parameter id="kumofs-url">memcached://127.0.0.1:13301/</parameter>
\
n
<parameter id="memcached-url">memcached://127.0.0.1:11000/</parameter>
\
n
<parameter id="cloudooo-url">cloudooo://127.0.0.1:23000/</parameter>
\
n
</instance>
\
n
'
,
u'<?xml version=
\
'
1.0
\
'
encoding=
\
'
utf-8
\
'
?>
\
n
<instance>
\
n
<parameter id="url">https://[fc00::1]:10001</parameter>
\
n
</instance>
\
n
'
,
None
,
u'tidstorage'
,
u'TidStorage'
,
u'slappart0'
,
u'started'
),
(
u'slappart6'
,
u'computer'
,
u'free'
,
None
,
None
,
None
,
None
,
None
,
None
,
None
,
u'started'
),
(
u'slappart7'
,
u'computer'
,
u'free'
,
None
,
None
,
None
,
None
,
None
,
None
,
None
,
u'started'
),
(
u'slappart8'
,
u'computer'
,
u'free'
,
None
,
None
,
None
,
None
,
None
,
None
,
None
,
u'started'
),
(
u'slappart9'
,
u'computer'
,
u'free'
,
None
,
None
,
None
,
None
,
None
,
None
,
None
,
u'started'
)]
)
slave_list
=
self
.
db
.
execute
(
"select * from slave11"
).
fetchall
()
self
.
assertEqual
(
slave_list
,
[]
)
partition_network_list
=
self
.
db
.
execute
(
"select * from partition_network11"
).
fetchall
()
self
.
assertEqual
(
partition_network_list
,
[(
u'slappart0'
,
u'computer'
,
u'slappart0'
,
u'127.0.0.1'
,
u'255.255.255.255'
),
(
u'slappart0'
,
u'computer'
,
u'slappart0'
,
u'fc00::1'
,
u'ffff:ffff:ffff::'
),
(
u'slappart1'
,
u'computer'
,
u'slappart1'
,
u'127.0.0.1'
,
u'255.255.255.255'
),
(
u'slappart1'
,
u'computer'
,
u'slappart1'
,
u'fc00::1'
,
u'ffff:ffff:ffff::'
),
(
u'slappart2'
,
u'computer'
,
u'slappart2'
,
u'127.0.0.1'
,
u'255.255.255.255'
),
(
u'slappart2'
,
u'computer'
,
u'slappart2'
,
u'fc00::1'
,
u'ffff:ffff:ffff::'
),
(
u'slappart3'
,
u'computer'
,
u'slappart3'
,
u'127.0.0.1'
,
u'255.255.255.255'
),
(
u'slappart3'
,
u'computer'
,
u'slappart3'
,
u'fc00::1'
,
u'ffff:ffff:ffff::'
),
(
u'slappart4'
,
u'computer'
,
u'slappart4'
,
u'127.0.0.1'
,
u'255.255.255.255'
),
(
u'slappart4'
,
u'computer'
,
u'slappart4'
,
u'fc00::1'
,
u'ffff:ffff:ffff::'
),
(
u'slappart5'
,
u'computer'
,
u'slappart5'
,
u'127.0.0.1'
,
u'255.255.255.255'
),
(
u'slappart5'
,
u'computer'
,
u'slappart5'
,
u'fc00::1'
,
u'ffff:ffff:ffff::'
),
(
u'slappart6'
,
u'computer'
,
u'slappart6'
,
u'127.0.0.1'
,
u'255.255.255.255'
),
(
u'slappart6'
,
u'computer'
,
u'slappart6'
,
u'fc00::1'
,
u'ffff:ffff:ffff::'
),
(
u'slappart7'
,
u'computer'
,
u'slappart7'
,
u'127.0.0.1'
,
u'255.255.255.255'
),
(
u'slappart7'
,
u'computer'
,
u'slappart7'
,
u'fc00::1'
,
u'ffff:ffff:ffff::'
),
(
u'slappart8'
,
u'computer'
,
u'slappart8'
,
u'127.0.0.1'
,
u'255.255.255.255'
),
(
u'slappart8'
,
u'computer'
,
u'slappart8'
,
u'fc00::1'
,
u'ffff:ffff:ffff::'
),
(
u'slappart9'
,
u'computer'
,
u'slappart9'
,
u'127.0.0.1'
,
u'255.255.255.255'
),
(
u'slappart9'
,
u'computer'
,
u'slappart9'
,
u'fc00::1'
,
u'ffff:ffff:ffff::'
)]
)
# Override several tests that needs an empty database
@
unittest
.
skip
(
"Not implemented"
)
def
test_multi_node_support_different_software_release_list
(
self
):
pass
@
unittest
.
skip
(
"Not implemented"
)
def
test_multi_node_support_instance_default_computer
(
self
):
pass
@
unittest
.
skip
(
"Not implemented"
)
def
test_multi_node_support_instance_guid
(
self
):
pass
@
unittest
.
skip
(
"Not implemented"
)
def
test_partition_are_empty
(
self
):
pass
@
unittest
.
skip
(
"Not implemented"
)
def
test_request_consistent_parameters
(
self
):
pass
slapos/tests/slapproxy/database_dump_version_10.sql
0 → 100644
View file @
42e72e67
-- Real world example of webrunner database running version 10 of proxy db.
PRAGMA
foreign_keys
=
OFF
;
BEGIN
TRANSACTION
;
CREATE
TABLE
software10
(
url
VARCHAR
(
255
)
UNIQUE
);
INSERT
INTO
"software10"
VALUES
(
'/srv/slapgrid//srv//runner/project//slapos/software.cfg'
);
CREATE
TABLE
computer10
(
address
VARCHAR
(
255
),
netmask
VARCHAR
(
255
),
CONSTRAINT
uniq
PRIMARY
KEY
(
address
,
netmask
));
INSERT
INTO
"computer10"
VALUES
(
'127.0.0.1'
,
'255.255.255.255'
);
CREATE
TABLE
partition10
(
reference
VARCHAR
(
255
)
UNIQUE
,
slap_state
VARCHAR
(
255
)
DEFAULT
'free'
,
software_release
VARCHAR
(
255
),
xml
TEXT
,
connection_xml
TEXT
,
slave_instance_list
TEXT
,
software_type
VARCHAR
(
255
),
partition_reference
VARCHAR
(
255
),
requested_by
VARCHAR
(
255
),
-- only used for debugging,
-- slapproxy does not support proper scope
requested_state
VARCHAR
(
255
)
NOT
NULL
DEFAULT
'started'
);
INSERT
INTO
"partition10"
VALUES
(
'slappart0'
,
'busy'
,
'/srv/slapgrid//srv//runner/project//slapos/software.cfg'
,
'<?xml version=
''
1.0
''
encoding=
''
utf-8
''
?>
<instance>
<parameter id="json">{
"site-id": "erp5"
}
}</parameter>
</instance>
'
,
NULL
,
NULL
,
'production'
,
'slapos'
,
NULL
,
'started'
);
INSERT
INTO
"partition10"
VALUES
(
'slappart1'
,
'busy'
,
'/srv/slapgrid//srv//runner/project//slapos/software.cfg'
,
'<?xml version=
''
1.0
''
encoding=
''
utf-8
''
?>
<instance/>
'
,
'<?xml version=
''
1.0
''
encoding=
''
utf-8
''
?>
<instance>
<parameter id="url">mysql://127.0.0.1:45678/erp5</parameter>
</instance>
'
,
NULL
,
'mariadb'
,
'MariaDB DataBase'
,
'slappart0'
,
'started'
);
INSERT
INTO
"partition10"
VALUES
(
'slappart2'
,
'busy'
,
'/srv/slapgrid//srv//runner/project//slapos/software.cfg'
,
'<?xml version=
''
1.0
''
encoding=
''
utf-8
''
?>
<instance>
<parameter id="cloudooo-json"></parameter>
</instance>
'
,
'<?xml version=
''
1.0
''
encoding=
''
utf-8
''
?>
<instance>
<parameter id="url">cloudooo://127.0.0.1:23000/</parameter>
</instance>
'
,
NULL
,
'cloudooo'
,
'Cloudooo'
,
'slappart0'
,
'started'
);
INSERT
INTO
"partition10"
VALUES
(
'slappart3'
,
'busy'
,
'/srv/slapgrid//srv//runner/project//slapos/software.cfg'
,
'<?xml version=
''
1.0
''
encoding=
''
utf-8
''
?>
<instance/>
'
,
'<?xml version=
''
1.0
''
encoding=
''
utf-8
''
?>
<instance>
<parameter id="url">memcached://127.0.0.1:11000/</parameter>
</instance>
'
,
NULL
,
'memcached'
,
'Memcached'
,
'slappart0'
,
'started'
);
INSERT
INTO
"partition10"
VALUES
(
'slappart4'
,
'busy'
,
'/srv/slapgrid//srv//runner/project//slapos/software.cfg'
,
'<?xml version=
''
1.0
''
encoding=
''
utf-8
''
?>
<instance/>
'
,
'<?xml version=
''
1.0
''
encoding=
''
utf-8
''
?>
<instance>
<parameter id="url">memcached://127.0.0.1:13301/</parameter>
</instance>
'
,
NULL
,
'kumofs'
,
'KumoFS'
,
'slappart0'
,
'started'
);
INSERT
INTO
"partition10"
VALUES
(
'slappart5'
,
'busy'
,
'/srv/slapgrid//srv//runner/project//slapos/software.cfg'
,
'<?xml version=
''
1.0
''
encoding=
''
utf-8
''
?>
<instance>
<parameter id="kumofs-url">memcached://127.0.0.1:13301/</parameter>
<parameter id="memcached-url">memcached://127.0.0.1:11000/</parameter>
<parameter id="cloudooo-url">cloudooo://127.0.0.1:23000/</parameter>
</instance>
'
,
'<?xml version=
''
1.0
''
encoding=
''
utf-8
''
?>
<instance>
<parameter id="url">https://[fc00::1]:10001</parameter>
</instance>
'
,
NULL
,
'tidstorage'
,
'TidStorage'
,
'slappart0'
,
'started'
);
INSERT
INTO
"partition10"
VALUES
(
'slappart6'
,
'free'
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
'started'
);
INSERT
INTO
"partition10"
VALUES
(
'slappart7'
,
'free'
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
'started'
);
INSERT
INTO
"partition10"
VALUES
(
'slappart8'
,
'free'
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
'started'
);
INSERT
INTO
"partition10"
VALUES
(
'slappart9'
,
'free'
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
'started'
);
CREATE
TABLE
slave10
(
reference
VARCHAR
(
255
)
UNIQUE
,
connection_xml
TEXT
,
hosted_by
VARCHAR
(
255
),
asked_by
VARCHAR
(
255
)
-- only used for debugging,
-- slapproxy does not support proper scope
);
CREATE
TABLE
partition_network10
(
partition_reference
VARCHAR
(
255
),
reference
VARCHAR
(
255
),
address
VARCHAR
(
255
),
netmask
VARCHAR
(
255
)
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart0'
,
'slappart0'
,
'127.0.0.1'
,
'255.255.255.255'
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart0'
,
'slappart0'
,
'fc00::1'
,
'ffff:ffff:ffff::'
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart1'
,
'slappart1'
,
'127.0.0.1'
,
'255.255.255.255'
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart1'
,
'slappart1'
,
'fc00::1'
,
'ffff:ffff:ffff::'
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart2'
,
'slappart2'
,
'127.0.0.1'
,
'255.255.255.255'
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart2'
,
'slappart2'
,
'fc00::1'
,
'ffff:ffff:ffff::'
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart3'
,
'slappart3'
,
'127.0.0.1'
,
'255.255.255.255'
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart3'
,
'slappart3'
,
'fc00::1'
,
'ffff:ffff:ffff::'
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart4'
,
'slappart4'
,
'127.0.0.1'
,
'255.255.255.255'
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart4'
,
'slappart4'
,
'fc00::1'
,
'ffff:ffff:ffff::'
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart5'
,
'slappart5'
,
'127.0.0.1'
,
'255.255.255.255'
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart5'
,
'slappart5'
,
'fc00::1'
,
'ffff:ffff:ffff::'
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart6'
,
'slappart6'
,
'127.0.0.1'
,
'255.255.255.255'
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart6'
,
'slappart6'
,
'fc00::1'
,
'ffff:ffff:ffff::'
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart7'
,
'slappart7'
,
'127.0.0.1'
,
'255.255.255.255'
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart7'
,
'slappart7'
,
'fc00::1'
,
'ffff:ffff:ffff::'
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart8'
,
'slappart8'
,
'127.0.0.1'
,
'255.255.255.255'
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart8'
,
'slappart8'
,
'fc00::1'
,
'ffff:ffff:ffff::'
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart9'
,
'slappart9'
,
'127.0.0.1'
,
'255.255.255.255'
);
INSERT
INTO
"partition_network10"
VALUES
(
'slappart9'
,
'slappart9'
,
'fc00::1'
,
'ffff:ffff:ffff::'
);
COMMIT
;
slapos/version.py
View file @
42e72e67
...
@@ -26,4 +26,4 @@
...
@@ -26,4 +26,4 @@
#
#
##############################################################################
##############################################################################
version
=
'1.
1.2
'
version
=
'1.
2.1
'
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment