summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Kearney <josh@jk0.org>2011-09-19 21:21:54 +0000
committerTarmac <>2011-09-19 21:21:54 +0000
commit682d358555e9f43acdb037cae5ad35a14d1cbcbd (patch)
tree5e2cef98a04ccd01a86d7ece7523716837e5df1c
parent3da916de6165e1e7012f61a05a6a0d9d06906b48 (diff)
parentbff43a5f0da9a891386d2d09464fb8f5e222d46d (diff)
downloadnova-682d358555e9f43acdb037cae5ad35a14d1cbcbd.tar.gz
nova-682d358555e9f43acdb037cae5ad35a14d1cbcbd.tar.xz
nova-682d358555e9f43acdb037cae5ad35a14d1cbcbd.zip
Adds the ability to automatically confirm resizes after the `resize_confirm_window` (0/disabled by default).
-rw-r--r--nova/compute/manager.py16
-rw-r--r--nova/db/api.py5
-rw-r--r--nova/db/sqlalchemy/api.py22
-rwxr-xr-xnova/network/linux_net.py1
-rw-r--r--nova/tests/test_db_api.py25
-rw-r--r--nova/tests/test_virt_drivers.py4
-rw-r--r--nova/virt/driver.py5
-rw-r--r--nova/virt/fake.py3
-rw-r--r--nova/virt/hyperv.py3
-rw-r--r--nova/virt/libvirt/connection.py4
-rw-r--r--nova/virt/xenapi/vmops.py23
-rw-r--r--nova/virt/xenapi_conn.py4
12 files changed, 109 insertions, 6 deletions
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 46c643aee..cb5d10f83 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -79,6 +79,9 @@ flags.DEFINE_integer('live_migration_retry_count', 30,
flags.DEFINE_integer("rescue_timeout", 0,
"Automatically unrescue an instance after N seconds."
" Set to 0 to disable.")
+flags.DEFINE_integer("resize_confirm_window", 0,
+ "Automatically confirm resizes after N seconds."
+ " Set to 0 to disable.")
flags.DEFINE_integer('host_state_interval', 120,
'Interval in seconds for querying the host status')
@@ -1648,14 +1651,23 @@ class ComputeManager(manager.SchedulerDependentManager):
self.driver.poll_rescued_instances(FLAGS.rescue_timeout)
except Exception as ex:
LOG.warning(_("Error during poll_rescued_instances: %s"),
- unicode(ex))
+ unicode(ex))
+ error_list.append(ex)
+
+ try:
+ if FLAGS.resize_confirm_window > 0:
+ self.driver.poll_unconfirmed_resizes(
+ FLAGS.resize_confirm_window)
+ except Exception as ex:
+ LOG.warning(_("Error during poll_unconfirmed_resizes: %s"),
+ unicode(ex))
error_list.append(ex)
try:
self._report_driver_status()
except Exception as ex:
LOG.warning(_("Error during report_driver_status(): %s"),
- unicode(ex))
+ unicode(ex))
error_list.append(ex)
try:
diff --git a/nova/db/api.py b/nova/db/api.py
index f68e1c48e..cdc7089cc 100644
--- a/nova/db/api.py
+++ b/nova/db/api.py
@@ -323,6 +323,11 @@ def migration_get_by_instance_and_status(context, instance_uuid, status):
status)
+def migration_get_all_unconfirmed(context, confirm_window):
+ """Finds all unconfirmed migrations within the confirmation window."""
+ return IMPL.migration_get_all_unconfirmed(context, confirm_window)
+
+
####################
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index c4bff8308..e7bd852f4 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -15,9 +15,10 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-"""
-Implementation of SQLAlchemy backend.
-"""
+
+"""Implementation of SQLAlchemy backend."""
+
+import datetime
import re
import warnings
@@ -3170,6 +3171,21 @@ def migration_get_by_instance_and_status(context, instance_uuid, status):
return result
+@require_admin_context
+def migration_get_all_unconfirmed(context, confirm_window, session=None):
+ confirm_window = datetime.datetime.utcnow() - datetime.timedelta(
+ seconds=confirm_window)
+
+ if not session:
+ session = get_session()
+
+ results = session.query(models.Migration).\
+ filter(models.Migration.updated_at <= confirm_window).\
+ filter_by(status="FINISHED").all()
+
+ return results
+
+
##################
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
index 2f9805fa3..9bf98fc27 100755
--- a/nova/network/linux_net.py
+++ b/nova/network/linux_net.py
@@ -824,7 +824,6 @@ class LinuxNetInterfaceDriver(object):
raise NotImplementedError()
-
# plugs interfaces using Linux Bridge
class LinuxBridgeInterfaceDriver(LinuxNetInterfaceDriver):
diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py
index 5ebab9cc8..35c2ed0e1 100644
--- a/nova/tests/test_db_api.py
+++ b/nova/tests/test_db_api.py
@@ -18,6 +18,8 @@
"""Unit tests for the DB API"""
+import datetime
+
from nova import test
from nova import context
from nova import db
@@ -95,3 +97,26 @@ class DbApiTestCase(test.TestCase):
self.assertEqual(result[0].id, inst1.id)
self.assertEqual(result[1].id, inst2.id)
self.assertTrue(result[0].deleted)
+
+ def test_migration_get_all_unconfirmed(self):
+ ctxt = context.get_admin_context()
+
+ # Ensure no migrations are returned.
+ results = db.migration_get_all_unconfirmed(ctxt, 10)
+ self.assertEqual(0, len(results))
+
+ # Ensure one migration older than 10 seconds is returned.
+ updated_at = datetime.datetime(2000, 01, 01, 12, 00, 00)
+ values = {"status": "FINISHED", "updated_at": updated_at}
+ migration = db.migration_create(ctxt, values)
+ results = db.migration_get_all_unconfirmed(ctxt, 10)
+ self.assertEqual(1, len(results))
+ db.migration_update(ctxt, migration.id, {"status": "CONFIRMED"})
+
+ # Ensure the new migration is not returned.
+ updated_at = datetime.datetime.utcnow()
+ values = {"status": "FINISHED", "updated_at": updated_at}
+ migration = db.migration_create(ctxt, values)
+ results = db.migration_get_all_unconfirmed(ctxt, 10)
+ self.assertEqual(0, len(results))
+ db.migration_update(ctxt, migration.id, {"status": "CONFIRMED"})
diff --git a/nova/tests/test_virt_drivers.py b/nova/tests/test_virt_drivers.py
index 440d3401b..8e20e999f 100644
--- a/nova/tests/test_virt_drivers.py
+++ b/nova/tests/test_virt_drivers.py
@@ -177,6 +177,10 @@ class _VirtDriverTestCase(test.TestCase):
self.connection.poll_rescued_instances(10)
@catch_notimplementederror
+ def test_poll_unconfirmed_resizes(self):
+ self.connection.poll_unconfirmed_resizes(10)
+
+ @catch_notimplementederror
def test_migrate_disk_and_power_off(self):
instance_ref = test_utils.get_test_instance()
network_info = test_utils.get_test_network_info()
diff --git a/nova/virt/driver.py b/nova/virt/driver.py
index 301346c6b..fc47d8d2d 100644
--- a/nova/virt/driver.py
+++ b/nova/virt/driver.py
@@ -469,6 +469,11 @@ class ComputeDriver(object):
# TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
+ def poll_unconfirmed_resizes(self, resize_confirm_window):
+ """Poll for unconfirmed resizes"""
+ # TODO(Vek): Need to pass context in for access to auth_token
+ raise NotImplementedError()
+
def host_power_action(self, host, action):
"""Reboots, shuts down or powers up the host."""
raise NotImplementedError()
diff --git a/nova/virt/fake.py b/nova/virt/fake.py
index 3596d8353..96f521ee7 100644
--- a/nova/virt/fake.py
+++ b/nova/virt/fake.py
@@ -130,6 +130,9 @@ class FakeConnection(driver.ComputeDriver):
def poll_rescued_instances(self, timeout):
pass
+ def poll_unconfirmed_resizes(self, resize_confirm_window):
+ pass
+
def migrate_disk_and_power_off(self, instance, dest):
pass
diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py
index 76925b405..fbf898317 100644
--- a/nova/virt/hyperv.py
+++ b/nova/virt/hyperv.py
@@ -487,6 +487,9 @@ class HyperVConnection(driver.ComputeDriver):
def poll_rescued_instances(self, timeout):
pass
+ def poll_unconfirmed_resizes(self, resize_confirm_window):
+ pass
+
def update_available_resource(self, ctxt, host):
"""This method is supported only by libvirt."""
return
diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py
index 4a0849127..b3c8ebf6e 100644
--- a/nova/virt/libvirt/connection.py
+++ b/nova/virt/libvirt/connection.py
@@ -588,6 +588,10 @@ class LibvirtConnection(driver.ComputeDriver):
def poll_rescued_instances(self, timeout):
pass
+ @exception.wrap_exception()
+ def poll_unconfirmed_resizes(self, resize_confirm_window):
+ pass
+
# NOTE(ilyaalekseyev): Implementation like in multinics
# for xenapi(tr3buchet)
@exception.wrap_exception()
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 8f7eb3795..210b8fe65 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -38,6 +38,7 @@ from nova import ipv6
from nova import log as logging
from nova import utils
+from nova.compute import api as compute
from nova.compute import power_state
from nova.virt import driver
from nova.virt.xenapi.network_utils import NetworkHelper
@@ -77,6 +78,7 @@ class VMOps(object):
"""
def __init__(self, session):
self.XenAPI = session.get_imported_xenapi()
+ self.compute_api = compute.API()
self._session = session
self.poll_rescue_last_ran = None
VMHelper.XenAPI = self.XenAPI
@@ -1039,6 +1041,27 @@ class VMOps(object):
self._session.call_xenapi("VM.start", original_vm_ref, False,
False)
+ def poll_unconfirmed_resizes(self, resize_confirm_window):
+ """Poll for unconfirmed resizes.
+
+ Look for any unconfirmed resizes that are older than
+ `resize_confirm_window` and automatically confirm them.
+ """
+ ctxt = nova_context.get_admin_context()
+ migrations = db.migration_get_all_unconfirmed(ctxt,
+ resize_confirm_window)
+
+ migrations_info = dict(migration_count=len(migrations),
+ confirm_window=FLAGS.resize_confirm_window)
+
+ if migrations_info["migration_count"] > 0:
+ LOG.info(_("Found %(migration_count)d unconfirmed migrations "
+ "older than %(confirm_window)d seconds") % migrations_info)
+
+ for migration in migrations:
+ LOG.info(_("Automatically confirming migration %d"), migration.id)
+ self.compute_api.confirm_resize(ctxt, migration.instance_uuid)
+
def get_info(self, instance):
"""Return data about VM instance."""
vm_ref = self._get_vm_opaque_ref(instance)
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index f6dbc19f8..7fc683a9f 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -254,6 +254,10 @@ class XenAPIConnection(driver.ComputeDriver):
"""Poll for rescued instances"""
self._vmops.poll_rescued_instances(timeout)
+ def poll_unconfirmed_resizes(self, resize_confirm_window):
+ """Poll for unconfirmed resizes"""
+ self._vmops.poll_unconfirmed_resizes(resize_confirm_window)
+
def reset_network(self, instance):
"""reset networking for specified instance"""
self._vmops.reset_network(instance)