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):
|
||||
@normalize_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
|
||||
if hasattr(request, 'context') and request.context.session:
|
||||
@ -54,8 +55,8 @@ class Controller(object):
|
||||
@utils.verify_session
|
||||
@normalize_path
|
||||
def post(self, request, environment_id, path, body):
|
||||
log.debug(_('Services:Post <EnvId: {0}, '
|
||||
'Body: {1}>'.format(environment_id, body)))
|
||||
log.debug(_('Services:Post <EnvId: {0}, , Path: {2}, '
|
||||
'Body: {1}>'.format(environment_id, body, path)))
|
||||
|
||||
post_data = CoreServices.post_data
|
||||
session_id = request.context.session
|
||||
@ -68,8 +69,8 @@ class Controller(object):
|
||||
@utils.verify_session
|
||||
@normalize_path
|
||||
def put(self, request, environment_id, path, body):
|
||||
log.debug(_('Services:Put <EnvId: {0}, '
|
||||
'Body: {1}>'.format(environment_id, body)))
|
||||
log.debug(_('Services:Put <EnvId: {0}, , Path: {2}, '
|
||||
'Body: {1}>'.format(environment_id, body, path)))
|
||||
|
||||
put_data = CoreServices.put_data
|
||||
session_id = request.context.session
|
||||
@ -80,6 +81,20 @@ class Controller(object):
|
||||
raise HTTPNotFound
|
||||
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():
|
||||
return wsgi.Resource(Controller())
|
||||
|
@ -20,16 +20,21 @@ from collections import deque
|
||||
from functools import wraps
|
||||
from muranoapi.openstack.common import log as logging
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TraverseHelper(object):
|
||||
value_type = (types.StringTypes, types.IntType, types.FloatType,
|
||||
types.BooleanType)
|
||||
|
||||
@staticmethod
|
||||
def get(path, source):
|
||||
"""
|
||||
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:
|
||||
|
||||
* each item should have id property
|
||||
* to select item from the list, specify id value
|
||||
|
||||
@ -49,24 +54,24 @@ class TraverseHelper(object):
|
||||
:return: object
|
||||
:raise: ValueError if object is malformed
|
||||
"""
|
||||
if path.startswith('/'):
|
||||
path = path[1:]
|
||||
|
||||
queue = deque(path.split('/'))
|
||||
obj = source
|
||||
queue = deque(filter(lambda x: x, path.split('/')))
|
||||
|
||||
while len(queue):
|
||||
path = queue.popleft()
|
||||
|
||||
if isinstance(obj, types.ListType):
|
||||
filtered = filter(lambda i: 'id' in i and i['id'] == path, obj)
|
||||
obj = filtered[0] if filtered else None
|
||||
elif isinstance(obj, types.DictionaryType):
|
||||
obj = obj[path] if path else obj
|
||||
if isinstance(source, types.ListType):
|
||||
idx_source = source
|
||||
source = next((i for i in source if i['id'] == path), None)
|
||||
if source is None and path.isdigit():
|
||||
source = idx_source[int(path)]
|
||||
elif isinstance(source, types.DictionaryType):
|
||||
source = source[path]
|
||||
elif isinstance(source, TraverseHelper.value_type):
|
||||
break
|
||||
else:
|
||||
raise ValueError('Object or path is malformed')
|
||||
raise ValueError('Source object or path is malformed')
|
||||
|
||||
return obj
|
||||
return source
|
||||
|
||||
@staticmethod
|
||||
def update(path, value, source):
|
||||
@ -91,11 +96,34 @@ class TraverseHelper(object):
|
||||
|
||||
:param path: string with path to desired value
|
||||
:param value: value
|
||||
:param source: python object (list or dict)
|
||||
:param source: List
|
||||
"""
|
||||
node = TraverseHelper.get(path, source)
|
||||
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):
|
||||
if isinstance(value, types.DictionaryType):
|
||||
|
@ -67,3 +67,13 @@ class CoreServices(object):
|
||||
save_description(session_id, env_description)
|
||||
|
||||
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
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import unittest2 as unittest
|
||||
from muranoapi.common.utils import TraverseHelper
|
||||
|
||||
|
||||
class TraverseHelperTests(unittest.TestCase):
|
||||
def test_simple_root_get(self):
|
||||
source = {"attr": True}
|
||||
def test_root_get_with_dict(self):
|
||||
source = {'attr': True}
|
||||
value = TraverseHelper.get('/', source)
|
||||
self.assertDictEqual(value, {"attr": True})
|
||||
self.assertDictEqual(value, source)
|
||||
|
||||
def test_simple_attribute_get(self):
|
||||
source = {"attr": True}
|
||||
def test_root_get_with_list(self):
|
||||
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)
|
||||
self.assertEqual(value, True)
|
||||
|
||||
def test_attribute_get(self):
|
||||
def test_nested_attribute_get(self):
|
||||
source = {'obj': {'attr': True}}
|
||||
value = TraverseHelper.get('/obj/attr', source)
|
||||
self.assertEqual(value, True)
|
||||
|
||||
def test_list_item_attribute_get_(self):
|
||||
def test_list_item_attribute_get(self):
|
||||
source = {'obj': [
|
||||
{'id': '1', 'value': 1},
|
||||
{'id': '2s', 'value': 2},
|
||||
@ -39,53 +50,64 @@ class TraverseHelperTests(unittest.TestCase):
|
||||
value = TraverseHelper.get('/obj/2s/value', source)
|
||||
self.assertEqual(value, 2)
|
||||
|
||||
def test_simple_attribute_set(self):
|
||||
source = {"attr": True}
|
||||
def test_list_item_attribute_get_by_index(self):
|
||||
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)
|
||||
value = TraverseHelper.get('/newAttr', source)
|
||||
self.assertEqual(value, False)
|
||||
|
||||
def test_simple_attribute_update(self):
|
||||
source = {"attr": True}
|
||||
def test_attribute_update(self):
|
||||
source = {'attr': True}
|
||||
TraverseHelper.update('/attr', False, source)
|
||||
value = TraverseHelper.get('/attr', source)
|
||||
self.assertEqual(value, False)
|
||||
|
||||
def test_attribute_update(self):
|
||||
source = {"obj": {"attr": True}}
|
||||
def test_nested_attribute_update(self):
|
||||
source = {'obj': {'attr': True}}
|
||||
TraverseHelper.update('/obj/attr', False, source)
|
||||
value = TraverseHelper.get('/obj/attr', source)
|
||||
self.assertEqual(value, False)
|
||||
|
||||
def test_simple_adding_item_to_list(self):
|
||||
source = {"attr": [1, 2, 3]}
|
||||
def test_adding_item_to_list(self):
|
||||
source = {'attr': [1, 2, 3]}
|
||||
TraverseHelper.insert('/attr', 4, source)
|
||||
value = TraverseHelper.get('/attr', source)
|
||||
self.assertListEqual(value, [1, 2, 3, 4])
|
||||
|
||||
def test_adding_item_to_list(self):
|
||||
source = {"obj": {"attr": [1, 2, 3]}}
|
||||
def test_nested_adding_item_to_list(self):
|
||||
source = {'obj': {'attr': [1, 2, 3]}}
|
||||
TraverseHelper.insert('/obj/attr', 4, source)
|
||||
value = TraverseHelper.get('/obj/attr', source)
|
||||
self.assertListEqual(value, [1, 2, 3, 4])
|
||||
|
||||
@unittest.skip
|
||||
def test_simple_attribute_remove(self):
|
||||
source = {"attr1": False, "attr2": True}
|
||||
def test_attribute_remove_from_dict(self):
|
||||
source = {'attr1': False, 'attr2': True}
|
||||
TraverseHelper.remove('/attr1', source)
|
||||
value = TraverseHelper.get('/', source)
|
||||
self.assertEqual(value, {"attr2": True})
|
||||
self.assertDictEqual(value, {'attr2': True})
|
||||
|
||||
@unittest.skip
|
||||
def test_nested_attribute_remove_from_object(self):
|
||||
source = {"obj": {"attr1": False, "attr2": True}}
|
||||
def test_nested_attribute_remove_from_dict(self):
|
||||
source = {'obj': {'attr1': False, 'attr2': True}}
|
||||
TraverseHelper.remove('/obj/attr1', 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(self):
|
||||
source = {"obj": [{"id": 'id1'}, {"id": 'id2'}]}
|
||||
def test_nested_attribute_remove_from_list_by_id(self):
|
||||
source = {'obj': [{'id': 'id1'}, {'id': 'id2'}]}
|
||||
TraverseHelper.remove('/obj/id1', source)
|
||||
value = TraverseHelper.get('/', source)
|
||||
self.assertListEqual(value, [{"id": 'id2'}])
|
||||
value = TraverseHelper.get('/obj', source)
|
||||
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…
Reference in New Issue
Block a user