Added ability to remove services
Change-Id: Ieb763013679356c898924444383e4ac65d373736
This commit is contained in:
parent
169bf1316c
commit
944f7c57b4
@ -39,7 +39,8 @@ def normalize_path(f):
|
|||||||
class Controller(object):
|
class Controller(object):
|
||||||
@normalize_path
|
@normalize_path
|
||||||
def get(self, request, environment_id, path):
|
def get(self, request, environment_id, path):
|
||||||
log.debug(_('Services:Get <EnvId: {0}>'.format(environment_id)))
|
log.debug(_('Services:Get <EnvId: {0}, '
|
||||||
|
'Path: {1}>'.format(environment_id, path)))
|
||||||
|
|
||||||
session_id = None
|
session_id = None
|
||||||
if hasattr(request, 'context') and request.context.session:
|
if hasattr(request, 'context') and request.context.session:
|
||||||
@ -54,8 +55,8 @@ class Controller(object):
|
|||||||
@utils.verify_session
|
@utils.verify_session
|
||||||
@normalize_path
|
@normalize_path
|
||||||
def post(self, request, environment_id, path, body):
|
def post(self, request, environment_id, path, body):
|
||||||
log.debug(_('Services:Post <EnvId: {0}, '
|
log.debug(_('Services:Post <EnvId: {0}, , Path: {2}, '
|
||||||
'Body: {1}>'.format(environment_id, body)))
|
'Body: {1}>'.format(environment_id, body, path)))
|
||||||
|
|
||||||
post_data = CoreServices.post_data
|
post_data = CoreServices.post_data
|
||||||
session_id = request.context.session
|
session_id = request.context.session
|
||||||
@ -68,8 +69,8 @@ class Controller(object):
|
|||||||
@utils.verify_session
|
@utils.verify_session
|
||||||
@normalize_path
|
@normalize_path
|
||||||
def put(self, request, environment_id, path, body):
|
def put(self, request, environment_id, path, body):
|
||||||
log.debug(_('Services:Put <EnvId: {0}, '
|
log.debug(_('Services:Put <EnvId: {0}, , Path: {2}, '
|
||||||
'Body: {1}>'.format(environment_id, body)))
|
'Body: {1}>'.format(environment_id, body, path)))
|
||||||
|
|
||||||
put_data = CoreServices.put_data
|
put_data = CoreServices.put_data
|
||||||
session_id = request.context.session
|
session_id = request.context.session
|
||||||
@ -80,6 +81,20 @@ class Controller(object):
|
|||||||
raise HTTPNotFound
|
raise HTTPNotFound
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@utils.verify_session
|
||||||
|
@normalize_path
|
||||||
|
def delete(self, request, environment_id, path):
|
||||||
|
log.debug(_('Services:Put <EnvId: {0}, '
|
||||||
|
'Path: {1}>'.format(environment_id, path)))
|
||||||
|
|
||||||
|
delete_data = CoreServices.delete_data
|
||||||
|
session_id = request.context.session
|
||||||
|
|
||||||
|
try:
|
||||||
|
delete_data(environment_id, session_id, path)
|
||||||
|
except (KeyError, ValueError):
|
||||||
|
raise HTTPNotFound
|
||||||
|
|
||||||
|
|
||||||
def create_resource():
|
def create_resource():
|
||||||
return wsgi.Resource(Controller())
|
return wsgi.Resource(Controller())
|
||||||
|
@ -20,16 +20,21 @@ from collections import deque
|
|||||||
from functools import wraps
|
from functools import wraps
|
||||||
from muranoapi.openstack.common import log as logging
|
from muranoapi.openstack.common import log as logging
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class TraverseHelper(object):
|
class TraverseHelper(object):
|
||||||
|
value_type = (types.StringTypes, types.IntType, types.FloatType,
|
||||||
|
types.BooleanType)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get(path, source):
|
def get(path, source):
|
||||||
"""
|
"""
|
||||||
Provides the ability to traverse a data source made up of any
|
Provides the ability to traverse a data source made up of any
|
||||||
combination of lists and dicts. Has simple rules for selecting item of
|
combination of lists and dicts. Has simple rules for selecting item of
|
||||||
the list:
|
the list:
|
||||||
|
|
||||||
* each item should have id property
|
* each item should have id property
|
||||||
* to select item from the list, specify id value
|
* to select item from the list, specify id value
|
||||||
|
|
||||||
@ -49,24 +54,24 @@ class TraverseHelper(object):
|
|||||||
:return: object
|
:return: object
|
||||||
:raise: ValueError if object is malformed
|
:raise: ValueError if object is malformed
|
||||||
"""
|
"""
|
||||||
if path.startswith('/'):
|
queue = deque(filter(lambda x: x, path.split('/')))
|
||||||
path = path[1:]
|
|
||||||
|
|
||||||
queue = deque(path.split('/'))
|
|
||||||
obj = source
|
|
||||||
|
|
||||||
while len(queue):
|
while len(queue):
|
||||||
path = queue.popleft()
|
path = queue.popleft()
|
||||||
|
|
||||||
if isinstance(obj, types.ListType):
|
if isinstance(source, types.ListType):
|
||||||
filtered = filter(lambda i: 'id' in i and i['id'] == path, obj)
|
idx_source = source
|
||||||
obj = filtered[0] if filtered else None
|
source = next((i for i in source if i['id'] == path), None)
|
||||||
elif isinstance(obj, types.DictionaryType):
|
if source is None and path.isdigit():
|
||||||
obj = obj[path] if path else obj
|
source = idx_source[int(path)]
|
||||||
|
elif isinstance(source, types.DictionaryType):
|
||||||
|
source = source[path]
|
||||||
|
elif isinstance(source, TraverseHelper.value_type):
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
raise ValueError('Object or path is malformed')
|
raise ValueError('Source object or path is malformed')
|
||||||
|
|
||||||
return obj
|
return source
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def update(path, value, source):
|
def update(path, value, source):
|
||||||
@ -91,11 +96,34 @@ class TraverseHelper(object):
|
|||||||
|
|
||||||
:param path: string with path to desired value
|
:param path: string with path to desired value
|
||||||
:param value: value
|
:param value: value
|
||||||
:param source: python object (list or dict)
|
:param source: List
|
||||||
"""
|
"""
|
||||||
node = TraverseHelper.get(path, source)
|
node = TraverseHelper.get(path, source)
|
||||||
node.append(value)
|
node.append(value)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def remove(path, source):
|
||||||
|
"""
|
||||||
|
Removes selected item from source.
|
||||||
|
|
||||||
|
:param path: string with path to desired value
|
||||||
|
:param source: python object (list or dict)
|
||||||
|
"""
|
||||||
|
parent_path = '/'.join(path.split('/')[:-1])
|
||||||
|
node = TraverseHelper.get(parent_path, source)
|
||||||
|
key = path[1:].split('/')[-1]
|
||||||
|
|
||||||
|
if isinstance(node, types.ListType):
|
||||||
|
item = next((i for i in node if i['id'] == key), None)
|
||||||
|
if item is None and key.isdigit():
|
||||||
|
del node[int(key)]
|
||||||
|
else:
|
||||||
|
node.remove(item)
|
||||||
|
elif isinstance(node, types.DictionaryType):
|
||||||
|
del node[key]
|
||||||
|
else:
|
||||||
|
raise ValueError('Source object or path is malformed')
|
||||||
|
|
||||||
|
|
||||||
def auto_id(value):
|
def auto_id(value):
|
||||||
if isinstance(value, types.DictionaryType):
|
if isinstance(value, types.DictionaryType):
|
||||||
|
@ -67,3 +67,13 @@ class CoreServices(object):
|
|||||||
save_description(session_id, env_description)
|
save_description(session_id, env_description)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def delete_data(environment_id, session_id, path):
|
||||||
|
get_description = EnvironmentServices.get_environment_description
|
||||||
|
save_description = EnvironmentServices.save_environment_description
|
||||||
|
|
||||||
|
env_description = get_description(environment_id, session_id)
|
||||||
|
|
||||||
|
TraverseHelper.remove(path, env_description)
|
||||||
|
save_description(session_id, env_description)
|
||||||
|
@ -11,27 +11,38 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import unittest2 as unittest
|
import unittest2 as unittest
|
||||||
from muranoapi.common.utils import TraverseHelper
|
from muranoapi.common.utils import TraverseHelper
|
||||||
|
|
||||||
|
|
||||||
class TraverseHelperTests(unittest.TestCase):
|
class TraverseHelperTests(unittest.TestCase):
|
||||||
def test_simple_root_get(self):
|
def test_root_get_with_dict(self):
|
||||||
source = {"attr": True}
|
source = {'attr': True}
|
||||||
value = TraverseHelper.get('/', source)
|
value = TraverseHelper.get('/', source)
|
||||||
self.assertDictEqual(value, {"attr": True})
|
self.assertDictEqual(value, source)
|
||||||
|
|
||||||
def test_simple_attribute_get(self):
|
def test_root_get_with_list(self):
|
||||||
source = {"attr": True}
|
source = [{'attr': True}]
|
||||||
|
value = TraverseHelper.get('/', source)
|
||||||
|
self.assertListEqual(value, source)
|
||||||
|
|
||||||
|
def test_root_get_with_value_type(self):
|
||||||
|
source = 'source'
|
||||||
|
value = TraverseHelper.get('/', source)
|
||||||
|
self.assertEqual(value, source)
|
||||||
|
|
||||||
|
def test_attribute_get(self):
|
||||||
|
source = {'attr': True}
|
||||||
value = TraverseHelper.get('/attr', source)
|
value = TraverseHelper.get('/attr', source)
|
||||||
self.assertEqual(value, True)
|
self.assertEqual(value, True)
|
||||||
|
|
||||||
def test_attribute_get(self):
|
def test_nested_attribute_get(self):
|
||||||
source = {'obj': {'attr': True}}
|
source = {'obj': {'attr': True}}
|
||||||
value = TraverseHelper.get('/obj/attr', source)
|
value = TraverseHelper.get('/obj/attr', source)
|
||||||
self.assertEqual(value, True)
|
self.assertEqual(value, True)
|
||||||
|
|
||||||
def test_list_item_attribute_get_(self):
|
def test_list_item_attribute_get(self):
|
||||||
source = {'obj': [
|
source = {'obj': [
|
||||||
{'id': '1', 'value': 1},
|
{'id': '1', 'value': 1},
|
||||||
{'id': '2s', 'value': 2},
|
{'id': '2s', 'value': 2},
|
||||||
@ -39,53 +50,64 @@ class TraverseHelperTests(unittest.TestCase):
|
|||||||
value = TraverseHelper.get('/obj/2s/value', source)
|
value = TraverseHelper.get('/obj/2s/value', source)
|
||||||
self.assertEqual(value, 2)
|
self.assertEqual(value, 2)
|
||||||
|
|
||||||
def test_simple_attribute_set(self):
|
def test_list_item_attribute_get_by_index(self):
|
||||||
source = {"attr": True}
|
source = {'obj': [
|
||||||
|
{'id': 'guid1', 'value': 1},
|
||||||
|
{'id': 'guid2', 'value': 2},
|
||||||
|
]}
|
||||||
|
value = TraverseHelper.get('/obj/1/value', source)
|
||||||
|
self.assertEqual(value, 2)
|
||||||
|
|
||||||
|
def test_attribute_set(self):
|
||||||
|
source = {'attr': True}
|
||||||
TraverseHelper.update('/newAttr', False, source)
|
TraverseHelper.update('/newAttr', False, source)
|
||||||
value = TraverseHelper.get('/newAttr', source)
|
value = TraverseHelper.get('/newAttr', source)
|
||||||
self.assertEqual(value, False)
|
self.assertEqual(value, False)
|
||||||
|
|
||||||
def test_simple_attribute_update(self):
|
def test_attribute_update(self):
|
||||||
source = {"attr": True}
|
source = {'attr': True}
|
||||||
TraverseHelper.update('/attr', False, source)
|
TraverseHelper.update('/attr', False, source)
|
||||||
value = TraverseHelper.get('/attr', source)
|
value = TraverseHelper.get('/attr', source)
|
||||||
self.assertEqual(value, False)
|
self.assertEqual(value, False)
|
||||||
|
|
||||||
def test_attribute_update(self):
|
def test_nested_attribute_update(self):
|
||||||
source = {"obj": {"attr": True}}
|
source = {'obj': {'attr': True}}
|
||||||
TraverseHelper.update('/obj/attr', False, source)
|
TraverseHelper.update('/obj/attr', False, source)
|
||||||
value = TraverseHelper.get('/obj/attr', source)
|
value = TraverseHelper.get('/obj/attr', source)
|
||||||
self.assertEqual(value, False)
|
self.assertEqual(value, False)
|
||||||
|
|
||||||
def test_simple_adding_item_to_list(self):
|
def test_adding_item_to_list(self):
|
||||||
source = {"attr": [1, 2, 3]}
|
source = {'attr': [1, 2, 3]}
|
||||||
TraverseHelper.insert('/attr', 4, source)
|
TraverseHelper.insert('/attr', 4, source)
|
||||||
value = TraverseHelper.get('/attr', source)
|
value = TraverseHelper.get('/attr', source)
|
||||||
self.assertListEqual(value, [1, 2, 3, 4])
|
self.assertListEqual(value, [1, 2, 3, 4])
|
||||||
|
|
||||||
def test_adding_item_to_list(self):
|
def test_nested_adding_item_to_list(self):
|
||||||
source = {"obj": {"attr": [1, 2, 3]}}
|
source = {'obj': {'attr': [1, 2, 3]}}
|
||||||
TraverseHelper.insert('/obj/attr', 4, source)
|
TraverseHelper.insert('/obj/attr', 4, source)
|
||||||
value = TraverseHelper.get('/obj/attr', source)
|
value = TraverseHelper.get('/obj/attr', source)
|
||||||
self.assertListEqual(value, [1, 2, 3, 4])
|
self.assertListEqual(value, [1, 2, 3, 4])
|
||||||
|
|
||||||
@unittest.skip
|
def test_attribute_remove_from_dict(self):
|
||||||
def test_simple_attribute_remove(self):
|
source = {'attr1': False, 'attr2': True}
|
||||||
source = {"attr1": False, "attr2": True}
|
|
||||||
TraverseHelper.remove('/attr1', source)
|
TraverseHelper.remove('/attr1', source)
|
||||||
value = TraverseHelper.get('/', source)
|
value = TraverseHelper.get('/', source)
|
||||||
self.assertEqual(value, {"attr2": True})
|
self.assertDictEqual(value, {'attr2': True})
|
||||||
|
|
||||||
@unittest.skip
|
def test_nested_attribute_remove_from_dict(self):
|
||||||
def test_nested_attribute_remove_from_object(self):
|
source = {'obj': {'attr1': False, 'attr2': True}}
|
||||||
source = {"obj": {"attr1": False, "attr2": True}}
|
|
||||||
TraverseHelper.remove('/obj/attr1', source)
|
TraverseHelper.remove('/obj/attr1', source)
|
||||||
value = TraverseHelper.get('/obj', source)
|
value = TraverseHelper.get('/obj', source)
|
||||||
self.assertDictEqual(value, {"attr2": True})
|
self.assertDictEqual(value, {'attr2': True})
|
||||||
|
|
||||||
@unittest.skip
|
def test_nested_attribute_remove_from_list_by_id(self):
|
||||||
def test_nested_attribute_remove_from_list(self):
|
source = {'obj': [{'id': 'id1'}, {'id': 'id2'}]}
|
||||||
source = {"obj": [{"id": 'id1'}, {"id": 'id2'}]}
|
|
||||||
TraverseHelper.remove('/obj/id1', source)
|
TraverseHelper.remove('/obj/id1', source)
|
||||||
value = TraverseHelper.get('/', source)
|
value = TraverseHelper.get('/obj', source)
|
||||||
self.assertListEqual(value, [{"id": 'id2'}])
|
self.assertListEqual(value, [{'id': 'id2'}])
|
||||||
|
|
||||||
|
def test_nested_attribute_remove_from_list_by_index(self):
|
||||||
|
source = {'obj': [{'id': 'id1'}, {'id': 'id2'}]}
|
||||||
|
TraverseHelper.remove('/obj/0', source)
|
||||||
|
value = TraverseHelper.get('/obj', source)
|
||||||
|
self.assertListEqual(value, [{'id': 'id2'}])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user