summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvladimir.p <vladimir@zadarastorage.com>2011-08-16 17:34:38 +0000
committerTarmac <>2011-08-16 17:34:38 +0000
commit3df69958daa57f267cbce84e29d48bf69d79c509 (patch)
treefd39022376c97276aed5f0248fe99b0c5110ba07
parentcb967b7b726e0678ccb7f0c6fb7daf77c1aa3aab (diff)
parentf9cf0d334330f034d0e0fb2ae8c88dda38e62832 (diff)
downloadnova-3df69958daa57f267cbce84e29d48bf69d79c509.tar.gz
nova-3df69958daa57f267cbce84e29d48bf69d79c509.tar.xz
nova-3df69958daa57f267cbce84e29d48bf69d79c509.zip
* Added search instance by metadata.
* instance_get_all_by_filters should filter deleted
-rw-r--r--nova/db/sqlalchemy/api.py20
-rw-r--r--nova/tests/test_compute.py63
2 files changed, 82 insertions, 1 deletions
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 184ad60d5..95ec3f715 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -1178,6 +1178,19 @@ def instance_get_all_by_filters(context, filters):
return True
return False
+ def _regexp_filter_by_metadata(instance, meta):
+ inst_metadata = [{node['key']: node['value']} \
+ for node in instance['metadata']]
+ if isinstance(meta, list):
+ for node in meta:
+ if node not in inst_metadata:
+ return False
+ elif isinstance(meta, dict):
+ for k, v in meta.iteritems():
+ if {k: v} not in inst_metadata:
+ return False
+ return True
+
def _regexp_filter_by_column(instance, filter_name, filter_re):
try:
v = getattr(instance, filter_name)
@@ -1236,7 +1249,9 @@ def instance_get_all_by_filters(context, filters):
query_prefix = _exact_match_filter(query_prefix, filter_name,
filters.pop(filter_name))
- instances = query_prefix.all()
+ instances = query_prefix.\
+ filter_by(deleted=can_read_deleted(context)).\
+ all()
if not instances:
return []
@@ -1252,6 +1267,9 @@ def instance_get_all_by_filters(context, filters):
filter_re = re.compile(str(filters[filter_name]))
if filter_func:
filter_l = lambda instance: filter_func(instance, filter_re)
+ elif filter_name == 'metadata':
+ filter_l = lambda instance: _regexp_filter_by_metadata(instance,
+ filters[filter_name])
else:
filter_l = lambda instance: _regexp_filter_by_column(instance,
filter_name, filter_re)
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index e2fa3b140..4f5d36f14 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -1341,6 +1341,69 @@ class ComputeTestCase(test.TestCase):
db.instance_destroy(c, instance_id2)
db.instance_destroy(c, instance_id3)
+ def test_get_all_by_metadata(self):
+ """Test searching instances by metadata"""
+
+ c = context.get_admin_context()
+ instance_id0 = self._create_instance()
+ instance_id1 = self._create_instance({
+ 'metadata': {'key1': 'value1'}})
+ instance_id2 = self._create_instance({
+ 'metadata': {'key2': 'value2'}})
+ instance_id3 = self._create_instance({
+ 'metadata': {'key3': 'value3'}})
+ instance_id4 = self._create_instance({
+ 'metadata': {'key3': 'value3',
+ 'key4': 'value4'}})
+
+ # get all instances
+ instances = self.compute_api.get_all(c,
+ search_opts={'metadata': {}})
+ self.assertEqual(len(instances), 5)
+
+ # wrong key/value combination
+ instances = self.compute_api.get_all(c,
+ search_opts={'metadata': {'key1': 'value3'}})
+ self.assertEqual(len(instances), 0)
+
+ # non-existing keys
+ instances = self.compute_api.get_all(c,
+ search_opts={'metadata': {'key5': 'value1'}})
+ self.assertEqual(len(instances), 0)
+
+ # find existing instance
+ instances = self.compute_api.get_all(c,
+ search_opts={'metadata': {'key2': 'value2'}})
+ self.assertEqual(len(instances), 1)
+ self.assertEqual(instances[0].id, instance_id2)
+
+ instances = self.compute_api.get_all(c,
+ search_opts={'metadata': {'key3': 'value3'}})
+ self.assertEqual(len(instances), 2)
+ instance_ids = [instance.id for instance in instances]
+ self.assertTrue(instance_id3 in instance_ids)
+ self.assertTrue(instance_id4 in instance_ids)
+
+ # multiple criterias as a dict
+ instances = self.compute_api.get_all(c,
+ search_opts={'metadata': {'key3': 'value3',
+ 'key4': 'value4'}})
+ self.assertEqual(len(instances), 1)
+ self.assertEqual(instances[0].id, instance_id4)
+
+ # multiple criterias as a list
+ instances = self.compute_api.get_all(c,
+ search_opts={'metadata': [{'key4': 'value4'},
+ {'key3': 'value3'}]})
+ self.assertEqual(len(instances), 1)
+ self.assertEqual(instances[0].id, instance_id4)
+
+ db.instance_destroy(c, instance_id0)
+ db.instance_destroy(c, instance_id1)
+ db.instance_destroy(c, instance_id2)
+ db.instance_destroy(c, instance_id3)
+ db.instance_destroy(c, instance_id4)
+
@staticmethod
def _parse_db_block_device_mapping(bdm_ref):
attr_list = ('delete_on_termination', 'device_name', 'no_device',