Commit 09e73a8e by Simon János

added new resource types; changed tests accordingly

parent 553e5137
import copy
import json import json
import uuid import uuid
from socket import inet_aton
from enum import Enum 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): class Resource(object):
...@@ -23,7 +27,7 @@ class Resource(object): ...@@ -23,7 +27,7 @@ class Resource(object):
@classmethod @classmethod
def __attributes_from_dict(cls, attributes): def __attributes_from_dict(cls, attributes):
cls.__validate_attributes(attributes, cls.__schema(extend=False)) 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['id'] = attributes.get('id', Resource.__generate_random_id())
attributes['type'] = ResourceType.validate(attributes.get('type', cls)) attributes['type'] = ResourceType.validate(attributes.get('type', cls))
return attributes return attributes
...@@ -37,17 +41,28 @@ class Resource(object): ...@@ -37,17 +41,28 @@ class Resource(object):
@classmethod @classmethod
def __schema(cls, resource_type=None, extend=False): 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: if extend:
additional = resource_type.ADDITIONAL_SCHEMA if resource_type else cls.ADDITIONAL_SCHEMA additional = resource_type.ADDITIONAL_SCHEMA if resource_type else cls.ADDITIONAL_SCHEMA
schema = schema.extend(additional, extra=PREVENT_EXTRA) schema = schema.extend(additional, extra=PREVENT_EXTRA)
return schema return schema
@staticmethod @staticmethod
def __id_validator(resource_id): def _id_validator(resource_id):
if not re.compile('^[a-zA-Z0-9_-]{2,42}$').match(resource_id): if not re.compile('^[a-zA-Z0-9_-]{2,42}$').match(resource_id):
raise Invalid("'%s' is invalid" % 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 @property
def type(self): def type(self):
return str(self._attributes['type']) return str(self._attributes['type'])
...@@ -92,7 +107,10 @@ class Resource(object): ...@@ -92,7 +107,10 @@ class Resource(object):
def flatten(self, fqn=None, flat_leaves=True): def flatten(self, fqn=None, flat_leaves=True):
fqn = '%s.%s' % (fqn, self.id) if fqn else self.id fqn = '%s.%s' % (fqn, self.id) if fqn else self.id
if flat_leaves: 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} return {fqn: self}
@staticmethod @staticmethod
...@@ -101,10 +119,13 @@ class Resource(object): ...@@ -101,10 +119,13 @@ class Resource(object):
return str(data) return str(data)
return dict(data) return dict(data)
def deploy(self, name):
pass
class ResourceGroup(Resource): class ResourceGroup(Resource):
ADDITIONAL_SCHEMA = { ADDITIONAL_SCHEMA = {
'resources': Any(list, set, tuple) Optional('resources'): Any(list, set, tuple)
} }
def __init__(self, *_, **__): def __init__(self, *_, **__):
...@@ -162,7 +183,53 @@ class ResourceGroup(Resource): ...@@ -162,7 +183,53 @@ class ResourceGroup(Resource):
class Instance(Resource): class Instance(Resource):
ADDITIONAL_SCHEMA = { 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): ...@@ -170,6 +237,9 @@ class ResourceType(Enum):
null = Resource null = Resource
group = ResourceGroup group = ResourceGroup
instance = Instance instance = Instance
disk = Disk
attachment = DiskAttachment
connection = NetworkConnection
@classmethod @classmethod
def validate(cls, value): def validate(cls, value):
......
...@@ -5,6 +5,10 @@ from falcon.testing import TestCase ...@@ -5,6 +5,10 @@ from falcon.testing import TestCase
from orchestrator.api import stacks from orchestrator.api import stacks
TEST_INSTANCE_ARGS = {
'cpu_count': 2,
'memory': 256 * 1000 * 1000
}
class StackTest(TestCase): class StackTest(TestCase):
def setUp(self): def setUp(self):
...@@ -30,7 +34,9 @@ class StackTest(TestCase): ...@@ -30,7 +34,9 @@ class StackTest(TestCase):
'resources': [ 'resources': [
{ {
'id': 'instance-1', 'id': 'instance-1',
'type': 'instance' 'type': 'instance',
'cpu_count': 1,
'memory': 100
}, },
{ {
'id': 'level-1', 'id': 'level-1',
...@@ -38,11 +44,23 @@ class StackTest(TestCase): ...@@ -38,11 +44,23 @@ class StackTest(TestCase):
'resources': [ 'resources': [
{ {
'id': 'instance-2', 'id': 'instance-2',
'type': 'instance' 'type': 'instance',
'cpu_count': 2,
'memory': 200
}, },
{ {
'id': 'instance-3', '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): ...@@ -96,6 +114,7 @@ class StackTest(TestCase):
resource_id = 'new_resource' resource_id = 'new_resource'
group1 = {'id': stack_id, 'type': 'group', 'resources': []} group1 = {'id': stack_id, 'type': 'group', 'resources': []}
resource = {'id': resource_id, 'type': 'instance'} resource = {'id': resource_id, 'type': 'instance'}
resource.update(TEST_INSTANCE_ARGS)
group2 = {'id': stack_id, 'type': 'group', 'resources': [resource]} group2 = {'id': stack_id, 'type': 'group', 'resources': [resource]}
expected_diff = { expected_diff = {
'added': { 'added': {
...@@ -117,6 +136,7 @@ class StackTest(TestCase): ...@@ -117,6 +136,7 @@ class StackTest(TestCase):
# given # given
resource_id = 'some_resource' resource_id = 'some_resource'
resource = {'id': resource_id, 'type': 'instance'} resource = {'id': resource_id, 'type': 'instance'}
resource.update(TEST_INSTANCE_ARGS)
# when # when
self.simulate_post('/stacks', body=json.dumps(resource)) self.simulate_post('/stacks', body=json.dumps(resource))
...@@ -132,7 +152,9 @@ class StackTest(TestCase): ...@@ -132,7 +152,9 @@ class StackTest(TestCase):
def test_stacks_api_get_list(self): def test_stacks_api_get_list(self):
# given # given
resource1 = {'id': 'some_resource', 'type': 'instance'} resource1 = {'id': 'some_resource', 'type': 'instance'}
resource1.update(TEST_INSTANCE_ARGS)
resource2 = {'id': 'some_other_resource', 'type': 'instance'} resource2 = {'id': 'some_other_resource', 'type': 'instance'}
resource2.update(TEST_INSTANCE_ARGS)
# when # when
self.simulate_post('/stacks', body=json.dumps(resource1)) self.simulate_post('/stacks', body=json.dumps(resource1))
...@@ -148,6 +170,7 @@ class StackTest(TestCase): ...@@ -148,6 +170,7 @@ class StackTest(TestCase):
# given # given
resource_id = 'some_resource' resource_id = 'some_resource'
resource = {'id': resource_id, 'type': 'instance'} resource = {'id': resource_id, 'type': 'instance'}
resource.update(TEST_INSTANCE_ARGS)
# when # when
self.simulate_post('/stacks', body=json.dumps(resource)) self.simulate_post('/stacks', body=json.dumps(resource))
......
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