summaryrefslogtreecommitdiffstats
path: root/nova/compute
diff options
context:
space:
mode:
authorMike Scherbakov <mihgen@gmail.com>2011-05-26 00:51:14 +0400
committerMike Scherbakov <mihgen@gmail.com>2011-05-26 00:51:14 +0400
commitfe77c55b7643bd9bd3bd988f7f759dde8af09cae (patch)
tree6d3a18d28fe54d2d1808ca8496f0ed04b32706cb /nova/compute
parent818c2424a0547882fe6bdfe6613ee66a248d91db (diff)
parentec0e674ce1a8539143e9b99deb8cc62b9d42d6b2 (diff)
Merged with trunk
Diffstat (limited to 'nova/compute')
-rw-r--r--nova/compute/api.py33
-rw-r--r--nova/compute/manager.py50
2 files changed, 69 insertions, 14 deletions
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 971c0732f..1a406bea8 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -19,6 +19,7 @@
"""Handles all requests relating to instances (guest vms)."""
import datetime
+import eventlet
import re
import time
@@ -42,6 +43,8 @@ LOG = logging.getLogger('nova.compute.api')
FLAGS = flags.FLAGS
flags.DECLARE('vncproxy_topic', 'nova.vnc')
+flags.DEFINE_integer('find_host_timeout', 30,
+ 'Timeout after NN seconds when looking for a host.')
def generate_default_hostname(instance_id):
@@ -92,14 +95,15 @@ class API(base.Base):
"""
if injected_files is None:
return
- limit = quota.allowed_injected_files(context)
+ limit = quota.allowed_injected_files(context, len(injected_files))
if len(injected_files) > limit:
raise quota.QuotaError(code="OnsetFileLimitExceeded")
path_limit = quota.allowed_injected_file_path_bytes(context)
- content_limit = quota.allowed_injected_file_content_bytes(context)
for path, content in injected_files:
if len(path) > path_limit:
raise quota.QuotaError(code="OnsetFilePathLimitExceeded")
+ content_limit = quota.allowed_injected_file_content_bytes(
+ context, len(content))
if len(content) > content_limit:
raise quota.QuotaError(code="OnsetFileContentLimitExceeded")
@@ -131,7 +135,8 @@ class API(base.Base):
display_name='', display_description='',
key_name=None, key_data=None, security_group='default',
availability_zone=None, user_data=None, metadata={},
- injected_files=None):
+ injected_files=None,
+ admin_password=None):
"""Create the number and type of instances requested.
Verifies that quota and other arguments are valid.
@@ -146,9 +151,13 @@ class API(base.Base):
pid = context.project_id
LOG.warn(_("Quota exceeeded for %(pid)s,"
" tried to run %(min_count)s instances") % locals())
- raise quota.QuotaError(_("Instance quota exceeded. You can only "
- "run %s more instances of this type.") %
- num_instances, "InstanceLimitExceeded")
+ if num_instances <= 0:
+ message = _("Instance quota exceeded. You cannot run any "
+ "more instances of this type.")
+ else:
+ message = _("Instance quota exceeded. You can only run %s "
+ "more instances of this type.") % num_instances
+ raise quota.QuotaError(message, "InstanceLimitExceeded")
self._check_metadata_properties_quota(context, metadata)
self._check_injected_file_quota(context, injected_files)
@@ -248,13 +257,21 @@ class API(base.Base):
uid = context.user_id
LOG.debug(_("Casting to scheduler for %(pid)s/%(uid)s's"
" instance %(instance_id)s") % locals())
+
+ # NOTE(sandy): For now we're just going to pass in the
+ # instance_type record to the scheduler. In a later phase
+ # we'll be ripping this whole for-loop out and deferring the
+ # creation of the Instance record. At that point all this will
+ # change.
rpc.cast(context,
FLAGS.scheduler_topic,
{"method": "run_instance",
"args": {"topic": FLAGS.compute_topic,
"instance_id": instance_id,
+ "instance_type": instance_type,
"availability_zone": availability_zone,
- "injected_files": injected_files}})
+ "injected_files": injected_files,
+ "admin_password": admin_password}})
for group_id in security_groups:
self.trigger_security_group_members_refresh(elevated, group_id)
@@ -484,7 +501,7 @@ class API(base.Base):
def _find_host(self, context, instance_id):
"""Find the host associated with an instance."""
- for attempts in xrange(10):
+ for attempts in xrange(FLAGS.find_host_timeout):
instance = self.get(context, instance_id)
host = instance["host"]
if host:
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index ae5b50ef3..d1e01f275 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -77,7 +77,8 @@ flags.DEFINE_integer("rescue_timeout", 0,
" Set to 0 to disable.")
flags.DEFINE_bool('auto_assign_floating_ip', False,
'Autoassigning floating ip to VM')
-
+flags.DEFINE_integer('host_state_interval', 120,
+ 'Interval in seconds for querying the host status')
LOG = logging.getLogger('nova.compute.manager')
@@ -131,6 +132,7 @@ class ComputeManager(manager.SchedulerDependentManager):
self.network_manager = utils.import_object(FLAGS.network_manager)
self.volume_manager = utils.import_object(FLAGS.volume_manager)
self.network_api = network.API()
+ self._last_host_check = 0
super(ComputeManager, self).__init__(service_name="compute",
*args, **kwargs)
@@ -219,6 +221,7 @@ class ComputeManager(manager.SchedulerDependentManager):
context = context.elevated()
instance_ref = self.db.instance_get(context, instance_id)
instance_ref.injected_files = kwargs.get('injected_files', [])
+ instance_ref.admin_pass = kwargs.get('admin_password', None)
if instance_ref['name'] in self.driver.list_instances():
raise exception.Error(_("Instance has already been created"))
LOG.audit(_("instance %s: starting..."), instance_id,
@@ -403,31 +406,49 @@ class ComputeManager(manager.SchedulerDependentManager):
@exception.wrap_exception
@checks_instance_lock
def set_admin_password(self, context, instance_id, new_pass=None):
- """Set the root/admin password for an instance on this host."""
+ """Set the root/admin password for an instance on this host.
+
+ This is generally only called by API password resets after an
+ image has been built.
+ """
+
context = context.elevated()
if new_pass is None:
# Generate a random password
new_pass = utils.generate_password(FLAGS.password_length)
- while True:
+ max_tries = 10
+
+ for i in xrange(max_tries):
instance_ref = self.db.instance_get(context, instance_id)
instance_id = instance_ref["id"]
instance_state = instance_ref["state"]
expected_state = power_state.RUNNING
if instance_state != expected_state:
- time.sleep(5)
- continue
+ raise exception.Error(_('Instance is not running'))
else:
try:
self.driver.set_admin_password(instance_ref, new_pass)
LOG.audit(_("Instance %s: Root password set"),
instance_ref["name"])
break
+ except NotImplementedError:
+ # NOTE(dprince): if the driver doesn't implement
+ # set_admin_password we break to avoid a loop
+ LOG.warn(_('set_admin_password is not implemented '
+ 'by this driver.'))
+ break
except Exception, e:
# Catch all here because this could be anything.
LOG.exception(e)
+ if i == max_tries - 1:
+ # At some point this exception may make it back
+ # to the API caller, and we don't want to reveal
+ # too much. The real exception is logged above
+ raise exception.Error(_('Internal error'))
+ time.sleep(1)
continue
@exception.wrap_exception
@@ -620,7 +641,7 @@ class ComputeManager(manager.SchedulerDependentManager):
instance_type = self.db.instance_type_get_by_flavor_id(context,
migration_ref['new_flavor_id'])
self.db.instance_update(context, instance_id,
- dict(instance_type=instance_type['name'],
+ dict(instance_type_id=instance_type['id'],
memory_mb=instance_type['memory_mb'],
vcpus=instance_type['vcpus'],
local_gb=instance_type['local_gb']))
@@ -1094,6 +1115,13 @@ class ComputeManager(manager.SchedulerDependentManager):
error_list.append(ex)
try:
+ self._report_driver_status()
+ except Exception as ex:
+ LOG.warning(_("Error during report_driver_status(): %s"),
+ unicode(ex))
+ error_list.append(ex)
+
+ try:
self._poll_instance_states(context)
except Exception as ex:
LOG.warning(_("Error during instance poll: %s"),
@@ -1102,6 +1130,16 @@ class ComputeManager(manager.SchedulerDependentManager):
return error_list
+ def _report_driver_status(self):
+ curr_time = time.time()
+ if curr_time - self._last_host_check > FLAGS.host_state_interval:
+ self._last_host_check = curr_time
+ LOG.info(_("Updating host status"))
+ # This will grab info about the host and queue it
+ # to be sent to the Schedulers.
+ self.update_service_capabilities(
+ self.driver.get_host_stats(refresh=True))
+
def _poll_instance_states(self, context):
vm_instances = self.driver.list_instances_detail()
vm_instances = dict((vm.name, vm) for vm in vm_instances)