diff options
| author | Sandy Walsh <sandy.walsh@rackspace.com> | 2011-05-26 12:00:15 -0700 |
|---|---|---|
| committer | Sandy Walsh <sandy.walsh@rackspace.com> | 2011-05-26 12:00:15 -0700 |
| commit | cc7aec17929414c58bbfdde609930e66e6f17028 (patch) | |
| tree | 32c3a7d1a554f1519edd9d4df53d38983ba12177 /nova/compute | |
| parent | c0cc56e3b7f00bc57316acfd92f2ceba4fc2be30 (diff) | |
| parent | cc51542911e4a34df75bd23a4a71a395e906e681 (diff) | |
branch 2a merge (including trunk)
Diffstat (limited to 'nova/compute')
| -rw-r--r-- | nova/compute/api.py | 47 | ||||
| -rw-r--r-- | nova/compute/manager.py | 21 |
2 files changed, 43 insertions, 25 deletions
diff --git a/nova/compute/api.py b/nova/compute/api.py index 032ef7469..52cff3d56 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -100,14 +100,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") @@ -139,9 +140,10 @@ 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, zone_blob=None): + injected_files=None, admin_password=None, zone_blob=None): """Verify all the input parameters regardless of the provisioning strategy being performed.""" + if not instance_type: instance_type = instance_types.get_default_instance_type() @@ -151,9 +153,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) @@ -262,6 +268,7 @@ class API(base.Base): def _ask_scheduler_to_create_instance(self, context, base_options, instance_type, zone_blob, availability_zone, injected_files, + admin_password, instance_id=None, num_instances=1): """Send the run_instance request to the schedulers for processing.""" pid = context.project_id @@ -289,6 +296,7 @@ class API(base.Base): "instance_id": instance_id, "request_spec": request_spec, "availability_zone": availability_zone, + "admin_password": admin_password, "injected_files": injected_files}}) def create_all_at_once(self, context, instance_type, @@ -297,7 +305,7 @@ 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, zone_blob=None): + injected_files=None, admin_password=None, zone_blob=None): """Provision the instances by passing the whole request to the Scheduler for execution. Returns a Reservation ID related to the creation of all of these instances.""" @@ -309,11 +317,12 @@ class API(base.Base): display_name, display_description, key_name, key_data, security_group, availability_zone, user_data, metadata, - injected_files, zone_blob) + injected_files, admin_password, zone_blob) self._ask_scheduler_to_create_instance(context, base_options, instance_type, zone_blob, availability_zone, injected_files, + admin_password, num_instances=num_instances) return base_options['reservation_id'] @@ -324,7 +333,7 @@ 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, zone_blob=None): + injected_files=None, admin_password=None, zone_blob=None): """ Provision the instances by sending off a series of single instance requests to the Schedulers. This is fine for trival @@ -342,7 +351,7 @@ class API(base.Base): display_name, display_description, key_name, key_data, security_group, availability_zone, user_data, metadata, - injected_files, zone_blob) + injected_files, admin_password, zone_blob) instances = [] LOG.debug(_("Going to run %s instances..."), num_instances) @@ -355,6 +364,7 @@ class API(base.Base): self._ask_scheduler_to_create_instance(context, base_options, instance_type, zone_blob, availability_zone, injected_files, + admin_password, instance_id=instance_id) return [dict(x.iteritems()) for x in instances] @@ -607,15 +617,6 @@ class API(base.Base): raise exception.Error(_("Unable to find host for Instance %s") % instance_id) - def _set_admin_password(self, context, instance_id, password): - """Set the root/admin password for the given instance.""" - host = self._find_host(context, instance_id) - - rpc.cast(context, - self.db.queue_get_for(context, FLAGS.compute_topic, host), - {"method": "set_admin_password", - "args": {"instance_id": instance_id, "new_pass": password}}) - def snapshot(self, context, instance_id, name): """Snapshot the given instance. @@ -769,8 +770,12 @@ class API(base.Base): def set_admin_password(self, context, instance_id, password=None): """Set the root/admin password for the given instance.""" - eventlet.spawn_n(self._set_admin_password, context, instance_id, - password) + host = self._find_host(context, instance_id) + + rpc.cast(context, + self.db.queue_get_for(context, FLAGS.compute_topic, host), + {"method": "set_admin_password", + "args": {"instance_id": instance_id, "new_pass": password}}) def inject_file(self, context, instance_id): """Write a file to the given instance.""" diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 11565c25e..d1e01f275 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -221,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, @@ -405,22 +406,28 @@ 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) @@ -436,6 +443,12 @@ class ComputeManager(manager.SchedulerDependentManager): 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 |
