Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Simon János
/
orchestrator
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
0b005a39
authored
Nov 16, 2016
by
Simon János
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
actually the whole code has been refactored
parent
eed8e4b7
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
277 additions
and
136 deletions
+277
-136
orchestrator/model/resources.py
+122
-78
tests/test_resources.py
+155
-58
No files found.
orchestrator/model/resources.py
View file @
0b005a39
import
copy
import
json
import
uuid
from
enum
import
Enum
from
voluptuous
import
Schema
,
Invalid
,
MultipleInvalid
from
voluptuous
import
Schema
,
Invalid
,
MultipleInvalid
,
Any
,
ALLOW_EXTRA
,
PREVENT_EXTRA
class
Resource
(
object
):
DEFAULT_ID_LENGTH
=
8
ADDITIONAL_SCHEMA
=
{}
def
__new__
(
cls
,
*
args
,
**
kwargs
):
attributes
=
cls
.
__attributes_from_dict
(
args
[
0
]
if
len
(
args
)
else
kwargs
)
resource_type
=
attributes
[
'type'
]
.
value
if
resource_type
is
Resource
:
raise
InvalidResourceException
(
'Resource class is abstract'
)
cls
.
__validate_attributes
(
attributes
,
cls
.
__schema
(
resource_type
,
extend
=
True
))
instance
=
super
(
Resource
,
resource_type
)
.
__new__
(
resource_type
)
instance
.
_attributes
=
attributes
# pylint: disable=protected-access
return
instance
def
__init__
(
self
,
*
args
,
**
kwargs
):
if
len
(
args
):
resource
=
args
[
0
]
if
isinstance
(
resource
,
Resource
):
self
.
__id
=
resource
.
id
self
.
__type
=
Resource
.
Type
[
resource
.
type
]
else
:
self
.
__attributes_from_dict
(
resource
)
else
:
self
.
__attributes_from_dict
(
kwargs
)
def
__attributes_from_dict
(
self
,
attributes
):
schema
=
Schema
({
'id'
:
str
,
'type'
:
Resource
.
Type
.
validate
})
@classmethod
def
__attributes_from_dict
(
cls
,
attributes
):
cls
.
__validate_attributes
(
attributes
,
cls
.
__schema
(
extend
=
False
))
attributes
=
copy
.
deepcopy
(
attributes
)
attributes
[
'id'
]
=
attributes
.
get
(
'id'
,
Resource
.
__generate_random_id
())
attributes
[
'type'
]
=
ResourceType
.
validate
(
attributes
.
get
(
'type'
,
cls
))
return
attributes
@classmethod
def
__validate_attributes
(
cls
,
attributes
,
schema
):
try
:
schema
(
attributes
)
self
.
__id
=
attributes
.
get
(
'id'
,
Resource
.
_random_id
())
self
.
__type
=
Resource
.
Type
[
attributes
.
get
(
'type'
,
'null'
)]
except
MultipleInvalid
as
invalid
:
raise
InvalidResourceException
(
invalid
)
@property
def
id
(
self
):
return
self
.
__id
@classmethod
def
__schema
(
cls
,
resource_type
=
None
,
extend
=
False
):
try
:
string_validator
=
Any
(
str
,
unicode
)
except
NameError
:
string_validator
=
Any
(
str
)
schema
=
Schema
(
schema
=
{
'id'
:
string_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
@property
def
type
(
self
):
return
self
.
__type
.
name
return
str
(
self
.
_attributes
[
'type'
])
def
__getattr__
(
self
,
item
):
try
:
return
self
.
_attributes
[
item
]
except
KeyError
:
raise
AttributeError
(
'Attribute (
%
s) is not set on resource'
)
@staticmethod
def
_random_id
():
def
_
_generate_
random_id
():
return
uuid
.
uuid4
()
.
hex
[:
Resource
.
DEFAULT_ID_LENGTH
]
def
__eq__
(
self
,
other
):
return
isinstance
(
other
,
Resource
)
and
\
self
.
id
==
other
.
id
and
\
self
.
type
==
other
.
type
try
:
for
attr
,
other_value
in
other
.
items
():
value
=
self
.
_attributes
.
get
(
attr
)
if
value
is
None
or
value
!=
other_value
:
return
False
return
True
except
AttributeError
:
return
False
def
__repr__
(
self
):
return
"
%
s(
%
s)"
%
(
self
.
__class__
.
__name__
,
self
.
id
)
return
json
.
dumps
(
self
,
default
=
Resource
.
json_encoder
)
def
__
hash
__
(
self
):
return
hash
(
self
.
__repr__
()
)
def
__
iter
__
(
self
):
return
self
.
_attributes
.
__iter__
(
)
class
Type
(
Enum
):
null
=
0
instance
=
1
def
keys
(
self
):
return
self
.
_attributes
.
keys
()
@classmethod
def
validate
(
cls
,
value
):
try
:
cls
[
value
]
except
KeyError
:
raise
Invalid
(
'The given resource type (
%
s) is not valid'
%
value
)
return
True
def
values
(
self
):
return
self
.
_attributes
.
values
()
def
items
(
self
):
return
self
.
_attributes
.
items
()
class
Instance
(
Resource
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
kwargs
[
'type'
]
=
Resource
.
Type
.
instance
.
name
super
(
Instance
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
__getitem__
(
self
,
item
):
return
self
.
_attributes
[
item
]
def
__add__
(
self
,
other
):
return
ResourceGroup
(
resources
=
[
self
,
other
])
@staticmethod
def
json_encoder
(
data
):
if
isinstance
(
data
,
ResourceType
):
return
str
(
data
)
return
dict
(
data
)
class
ResourceGroup
(
Resource
):
ADDITIONAL_SCHEMA
=
{
'resources'
:
Any
(
list
,
set
,
tuple
)
}
def
__init__
(
self
,
*
_
,
**
__
):
self
.
__resources
=
{}
if
'resources'
in
self
.
_attributes
.
keys
():
for
resource
in
self
.
_attributes
[
'resources'
]:
self
.
add
(
resource
)
self
.
_attributes
[
'resources'
]
=
self
.
resources
def
add
(
self
,
resource
):
if
not
isinstance
(
resource
,
Resource
):
try
:
resource
=
Resource
(
resource
)
except
InvalidResourceException
:
raise
InvalidResourceException
(
'ResourceGroup can only store resources'
)
self
.
__resources
[
resource
.
id
]
=
resource
class
ResourceGroup
(
object
):
def
__init__
(
self
,
*
args
):
self
.
__resources
=
set
()
if
len
(
args
):
for
argument
in
args
:
def
remove
(
self
,
resource
):
try
:
self
.
__iadd__
(
argument
)
del
self
.
__resources
[
Resource
(
resource
)
.
id
]
except
InvalidResourceException
:
for
resource
in
argument
:
self
.
__iadd__
(
resource
)
del
self
.
__resources
[
resource
.
id
]
@property
def
resources
(
self
):
return
list
(
self
.
__resources
)
return
list
(
self
.
__resources
.
values
()
)
def
__add__
(
self
,
other
):
if
isinstance
(
other
,
dict
):
return
ResourceGroup
(
Resource
(
other
),
*
self
.
resources
)
if
isinstance
(
other
,
Resource
):
return
ResourceGroup
(
other
,
*
self
.
resources
)
if
isinstance
(
other
,
ResourceGroup
):
resources
=
other
.
resources
+
self
.
resources
return
ResourceGroup
(
*
resources
)
raise
InvalidResourceException
()
def
__iadd__
(
self
,
other
):
if
isinstance
(
other
,
dict
):
self
.
__resources
.
add
(
Resource
(
other
))
return
self
if
isinstance
(
other
,
Resource
):
self
.
__resources
.
add
(
other
)
return
self
if
isinstance
(
other
,
ResourceGroup
):
self
.
__resources
.
union
(
other
.
resources
)
return
self
raise
InvalidResourceException
()
def
__iter__
(
self
):
return
self
.
__resources
.
__iter__
()
class
Instance
(
Resource
):
ADDITIONAL_SCHEMA
=
{
'number_of_cores'
:
int
}
def
__eq__
(
self
,
other
):
return
self
.
__resources
==
set
(
other
.
resources
)
class
ResourceType
(
Enum
):
null
=
Resource
group
=
ResourceGroup
instance
=
Instance
@classmethod
def
validate
(
cls
,
value
):
if
isinstance
(
value
,
cls
):
return
value
try
:
return
cls
[
value
]
except
KeyError
:
return
cls
(
value
)
except
ValueError
:
raise
Invalid
(
'The given resource type (
%
s) is not valid'
%
value
)
def
__str__
(
self
):
return
str
(
self
.
name
)
def
__repr__
(
self
):
return
'
%
s(
%
s)'
%
(
self
.
__class__
.
__name__
,
str
(
self
))
class
InvalidResourceException
(
Exception
):
...
...
tests/test_resources.py
View file @
0b005a39
import
json
from
unittest.case
import
TestCase
from
voluptuous
import
Invalid
from
orchestrator.model.resources
import
Resource
,
ResourceGroup
,
Instance
,
InvalidResourceException
from
orchestrator.model.resources
import
Resource
,
ResourceGroup
,
Instance
,
InvalidResourceException
,
ResourceType
class
ResourceTest
(
TestCase
):
def
test_resource_without_args
(
self
):
# when
resource
=
Resource
()
# then
self
.
assertIsInstance
(
resource
.
id
,
str
)
self
.
assertEqual
(
Resource
.
DEFAULT_ID_LENGTH
,
len
(
resource
.
id
))
self
.
assertEqual
(
'null'
,
resource
.
type
)
with
self
.
assertRaises
(
InvalidResourceException
):
Resource
()
def
test_resource_from_args
(
self
):
# given
expected_id
=
'dummy_resource'
expected_type
=
'null'
expected_type
=
ResourceType
.
instance
# when
result
=
Resource
(
id
=
expected_id
,
type
=
expected_type
)
# then
self
.
assertEqual
(
expected_id
,
result
.
id
)
self
.
assertEqual
(
expected_type
,
result
.
type
)
self
.
assertEqual
(
expected_type
.
name
,
result
.
type
)
def
test_resource_from_dict
(
self
):
# given
resource_dict
=
dict
(
id
=
'dummy_resource'
,
type
=
'null'
)
resource_dict
=
{
'id'
:
'dummy_resource'
,
'type'
:
'instance'
}
# when
result
=
Resource
(
resource_dict
)
...
...
@@ -50,12 +44,20 @@ class ResourceTest(TestCase):
with
self
.
assertRaises
(
InvalidResourceException
):
Resource
(
invalid_attributes
)
def
test_resource_type_validate
(
self
):
self
.
assertTrue
(
Resource
.
Type
.
validate
(
'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
))
def
test_resource_type_invalid
(
self
):
with
self
.
assertRaises
(
Invalid
):
Resource
.
Type
.
validate
(
'nonexisting_resource_type'
)
with
self
.
assertRaises
(
ValueError
):
ResourceType
.
validate
(
'nonexisting_resource_type'
)
def
test_resource_instance
(
self
):
# when
...
...
@@ -64,20 +66,61 @@ class ResourceTest(TestCase):
# then
self
.
assertIsInstance
(
instance
.
id
,
str
)
self
.
assertEqual
(
Resource
.
DEFAULT_ID_LENGTH
,
len
(
instance
.
id
))
self
.
assertEqual
(
Resource
.
Type
.
instance
.
name
,
instance
.
type
)
self
.
assertEqual
(
ResourceType
.
instance
.
name
,
instance
.
type
)
def
test_resource_equivalence
(
self
):
# given
resource1
=
Resource
(
id
=
'some_resource'
,
type
=
'null'
)
resource2
=
Resource
(
id
=
'some_resource'
,
type
=
'null'
)
resource3
=
Resource
(
id
=
'some_other_resource'
,
type
=
'null'
)
resource4
=
Resource
(
id
=
'some_resource'
,
type
=
'instance'
)
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
)
resource5
=
Resource
(
id
=
'some_resource'
,
type
=
ResourceGroup
)
# then
self
.
assertEqual
(
resource1
,
resource1
)
self
.
assertEqual
(
resource1
,
resource2
)
self
.
assert
Not
Equal
(
resource1
,
resource3
)
self
.
assertEqual
(
resource1
,
resource3
)
self
.
assertNotEqual
(
resource1
,
resource4
)
self
.
assertNotEqual
(
resource1
,
resource5
)
self
.
assertFalse
(
resource1
==
500
)
def
test_resource_str_representation
(
self
):
# given
expected_json
=
'{"id": "some_resource", "type": "instance"}'
expected_dict
=
json
.
loads
(
expected_json
)
# when
resource
=
Resource
(
expected_dict
)
resource_dict
=
json
.
loads
(
str
(
resource
))
# then
self
.
assertEqual
(
expected_dict
,
resource_dict
)
def
test_resource_dict_representation
(
self
):
# given
expected_dict
=
{
'id'
:
'some_resource'
,
'type'
:
ResourceType
.
instance
}
# when
resource
=
Resource
(
expected_dict
)
resource_dict
=
dict
(
resource
)
# then
self
.
assertEqual
(
expected_dict
,
resource_dict
)
def
test_dynamic_resource_type
(
self
):
# when
resource
=
Resource
(
type
=
'instance'
)
# then
self
.
__assert_is_instance
(
resource
)
self
.
__assert_is_instance
(
Resource
({
'type'
:
'instance'
}))
with
self
.
assertRaises
(
InvalidResourceException
):
Resource
()
def
__assert_is_instance
(
self
,
resource
):
self
.
assertIsInstance
(
resource
,
Instance
)
self
.
assertEqual
(
ResourceType
.
instance
.
name
,
resource
.
type
)
class
ResourceGroupTest
(
TestCase
):
...
...
@@ -90,65 +133,119 @@ class ResourceGroupTest(TestCase):
def
test_resource_group_from_resources
(
self
):
# given
resource1
=
Resour
ce
(
id
=
'some_resource'
)
resource2
=
Resour
ce
(
id
=
'some_other_resource'
)
resource1
=
Instan
ce
(
id
=
'some_resource'
)
resource2
=
Instan
ce
(
id
=
'some_other_resource'
)
# then
self
.
assertEqual
([
resource1
],
ResourceGroup
(
resource1
)
.
resources
)
self
.
assertEqual
([
resource1
],
ResourceGroup
([
resource1
])
.
resources
)
self
.
assertEqual
([
resource1
],
ResourceGroup
([
resource1
,
resource1
])
.
resources
)
self
.
assertEqual
([
resource1
],
ResourceGroup
(
resources
=
[
resource1
])
.
resources
)
self
.
assertEqual
([
resource1
],
ResourceGroup
(
resources
=
[
resource1
,
resource1
])
.
resources
)
for
resources
in
[[
resource1
,
resource2
],
[
resource2
,
resource1
]]:
self
.
assertEqual
(
2
,
len
(
ResourceGroup
(
*
resources
)
.
resources
))
self
.
assertIn
(
resource1
,
ResourceGroup
(
*
resources
)
.
resources
)
self
.
assertIn
(
resource2
,
ResourceGroup
(
*
resources
)
.
resources
)
self
.
assertEqual
(
2
,
len
(
ResourceGroup
(
resources
=
resources
)
.
resources
))
self
.
assertIn
(
resource1
,
ResourceGroup
(
resources
=
resources
)
.
resources
)
self
.
assertIn
(
resource2
,
ResourceGroup
(
resources
=
resources
)
.
resources
)
def
test_resource_group_from_invalid_collection
(
self
):
with
self
.
assertRaises
(
InvalidResourceException
):
ResourceGroup
(
resources
=
{
'invalid'
:
'resource'
})
def
test_resource_group_from_dicts
(
self
):
# given
dict1
=
dict
(
id
=
'some_resource'
)
dict2
=
dict
(
id
=
'some_other_resource'
)
expected1
=
Resour
ce
(
dict1
)
expected2
=
Resour
ce
(
dict2
)
dict1
=
dict
(
id
=
'some_resource'
,
type
=
Instance
)
dict2
=
dict
(
id
=
'some_other_resource'
,
type
=
Instance
)
expected1
=
Instan
ce
(
dict1
)
expected2
=
Instan
ce
(
dict2
)
# then
self
.
assertEqual
([
expected1
],
ResourceGroup
(
dict1
)
.
resources
)
self
.
assertEqual
([
expected1
],
ResourceGroup
([
dict1
])
.
resources
)
self
.
assertEqual
([
expected1
],
ResourceGroup
([
dict1
,
dict1
])
.
resources
)
self
.
assertEqual
([
expected1
],
ResourceGroup
(
resources
=
[
dict1
])
.
resources
)
self
.
assertEqual
([
expected1
],
ResourceGroup
(
resources
=
[
dict1
,
dict1
])
.
resources
)
for
resources
in
[[
expected1
,
expected2
],
[
dict2
,
dict1
]]:
self
.
assertEqual
(
2
,
len
(
ResourceGroup
(
resources
)
.
resources
))
self
.
assertIn
(
expected1
,
ResourceGroup
(
resources
)
.
resources
)
self
.
assertIn
(
expected2
,
ResourceGroup
(
resources
)
.
resources
)
self
.
assertEqual
(
2
,
len
(
ResourceGroup
(
resources
=
resources
)
.
resources
))
self
.
assertIn
(
expected1
,
ResourceGroup
(
resources
=
resources
)
.
resources
)
self
.
assertIn
(
expected2
,
ResourceGroup
(
resources
=
resources
)
.
resources
)
def
test_resource_group_from_dict
(
self
):
# given
expected_group_id
=
'some_resource_group'
expected_resource_id
=
'some_instance'
group_dict
=
{
'id'
:
expected_group_id
,
'type'
:
'group'
,
'resources'
:
[
{
'id'
:
expected_resource_id
,
'type'
:
'instance'
}
]
}
# when
group
=
ResourceGroup
(
group_dict
)
# then
self
.
assertEqual
(
expected_group_id
,
group
.
id
)
self
.
assertEqual
(
1
,
len
(
group
.
resources
))
self
.
assertEqual
(
expected_resource_id
,
group
.
resources
[
0
]
.
id
)
def
test_resource_group_add_resource
(
self
):
# given
group
=
ResourceGroup
()
resource
=
Instance
()
# when
group
.
add
(
resource
)
# then
self
.
assertEqual
(
1
,
len
(
group
.
resources
))
self
.
assertIn
(
resource
,
group
.
resources
)
def
test_resource_group_remove_resource
(
self
):
# given
resource
=
Instance
()
group
=
ResourceGroup
()
group
.
add
(
resource
)
# when
group
.
remove
(
resource
)
# then
self
.
assertEqual
([],
group
.
resources
)
# @skip('works same way as resource addition')
def
test_resource_group_addition
(
self
):
# given
resource1
=
Resource
()
resource2
=
Resource
()
group1
=
ResourceGroup
(
resource1
)
group2
=
ResourceGroup
(
resource2
)
group1
=
ResourceGroup
()
group2
=
ResourceGroup
()
resource
=
Instance
()
# when
result_group
=
group1
+
group2
result_group1
=
group1
+
group2
result_group2
=
result_group1
+
resource
# then
self
.
assertEqual
(
2
,
len
(
result_group
.
resources
))
self
.
assertIn
(
resource1
,
result_group
.
resources
)
self
.
assertIn
(
resource2
,
result_group
.
resources
)
self
.
assertIsInstance
(
result_group1
,
ResourceGroup
)
self
.
assertIsInstance
(
result_group2
,
ResourceGroup
)
self
.
assertEqual
(
2
,
len
(
result_group1
.
resources
))
self
.
assertEqual
(
2
,
len
(
result_group2
.
resources
))
self
.
assertIn
(
group1
,
result_group1
.
resources
)
self
.
assertIn
(
group2
,
result_group1
.
resources
)
self
.
assertIn
(
resource
,
result_group2
.
resources
)
def
test_resource_group_iteration
(
self
):
# when
group
=
ResourceGroup
(
Resource
(),
Resource
(),
Resource
()
)
group
=
ResourceGroup
(
resources
=
[
Instance
(),
Instance
(),
Instance
()]
)
# then
for
index
,
resource
in
enumerate
(
group
):
for
index
,
resource
in
enumerate
(
group
.
resources
):
self
.
assertEqual
(
group
.
resources
[
index
],
resource
)
def
test_resource_group_equivalence
(
self
):
# given
resource1
=
Resource
(
id
=
'some_resource'
,
type
=
'null'
)
resource2
=
Resource
(
id
=
'some_resource'
,
type
=
'null'
)
resource3
=
Resource
(
id
=
'some_other_resource'
,
type
=
'null'
)
resource1
=
Instance
(
id
=
'some_resource'
)
resource2
=
Instance
(
id
=
'some_other_resource'
)
# then
self
.
assertEqual
(
ResourceGroup
(),
ResourceGroup
())
self
.
assertEqual
(
ResourceGroup
(
resource1
),
ResourceGroup
(
resource1
))
self
.
assertEqual
(
ResourceGroup
(
resource1
),
ResourceGroup
(
resource2
))
self
.
assertNotEqual
(
ResourceGroup
(
resource1
),
ResourceGroup
(
resource3
))
self
.
assertEqual
(
ResourceGroup
(
id
=
'some_group'
),
ResourceGroup
(
id
=
'some_group'
))
self
.
assertEqual
(
ResourceGroup
(
id
=
'some_group'
,
resources
=
[
resource1
]),
ResourceGroup
(
id
=
'some_group'
,
resources
=
[
resource1
]))
self
.
assertNotEqual
(
ResourceGroup
(
id
=
'some_group'
),
ResourceGroup
(
id
=
'some_other_group'
))
self
.
assertNotEqual
(
ResourceGroup
(
id
=
'some_group'
,
resources
=
[
resource1
]),
ResourceGroup
(
id
=
'some_group'
,
resources
=
[
resource2
]))
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