Commit 09e73a8e by Simon János

added new resource types; changed tests accordingly

parent 553e5137
import copy
import json
import uuid
from socket import inet_aton
from enum import Enum
from oslo_config import cfg
from voluptuous import Schema, Invalid, MultipleInvalid, Any, ALLOW_EXTRA, PREVENT_EXTRA, re, Required, Optional, All, \
Range
from voluptuous import Schema, Invalid, MultipleInvalid, Any, ALLOW_EXTRA, PREVENT_EXTRA, re
from orchestrator.util.task_client import Tasks
class Resource(object):
......@@ -23,7 +27,7 @@ class Resource(object):
@classmethod
def __attributes_from_dict(cls, attributes):
cls.__validate_attributes(attributes, cls.__schema(extend=False))
attributes = copy.deepcopy(attributes)
attributes = attributes.copy()
attributes['id'] = attributes.get('id', Resource.__generate_random_id())
attributes['type'] = ResourceType.validate(attributes.get('type', cls))
return attributes
......@@ -37,17 +41,28 @@ class Resource(object):
@classmethod
def __schema(cls, resource_type=None, extend=False):
schema = Schema(schema={'id': cls.__id_validator, 'type': ResourceType.validate}, extra=ALLOW_EXTRA)
schema = Schema(schema={'id': cls._id_validator, 'type': ResourceType.validate}, extra=ALLOW_EXTRA)
if extend:
additional = resource_type.ADDITIONAL_SCHEMA if resource_type else cls.ADDITIONAL_SCHEMA
schema = schema.extend(additional, extra=PREVENT_EXTRA)
return schema
@staticmethod
def __id_validator(resource_id):
def _id_validator(resource_id):
if not re.compile('^[a-zA-Z0-9_-]{2,42}$').match(resource_id):
raise Invalid("'%s' is invalid" % resource_id)
@staticmethod
def _mac_validator(mac):
return re.match("[0-9a-f]{2}([-:])[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", mac.lower())
@staticmethod
def _ip_validator(ip_address):
try:
return inet_aton(ip_address)
except AttributeError:
return False
@property
def type(self):
return str(self._attributes['type'])
......@@ -92,7 +107,10 @@ class Resource(object):
def flatten(self, fqn=None, flat_leaves=True):
fqn = '%s.%s' % (fqn, self.id) if fqn else self.id
if flat_leaves:
return {'%s.%s' % (fqn, key): str(value) for key, value in self.items()}
leaves = {}
for key, value in self.items():
leaves['%s.%s' % (fqn, key)] = str(value) if isinstance(value, ResourceType) else value
return leaves
return {fqn: self}
@staticmethod
......@@ -101,10 +119,13 @@ class Resource(object):
return str(data)
return dict(data)
def deploy(self, name):
pass
class ResourceGroup(Resource):
ADDITIONAL_SCHEMA = {
'resources': Any(list, set, tuple)
Optional('resources'): Any(list, set, tuple)
}
def __init__(self, *_, **__):
......@@ -162,7 +183,53 @@ class ResourceGroup(Resource):
class Instance(Resource):
ADDITIONAL_SCHEMA = {
'number_of_cores': int
Required('cpu_count'): int,
Required('memory'): int
}
def deploy(self, name):
args = {
'name': name,
'vcpu': self.cpu_count,
'memory_max': self.memory
}
result = Tasks.send_task('vmdriver.create', args=[args])
return result
class Disk(Resource):
ADDITIONAL_SCHEMA = {
Required('size'): All(int, Range(min=1)),
Optional('base'): str
}
def deploy(self, name):
args = {
'dir': cfg.CONF.storage.datastore_root,
'name': name,
'format': 'qcow2',
'type': 'normal',
'size': self.size,
'base_name': self.base or None
}
task_name = 'storagedriver.snapshot' if self.base else 'storagedriver.create'
result = Tasks.send_task(task_name, args=[args])
return result
class DiskAttachment(Resource):
ADDITIONAL_SCHEMA = {
Required('instance_id'): Resource._id_validator,
Required('stack_id'): Resource._id_validator
}
class NetworkConnection(Resource):
ADDITIONAL_SCHEMA = {
Required('instance_id'): Resource._id_validator,
Required('mac'): Resource._mac_validator,
Required('vlan'): All(int, Range(min=1, max=4094)),
Required('ip_address'): Resource._ip_validator
}
......@@ -170,6 +237,9 @@ class ResourceType(Enum):
null = Resource
group = ResourceGroup
instance = Instance
disk = Disk
attachment = DiskAttachment
connection = NetworkConnection
@classmethod
def validate(cls, value):
......
......@@ -5,6 +5,10 @@ from falcon.testing import TestCase
from orchestrator.api import stacks
TEST_INSTANCE_ARGS = {
'cpu_count': 2,
'memory': 256 * 1000 * 1000
}
class StackTest(TestCase):
def setUp(self):
......@@ -30,7 +34,9 @@ class StackTest(TestCase):
'resources': [
{
'id': 'instance-1',
'type': 'instance'
'type': 'instance',
'cpu_count': 1,
'memory': 100
},
{
'id': 'level-1',
......@@ -38,11 +44,23 @@ class StackTest(TestCase):
'resources': [
{
'id': 'instance-2',
'type': 'instance'
'type': 'instance',
'cpu_count': 2,
'memory': 200
},
{
'id': 'instance-3',
'type': 'instance'
'type': 'instance',
'cpu_count': 3,
'memory': 300
},
{
'id': 'connection-1',
'type': 'connection',
'instance_id': 'instance-1',
'vlan': 42,
'mac': 'aa:bb:cc:dd:ee:ff',
'ip_address': '10.0.0.42'
}
]
}
......@@ -96,6 +114,7 @@ class StackTest(TestCase):
resource_id = 'new_resource'
group1 = {'id': stack_id, 'type': 'group', 'resources': []}
resource = {'id': resource_id, 'type': 'instance'}
resource.update(TEST_INSTANCE_ARGS)
group2 = {'id': stack_id, 'type': 'group', 'resources': [resource]}
expected_diff = {
'added': {
......@@ -117,6 +136,7 @@ class StackTest(TestCase):
# given
resource_id = 'some_resource'
resource = {'id': resource_id, 'type': 'instance'}
resource.update(TEST_INSTANCE_ARGS)
# when
self.simulate_post('/stacks', body=json.dumps(resource))
......@@ -132,7 +152,9 @@ class StackTest(TestCase):
def test_stacks_api_get_list(self):
# given
resource1 = {'id': 'some_resource', 'type': 'instance'}
resource1.update(TEST_INSTANCE_ARGS)
resource2 = {'id': 'some_other_resource', 'type': 'instance'}
resource2.update(TEST_INSTANCE_ARGS)
# when
self.simulate_post('/stacks', body=json.dumps(resource1))
......@@ -148,6 +170,7 @@ class StackTest(TestCase):
# given
resource_id = 'some_resource'
resource = {'id': resource_id, 'type': 'instance'}
resource.update(TEST_INSTANCE_ARGS)
# when
self.simulate_post('/stacks', body=json.dumps(resource))
......
......@@ -4,6 +4,11 @@ from unittest.case import TestCase
from orchestrator.model.resources import Resource, ResourceGroup, Instance, InvalidResourceException, ResourceType
TEST_INSTANCE_ARGS = {
'cpu_count': 2,
'memory': 256 * 1000 * 1000
}
class ResourceTest(TestCase):
def test_resource_without_args(self):
......@@ -16,7 +21,7 @@ class ResourceTest(TestCase):
expected_type = ResourceType.instance
# when
result = Resource(id=expected_id, type=expected_type)
result = Resource(id=expected_id, type=expected_type, **TEST_INSTANCE_ARGS)
# then
self.assertEqual(expected_id, result.id)
......@@ -25,6 +30,7 @@ class ResourceTest(TestCase):
def test_resource_from_dict(self):
# given
resource_dict = {'id': 'dummy_resource', 'type': 'instance'}
resource_dict.update(TEST_INSTANCE_ARGS)
# when
result = Resource(resource_dict)
......@@ -55,24 +61,27 @@ class ResourceTest(TestCase):
for invalid_id in invalid_ids:
with self.assertRaises(InvalidResourceException):
Instance(id=invalid_id)
Instance(id=invalid_id, **TEST_INSTANCE_ARGS)
self.assertIsInstance(Instance(id='valid_id'), Instance)
self.assertIsInstance(Instance(id='valid-id'), Instance)
self.assertIsInstance(Instance(id='VALID'), Instance)
self.assertIsInstance(Instance(id='123456'), Instance)
self.assertIsInstance(Instance(id='_id-42'), Instance)
self.assertIsInstance(Instance(id='valid_id', **TEST_INSTANCE_ARGS), Instance)
self.assertIsInstance(Instance(id='valid-id', **TEST_INSTANCE_ARGS), Instance)
self.assertIsInstance(Instance(id='VALID', **TEST_INSTANCE_ARGS), Instance)
self.assertIsInstance(Instance(id='123456', **TEST_INSTANCE_ARGS), Instance)
self.assertIsInstance(Instance(id='_id-42', **TEST_INSTANCE_ARGS), Instance)
def test_resource_type_validation(self):
self.assertTrue(ResourceType.validate('instance'))
self.assertTrue(ResourceType.validate(Instance))
self.assertTrue(ResourceType.validate(ResourceType.instance))
self.assertIsInstance(Resource(type='instance'), Instance)
self.assertIsInstance(Resource(type=Instance), Instance)
self.assertIsInstance(Resource(type=ResourceType.instance), Instance)
self.assertEqual(Instance(id='some_instance'), Resource(id='some_instance', type='instance'))
self.assertEqual(Instance(id='some_instance'), Resource(id='some_instance', type=Instance))
self.assertEqual(Instance(id='some_instance'), Resource(id='some_instance', type=ResourceType.instance))
self.assertIsInstance(Resource(type='instance', **TEST_INSTANCE_ARGS), Instance)
self.assertIsInstance(Resource(type=Instance, **TEST_INSTANCE_ARGS), Instance)
self.assertIsInstance(Resource(type=ResourceType.instance, **TEST_INSTANCE_ARGS), Instance)
self.assertEqual(Instance(id='some_instance', **TEST_INSTANCE_ARGS),
Resource(id='some_instance', type='instance', **TEST_INSTANCE_ARGS))
self.assertEqual(Instance(id='some_instance', **TEST_INSTANCE_ARGS),
Resource(id='some_instance', type=Instance, **TEST_INSTANCE_ARGS))
self.assertEqual(Instance(id='some_instance', **TEST_INSTANCE_ARGS),
Resource(id='some_instance', type=ResourceType.instance, **TEST_INSTANCE_ARGS))
def test_resource_type_invalid(self):
with self.assertRaises(ValueError):
......@@ -80,7 +89,7 @@ class ResourceTest(TestCase):
def test_resource_instance(self):
# when
instance = Instance()
instance = Instance(TEST_INSTANCE_ARGS)
# then
self.assertIsInstance(instance.id, str)
......@@ -89,10 +98,10 @@ class ResourceTest(TestCase):
def test_resource_equivalence(self):
# given
resource1 = Resource(id='some_resource', type=Instance)
resource2 = Resource(id='some_resource', type=Instance)
resource3 = Instance(id='some_resource')
resource4 = Resource(id='some_other_resource', type=Instance)
resource1 = Resource(id='some_resource', type=Instance, **TEST_INSTANCE_ARGS)
resource2 = Resource(id='some_resource', type=Instance, **TEST_INSTANCE_ARGS)
resource3 = Instance(id='some_resource', **TEST_INSTANCE_ARGS)
resource4 = Resource(id='some_other_resource', type=Instance, **TEST_INSTANCE_ARGS)
resource5 = Resource(id='some_resource', type=ResourceGroup)
# then
......@@ -107,10 +116,12 @@ class ResourceTest(TestCase):
# given
expected_json = '{"id": "some_resource", "type": "instance"}'
expected_dict = json.loads(expected_json)
expected_dict.update(TEST_INSTANCE_ARGS)
# when
resource = Resource(expected_dict)
resource_dict = json.loads(str(resource))
resource_dict.update(TEST_INSTANCE_ARGS)
# then
self.assertEqual(expected_dict, resource_dict)
......@@ -118,6 +129,7 @@ class ResourceTest(TestCase):
def test_resource_dict_representation(self):
# given
expected_dict = {'id': 'some_resource', 'type': ResourceType.instance}
expected_dict.update(TEST_INSTANCE_ARGS)
# when
resource = Resource(expected_dict)
......@@ -128,11 +140,12 @@ class ResourceTest(TestCase):
def test_resource_dynamic_type(self):
# when
resource = Resource(type='instance')
args = dict(type='instance', **TEST_INSTANCE_ARGS)
# then
self.__assert_is_instance(resource)
self.__assert_is_instance(Resource({'type': 'instance'}))
self.__assert_is_instance(Resource(args))
self.__assert_is_instance(Resource(**args))
self.__assert_is_instance(Instance(**args))
with self.assertRaises(InvalidResourceException):
Resource()
......@@ -152,8 +165,8 @@ class ResourceGroupTest(TestCase):
def test_resource_group_from_resources(self):
# given
resource1 = Instance(id='some_resource')
resource2 = Instance(id='some_other_resource')
resource1 = Instance(id='some_resource', **TEST_INSTANCE_ARGS)
resource2 = Instance(id='some_other_resource', **TEST_INSTANCE_ARGS)
# then
self.assertEqual([resource1], ResourceGroup(resources=[resource1]).resources)
......@@ -168,8 +181,8 @@ class ResourceGroupTest(TestCase):
def test_resource_group_from_dicts(self):
# given
dict1 = dict(id='some_resource', type=Instance)
dict2 = dict(id='some_other_resource', type=Instance)
dict1 = dict(id='some_resource', type=Instance, **TEST_INSTANCE_ARGS)
dict2 = dict(id='some_other_resource', type=Instance, **TEST_INSTANCE_ARGS)
expected1 = Instance(dict1)
expected2 = Instance(dict2)
......@@ -188,7 +201,7 @@ class ResourceGroupTest(TestCase):
'id': expected_group_id,
'type': 'group',
'resources': [
{'id': expected_resource_id, 'type': 'instance'}
dict(id=expected_resource_id, type='instance', **TEST_INSTANCE_ARGS)
]
}
......@@ -203,7 +216,7 @@ class ResourceGroupTest(TestCase):
def test_resource_group_add_resource(self):
# given
group = ResourceGroup()
resource = Instance()
resource = Instance(TEST_INSTANCE_ARGS)
# when
group.add(resource)
......@@ -214,7 +227,7 @@ class ResourceGroupTest(TestCase):
def test_resource_group_remove_resource(self):
# given
resource = Instance()
resource = Instance(TEST_INSTANCE_ARGS)
group = ResourceGroup()
group.add(resource)
......@@ -227,7 +240,7 @@ class ResourceGroupTest(TestCase):
def test_resource_group_duplicate_resource_id(self):
# given
group = ResourceGroup()
resource = Instance()
resource = Instance(TEST_INSTANCE_ARGS)
# then
with self.assertRaises(KeyError):
......@@ -238,7 +251,7 @@ class ResourceGroupTest(TestCase):
# given
group1 = ResourceGroup()
group2 = ResourceGroup()
resource = Instance()
resource = Instance(TEST_INSTANCE_ARGS)
# when
result_group1 = group1 + group2
......@@ -255,7 +268,9 @@ class ResourceGroupTest(TestCase):
def test_resource_group_iteration(self):
# when
group = ResourceGroup(resources=[Instance(), Instance(), Instance()])
group = ResourceGroup(resources=[Instance(TEST_INSTANCE_ARGS),
Instance(TEST_INSTANCE_ARGS),
Instance(TEST_INSTANCE_ARGS)])
# then
for index, resource in enumerate(group.resources):
......@@ -263,8 +278,8 @@ class ResourceGroupTest(TestCase):
def test_resource_group_equivalence(self):
# given
resource1 = Instance(id='some_resource')
resource2 = Instance(id='some_other_resource')
resource1 = Instance(id='some_resource', **TEST_INSTANCE_ARGS)
resource2 = Instance(id='some_other_resource', **TEST_INSTANCE_ARGS)
# then
self.assertEqual(ResourceGroup(id='some_group'),
......@@ -282,7 +297,9 @@ class ResourceGroupTest(TestCase):
'resources': [
{
'id': 'instance-1',
'type': 'instance'
'type': 'instance',
'cpu_count': 1,
'memory': 100
},
{
'id': 'level-1',
......@@ -290,11 +307,15 @@ class ResourceGroupTest(TestCase):
'resources': [
{
'id': 'instance-2',
'type': 'instance'
'type': 'instance',
'cpu_count': 2,
'memory': 200
},
{
'id': 'instance-3',
'type': 'instance'
'type': 'instance',
'cpu_count': 3,
'memory': 300
}
]
}
......@@ -306,10 +327,16 @@ class ResourceGroupTest(TestCase):
expected_flat_dict = {
'root.instance-1.id': 'instance-1',
'root.instance-1.type': 'instance',
'root.instance-1.cpu_count': 1,
'root.instance-1.memory': 100,
'root.level-1.instance-2.id': 'instance-2',
'root.level-1.instance-2.type': 'instance',
'root.level-1.instance-2.cpu_count': 2,
'root.level-1.instance-2.memory': 200,
'root.level-1.instance-3.id': 'instance-3',
'root.level-1.instance-3.type': 'instance'
'root.level-1.instance-3.type': 'instance',
'root.level-1.instance-3.cpu_count': 3,
'root.level-1.instance-3.memory': 300
}
# when
......@@ -322,9 +349,9 @@ class ResourceGroupTest(TestCase):
def test_resource_group_flatten_not_flat_leaves(self):
# given
expected_flat_dict = {
'root.instance-1': Instance(id='instance-1'),
'root.level-1.instance-2': Instance(id='instance-2'),
'root.level-1.instance-3': Instance(id='instance-3')
'root.instance-1': Instance(id='instance-1', cpu_count=1, memory=100),
'root.level-1.instance-2': Instance(id='instance-2', cpu_count=2, memory=200),
'root.level-1.instance-3': Instance(id='instance-3', cpu_count=3, memory=300)
}
# when
......@@ -345,6 +372,8 @@ class ResourceGroupTest(TestCase):
expected_diff_values = {
'root.instance-1.id': 'instance-1',
'root.instance-1.type': 'instance',
'root.instance-1.cpu_count': 1,
'root.instance-1.memory': 100
}
expected_diff_added = {
'added': expected_diff_values,
......@@ -374,7 +403,7 @@ class ResourceGroupTest(TestCase):
group2 = ResourceGroup(tree_dict2)
expected_diff_values = {
'root.instance-1': Instance(id=removed_resource['id'])
'root.instance-1': Instance(id=removed_resource['id'], cpu_count=1, memory=100)
}
expected_diff_added = {
'added': expected_diff_values,
......
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 sign in to comment