Commit fa1a40dd authored by Xavier Thompson's avatar Xavier Thompson

Add capabilities to compute node partitions

See merge request nexedi/slapos.core!584
parents 4b9c54f0 981c5d4f
...@@ -88,6 +88,10 @@ for base_category in compute_node_base_category_list: ...@@ -88,6 +88,10 @@ for base_category in compute_node_base_category_list:
else: else:
query_kw["%s_uid" % base_category] = category.getUid() query_kw["%s_uid" % base_category] = category.getUid()
if 'capability' in filter_kw:
capability = filter_kw.pop('capability')
query_kw['subject'] = {'query': capability, 'key': 'ExactMatch'}
query_kw["capacity_scope_uid"] = portal.portal_categories.capacity_scope.open.getUid() query_kw["capacity_scope_uid"] = portal.portal_categories.capacity_scope.open.getUid()
if subscription_reference is not None and software_instance_portal_type != "Slave Instance": if subscription_reference is not None and software_instance_portal_type != "Slave Instance":
# Subscriptions uses a specific set of allocation scope # Subscriptions uses a specific set of allocation scope
......
...@@ -853,3 +853,71 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by S ...@@ -853,3 +853,71 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by S
@simulate('Person_isAllowedToAllocate', '*args, **kwargs', 'return True') @simulate('Person_isAllowedToAllocate', '*args, **kwargs', 'return True')
def test_allocation_storage_redundancy_sla(self): def test_allocation_storage_redundancy_sla(self):
return self.check_allocation_category_sla('storage_redundancy', 'dht', 'raid') return self.check_allocation_category_sla('storage_redundancy', 'dht', 'raid')
def check_allocation_capability(self, capability, bad_capability_list,
good_capability=None):
good_capability = good_capability or capability
self._makeTree()
self._makeComputeNode()
self.partition.edit(subject=capability)
self._installSoftware(self.compute_node,
self.software_instance.getUrlString())
self.assertEqual(None,
self.software_instance.getAggregate(portal_type='Compute Partition'))
for bad_capability in bad_capability_list:
self.software_instance.setSlaXml("""<?xml version='1.0' encoding='utf-8'?>
<instance>
<parameter id='capability'>%s</parameter>
</instance>""" % bad_capability)
self.software_instance.SoftwareInstance_tryToAllocatePartition()
try:
partition = self.software_instance.getAggregate(
portal_type='Compute Partition')
self.assertEqual(None, partition)
except AssertionError:
raise AssertionError("Allocated %s on %s with capability %s" % (
bad_capability, partition, capability))
self.software_instance.setSlaXml("""<?xml version='1.0' encoding='utf-8'?>
<instance>
<parameter id='capability'>%s</parameter>
</instance>""" % good_capability)
self.software_instance.SoftwareInstance_tryToAllocatePartition()
self.assertEqual(self.partition.getRelativeUrl(),
self.software_instance.getAggregate(portal_type='Compute Partition'))
@simulate('Person_isAllowedToAllocate', '*args, **kwargs', 'return True')
def test_allocation_capability(self):
valid_id = self.generateNewId()
capability = 'toto_' + valid_id
self.check_allocation_capability(capability, (
'tutu_' + self.generateNewId(),
't%to_' + valid_id,
'%_' + valid_id,
'%',
't_to_' + valid_id,
'__' + valid_id,
'_',
'.*_' + valid_id,
'.*',
))
@simulate('Person_isAllowedToAllocate', '*args, **kwargs', 'return True')
def test_allocation_capability_percent(self):
self.check_allocation_capability('%', ('_',))
@simulate('Person_isAllowedToAllocate', '*args, **kwargs', 'return True')
def test_allocation_capability_ipv6(self):
self.check_allocation_capability('fe80::1ff:fe23:4567:890a', ('fe80::1',))
@simulate('Person_isAllowedToAllocate', '*args, **kwargs', 'return True')
def test_allocation_capability_multiple(self):
self.check_allocation_capability('toto\ntata', ('titi',), 'toto')
self.check_allocation_capability('toto\ntata', ('titi',), 'tata')
...@@ -85,6 +85,11 @@ for send_partition in compute_node_dict['partition_list']: ...@@ -85,6 +85,11 @@ for send_partition in compute_node_dict['partition_list']:
partition.validate(comment="Reactivated by slapformat") partition.validate(comment="Reactivated by slapformat")
if partition.getReference() != send_partition['reference']: if partition.getReference() != send_partition['reference']:
partition.edit(reference=send_partition['reference']) partition.edit(reference=send_partition['reference'])
send_capability_list = send_partition.get('capability_list') or []
if partition.getSubjectList() != send_capability_list:
partition.edit(subject=send_capability_list)
network_interface = send_partition['tap']['name'] network_interface = send_partition['tap']['name']
compareAndUpdateAddressList(partition, send_partition['address_list'], {'network_interface': network_interface}) compareAndUpdateAddressList(partition, send_partition['address_list'], {'network_interface': network_interface})
tap_addr_list = [] tap_addr_list = []
......
...@@ -980,3 +980,90 @@ class TestSlapOSCoreComputeNodeUpdateFromDict(SlapOSTestCaseMixinWithAbort): ...@@ -980,3 +980,90 @@ class TestSlapOSCoreComputeNodeUpdateFromDict(SlapOSTestCaseMixinWithAbort):
self.assertEqual(partition.getValidationState(), 'invalidated') self.assertEqual(partition.getValidationState(), 'invalidated')
self.assertEqual(partition.getSlapState(), 'inactive') self.assertEqual(partition.getSlapState(), 'inactive')
self.assertEqual(partition.getId(), 'bar') self.assertEqual(partition.getId(), 'bar')
#############################################
# Compute Partition capabilities
#############################################
def test_CreateSinglePartitionWithCapability(self):
capability_list = ["CAPA-%s" % self.generateNewId()]
parameter_dict = {
'partition_list': [{
'reference': 'foo',
'address_list': [],
'tap': {'name': 'bar'},
'capability_list': capability_list,
}],
'address': 'a',
'netmask': 'b',
}
self.compute_node.ComputeNode_updateFromDict(parameter_dict)
partition_list = self.compute_node.contentValues(
portal_type='Compute Partition')
self.assertEqual(len(partition_list), 1)
partition = partition_list[0]
self.assertEqual(partition.getReference(), 'foo')
self.assertEqual(partition.getValidationState(), 'validated')
self.assertEqual(partition.getSlapState(), 'free')
self.assertEqual(partition.getSubjectList(), capability_list)
def test_UpdatePartitionCapability(self):
partition_dict = {
'reference': 'foo',
'address_list': [],
'tap': {'name': 'bar'},
}
parameter_dict = {
'partition_list': [partition_dict],
'address': 'a',
'netmask': 'b',
}
def check_Partition(subject_list):
partition_list = self.compute_node.contentValues(
portal_type='Compute Partition')
self.assertEqual(len(partition_list), 1)
partition = partition_list[0]
self.assertEqual(partition.getReference(), 'foo')
self.assertEqual(partition.getValidationState(), 'validated')
self.assertEqual(partition.getSlapState(), 'free')
self.assertEqual(partition.getSubjectList(), subject_list)
self.compute_node.ComputeNode_updateFromDict(parameter_dict)
check_Partition([])
capa1 = ["CAPA1-%s" % self.generateNewId()]
partition_dict['capability_list'] = capa1
self.compute_node.ComputeNode_updateFromDict(parameter_dict)
check_Partition(capa1)
capa2 = ["CAPA2-%s" % self.generateNewId()]
partition_dict['capability_list'] = capa2
self.compute_node.ComputeNode_updateFromDict(parameter_dict)
check_Partition(capa2)
capa = capa1 + capa2
partition_dict['capability_list'] = capa
self.compute_node.ComputeNode_updateFromDict(parameter_dict)
check_Partition(capa)
# Check order is maintained
capa = capa2 + capa1
partition_dict['capability_list'] = capa
self.compute_node.ComputeNode_updateFromDict(parameter_dict)
check_Partition(capa)
partition_dict['capability_list'] = []
self.compute_node.ComputeNode_updateFromDict(parameter_dict)
check_Partition([])
# Check duplicates are not removed
capa = capa2 + capa1 + capa2
partition_dict['capability_list'] = capa
self.compute_node.ComputeNode_updateFromDict(parameter_dict)
check_Partition(capa)
del partition_dict['capability_list']
self.compute_node.ComputeNode_updateFromDict(parameter_dict)
check_Partition([])
...@@ -6,12 +6,6 @@ ...@@ -6,12 +6,6 @@
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>default_reference</string> </key>
<value> <string>testSlapOSSlapToolComputeNodeUpdateFromDict</string> </value> <value> <string>testSlapOSSlapToolComputeNodeUpdateFromDict</string> </value>
...@@ -55,28 +49,13 @@ ...@@ -55,28 +49,13 @@
<item> <item>
<key> <string>workflow_history</string> </key> <key> <string>workflow_history</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI="> <record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="PersistentMapping" module="Persistence.mapping"/> <global name="PersistentMapping" module="Persistence.mapping"/>
</pickle> </pickle>
...@@ -89,7 +68,7 @@ ...@@ -89,7 +68,7 @@
<item> <item>
<key> <string>component_validation_workflow</string> </key> <key> <string>component_validation_workflow</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
...@@ -98,7 +77,7 @@ ...@@ -98,7 +77,7 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="4" aka="AAAAAAAAAAQ="> <record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle> </pickle>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment