summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvladimir.p <vladimir@zadarastorage.com>2011-08-11 11:54:35 -0700
committervladimir.p <vladimir@zadarastorage.com>2011-08-11 11:54:35 -0700
commitf9cf0d334330f034d0e0fb2ae8c88dda38e62832 (patch)
treecf887941a94a57b93effe2401e419e31762765ab
parentfe0bde67193ce76376e72a7263b89240a63722a8 (diff)
downloadnova-f9cf0d334330f034d0e0fb2ae8c88dda38e62832.tar.gz
nova-f9cf0d334330f034d0e0fb2ae8c88dda38e62832.tar.xz
nova-f9cf0d334330f034d0e0fb2ae8c88dda38e62832.zip
Added search instance by metadata. get_all_by_filters should filter deleted
-rw-r--r--Authors1
-rw-r--r--nova/db/sqlalchemy/api.py20
-rw-r--r--nova/tests/test_compute.py63
3 files changed, 83 insertions, 1 deletions
diff --git a/Authors b/Authors
index e639cbf76..ccd70baaf 100644
--- a/Authors
+++ b/Authors
@@ -103,6 +103,7 @@ Tushar Patil <tushar.vitthal.patil@gmail.com>
Vasiliy Shlykov <vash@vasiliyshlykov.org>
Vishvananda Ishaya <vishvananda@gmail.com>
Vivek Y S <vivek.ys@gmail.com>
+Vladimir Popovski <vladimir@zadarastorage.com>
William Wolf <throughnothing@gmail.com>
Yoshiaki Tamura <yoshi@midokura.jp>
Youcef Laribi <Youcef.Laribi@eu.citrix.com>
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 8119cdfb8..65977a8bf 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -1175,6 +1175,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)
@@ -1232,7 +1245,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 []
@@ -1248,6 +1263,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 73c9bd78d..18daa970e 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -1323,6 +1323,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',