summaryrefslogtreecommitdiffstats
path: root/nova/compute
diff options
context:
space:
mode:
Diffstat (limited to 'nova/compute')
-rw-r--r--nova/compute/api.py28
-rw-r--r--nova/compute/instance_types.py12
-rw-r--r--nova/compute/manager.py87
-rw-r--r--nova/compute/power_state.py21
4 files changed, 106 insertions, 42 deletions
diff --git a/nova/compute/api.py b/nova/compute/api.py
index c85f0f53a..be26d8ca3 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -32,6 +32,7 @@ from nova import rpc
from nova import utils
from nova import volume
from nova.compute import instance_types
+from nova.compute import power_state
from nova.scheduler import api as scheduler_api
from nova.db import base
@@ -501,6 +502,33 @@ class API(base.Base):
"""Reboot the given instance."""
self._cast_compute_message('reboot_instance', context, instance_id)
+ def rebuild(self, context, instance_id, image_id, metadata=None,
+ files_to_inject=None):
+ """Rebuild the given instance with the provided metadata."""
+ instance = db.api.instance_get(context, instance_id)
+
+ if instance["state"] == power_state.BUILDING:
+ msg = _("Instance already building")
+ raise exception.BuildInProgress(msg)
+
+ metadata = metadata or {}
+ self._check_metadata_properties_quota(context, metadata)
+
+ files_to_inject = files_to_inject or []
+ self._check_injected_file_quota(context, files_to_inject)
+
+ self.db.instance_update(context, instance_id, {"metadata": metadata})
+
+ rebuild_params = {
+ "image_id": image_id,
+ "injected_files": files_to_inject,
+ }
+
+ self._cast_compute_message('rebuild_instance',
+ context,
+ instance_id,
+ params=rebuild_params)
+
def revert_resize(self, context, instance_id):
"""Reverts a resize, deleting the 'new' instance in the process."""
context = context.elevated()
diff --git a/nova/compute/instance_types.py b/nova/compute/instance_types.py
index 7e7198b96..1275a6fdd 100644
--- a/nova/compute/instance_types.py
+++ b/nova/compute/instance_types.py
@@ -37,11 +37,11 @@ def create(name, memory, vcpus, local_gb, flavorid, swap=0,
try:
int(option)
except ValueError:
- raise exception.InvalidInputException(
- _("create arguments must be positive integers"))
+ raise exception.InvalidInput(reason=_("create arguments must "
+ "be positive integers"))
if (int(memory) <= 0) or (int(vcpus) <= 0) or (int(local_gb) < 0):
- raise exception.InvalidInputException(
- _("create arguments must be positive integers"))
+ raise exception.InvalidInput(reason=_("create arguments must "
+ "be positive integers"))
try:
db.instance_type_create(
@@ -64,7 +64,7 @@ def create(name, memory, vcpus, local_gb, flavorid, swap=0,
def destroy(name):
"""Marks instance types as deleted."""
if name is None:
- raise exception.InvalidInputException(_("No instance type specified"))
+ raise exception.InvalidInstanceType(instance_type=name)
else:
try:
db.instance_type_destroy(context.get_admin_context(), name)
@@ -76,7 +76,7 @@ def destroy(name):
def purge(name):
"""Removes instance types from database."""
if name is None:
- raise exception.InvalidInputException(_("No instance type specified"))
+ raise exception.InvalidInstanceType(instance_type=name)
else:
try:
db.instance_type_purge(context.get_admin_context(), name)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 93eb547ba..e698b0255 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -137,17 +137,33 @@ class ComputeManager(manager.SchedulerDependentManager):
"""Initialization for a standalone compute service."""
self.driver.init_host(host=self.host)
- def _update_state(self, context, instance_id):
+ def _update_state(self, context, instance_id, state=None):
"""Update the state of an instance from the driver info."""
- # FIXME(ja): include other fields from state?
instance_ref = self.db.instance_get(context, instance_id)
- try:
- info = self.driver.get_info(instance_ref['name'])
- state = info['state']
- except exception.NotFound:
- state = power_state.FAILED
+
+ if state is None:
+ try:
+ info = self.driver.get_info(instance_ref['name'])
+ except exception.NotFound:
+ info = None
+
+ if info is not None:
+ state = info['state']
+ else:
+ state = power_state.FAILED
+
self.db.instance_set_state(context, instance_id, state)
+ def _update_launched_at(self, context, instance_id, launched_at=None):
+ """Update the launched_at parameter of the given instance."""
+ data = {'launched_at': launched_at or datetime.datetime.utcnow()}
+ self.db.instance_update(context, instance_id, data)
+
+ def _update_image_id(self, context, instance_id, image_id):
+ """Update the image_id for the given instance."""
+ data = {'image_id': image_id}
+ self.db.instance_update(context, instance_id, data)
+
def get_console_topic(self, context, **kwargs):
"""Retrieves the console host for a project on this host.
@@ -231,24 +247,15 @@ class ComputeManager(manager.SchedulerDependentManager):
instance_id)
# TODO(vish) check to make sure the availability zone matches
- self.db.instance_set_state(context,
- instance_id,
- power_state.NOSTATE,
- 'spawning')
+ self._update_state(context, instance_id, power_state.BUILDING)
try:
self.driver.spawn(instance_ref)
- now = datetime.datetime.utcnow()
- self.db.instance_update(context,
- instance_id,
- {'launched_at': now})
- except Exception: # pylint: disable=W0702
- LOG.exception(_("Instance '%s' failed to spawn. Is virtualization"
- " enabled in the BIOS?"), instance_id,
- context=context)
- self.db.instance_set_state(context,
- instance_id,
- power_state.SHUTDOWN)
+ except Exception as ex: # pylint: disable=W0702
+ msg = _("Instance '%(instance_id)s' failed to spawn. Is "
+ "virtualization enabled in the BIOS? Details: "
+ "%(ex)s") % locals()
+ LOG.exception(msg)
if not FLAGS.stub_network and FLAGS.auto_assign_floating_ip:
public_ip = self.network_api.allocate_floating_ip(context)
@@ -262,6 +269,8 @@ class ComputeManager(manager.SchedulerDependentManager):
floating_ip,
fixed_ip,
affect_auto_assigned=True)
+
+ self._update_launched_at(context, instance_id)
self._update_state(context, instance_id)
@exception.wrap_exception
@@ -318,6 +327,33 @@ class ComputeManager(manager.SchedulerDependentManager):
@exception.wrap_exception
@checks_instance_lock
+ def rebuild_instance(self, context, instance_id, image_id):
+ """Destroy and re-make this instance.
+
+ A 'rebuild' effectively purges all existing data from the system and
+ remakes the VM with given 'metadata' and 'personalities'.
+
+ :param context: `nova.RequestContext` object
+ :param instance_id: Instance identifier (integer)
+ :param image_id: Image identifier (integer)
+ """
+ context = context.elevated()
+
+ instance_ref = self.db.instance_get(context, instance_id)
+ LOG.audit(_("Rebuilding instance %s"), instance_id, context=context)
+
+ self._update_state(context, instance_id, power_state.BUILDING)
+
+ self.driver.destroy(instance_ref)
+ instance_ref.image_id = image_id
+ self.driver.spawn(instance_ref)
+
+ self._update_image_id(context, instance_id, image_id)
+ self._update_launched_at(context, instance_id)
+ self._update_state(context, instance_id)
+
+ @exception.wrap_exception
+ @checks_instance_lock
def reboot_instance(self, context, instance_id):
"""Reboot an instance on this host."""
context = context.elevated()
@@ -1073,8 +1109,7 @@ class ComputeManager(manager.SchedulerDependentManager):
if vm_instance is None:
# NOTE(justinsb): We have to be very careful here, because a
# concurrent operation could be in progress (e.g. a spawn)
- if db_state == power_state.NOSTATE:
- # Assume that NOSTATE => spawning
+ if db_state == power_state.BUILDING:
# TODO(justinsb): This does mean that if we crash during a
# spawn, the machine will never leave the spawning state,
# but this is just the way nova is; this function isn't
@@ -1105,9 +1140,7 @@ class ComputeManager(manager.SchedulerDependentManager):
if vm_state != db_state:
LOG.info(_("DB/VM state mismatch. Changing state from "
"'%(db_state)s' to '%(vm_state)s'") % locals())
- self.db.instance_set_state(context,
- db_instance['id'],
- vm_state)
+ self._update_state(context, db_instance['id'], vm_state)
# NOTE(justinsb): We no longer auto-remove SHUTOFF instances
# It's quite hard to get them back when we do.
diff --git a/nova/compute/power_state.py b/nova/compute/power_state.py
index ef013b2ef..c468fe6b3 100644
--- a/nova/compute/power_state.py
+++ b/nova/compute/power_state.py
@@ -30,20 +30,23 @@ SHUTOFF = 0x05
CRASHED = 0x06
SUSPENDED = 0x07
FAILED = 0x08
+BUILDING = 0x09
# TODO(justinsb): Power state really needs to be a proper class,
# so that we're not locked into the libvirt status codes and can put mapping
# logic here rather than spread throughout the code
_STATE_MAP = {
- NOSTATE: 'pending',
- RUNNING: 'running',
- BLOCKED: 'blocked',
- PAUSED: 'paused',
- SHUTDOWN: 'shutdown',
- SHUTOFF: 'shutdown',
- CRASHED: 'crashed',
- SUSPENDED: 'suspended',
- FAILED: 'failed to spawn'}
+ NOSTATE: 'pending',
+ RUNNING: 'running',
+ BLOCKED: 'blocked',
+ PAUSED: 'paused',
+ SHUTDOWN: 'shutdown',
+ SHUTOFF: 'shutdown',
+ CRASHED: 'crashed',
+ SUSPENDED: 'suspended',
+ FAILED: 'failed to spawn',
+ BUILDING: 'building',
+}
def name(code):