From a81aae612f409bc767af3013eeccb71226831fc2 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Wed, 17 Aug 2011 11:19:34 -0400 Subject: Add modules for task and vm states. --- nova/compute/task_state.py | 28 ++++++++++++++++++++++++++++ nova/compute/vm_state.py | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 nova/compute/task_state.py create mode 100644 nova/compute/vm_state.py diff --git a/nova/compute/task_state.py b/nova/compute/task_state.py new file mode 100644 index 000000000..b4dc9af51 --- /dev/null +++ b/nova/compute/task_state.py @@ -0,0 +1,28 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""Possible task states for instances""" + +BUILD_BLOCK_DEVICE_MAPPING='block_device_mapping' +NETWORKING='networking' + +PASSWORD='password' + +RESIZE_PREP='resize_prep' +RESIZE_MIGRATING='resize_migrating' +RESIZE_MIGRATED='resize_migrated' +RESIZE_FINISH='resize_finish' diff --git a/nova/compute/vm_state.py b/nova/compute/vm_state.py new file mode 100644 index 000000000..e81cba1f0 --- /dev/null +++ b/nova/compute/vm_state.py @@ -0,0 +1,35 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""Possible vm states for instances""" + +BUILD='build' +REBUILD='rebuild' +REBOOT='reboot' +DELETE='delete' +STOP='stop' +START='start' +RESIZE='resize' +VERIFY_RESIZE='verify_resize' +PAUSE='pause' +UNPAUSE='unpause' + +SUSPEND='suspend' +RESUME='resume' + +RESCUE='rescue' +UNRESCUE='unrescue' -- cgit From 5270b0a565ec26d2f7de3a7d95be86433d8c6bd2 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Wed, 17 Aug 2011 11:46:28 -0400 Subject: Split set state into vm, task, and power state functions. --- nova/db/sqlalchemy/api.py | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 57a4370d8..07207b8ee 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1439,15 +1439,43 @@ def instance_get_floating_address(context, instance_id): @require_admin_context -def instance_set_state(context, instance_id, state, description=None): - # TODO(devcamcar): Move this out of models and into driver - from nova.compute import power_state - if not description: - description = power_state.name(state) - db.instance_update(context, - instance_id, - {'state': state, - 'state_description': description}) +def instance_set_power_state(context, instance_id, power_state): + session = get_session() + partial = session.query(models.Instance) + + if utils.is_uuid_like(instance_id): + result = partial.filter_by(uuid=instance_id) + else: + result = partial.filter_by(id=instance_id) + + result.update({'power_state': power_state}) + + +@require_admin_context +def instance_set_vm_state(context, instance_id, vm_state): + # vm_state = running, halted, suspended, paused + session = get_session() + partial = session.query(models.Instance) + + if utils.is_uuid_like(instance_id): + result = partial.filter_by(uuid=instance_id) + else: + result = partial.filter_by(id=instance_id) + + result.update({'vm_state': vm_state}) + + +def instance_set_task_state(context, instance_id, task_state): + # task_state = running, halted, suspended, paused + session = get_session() + partial = session.query(models.Instance) + + if utils.is_uuid_like(instance_id): + result = partial.filter_by(uuid=instance_id) + else: + result = partial.filter_by(id=instance_id) + + result.update({'task_state': task_state}) @require_context -- cgit From 6515b115de8cd026ea88aab796d4364ccc2ac4f0 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Wed, 17 Aug 2011 11:51:39 -0400 Subject: Pep8 fixes. --- nova/db/sqlalchemy/api.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 07207b8ee..e7d02cb5d 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1442,7 +1442,7 @@ def instance_get_floating_address(context, instance_id): def instance_set_power_state(context, instance_id, power_state): session = get_session() partial = session.query(models.Instance) - + if utils.is_uuid_like(instance_id): result = partial.filter_by(uuid=instance_id) else: @@ -1456,7 +1456,7 @@ def instance_set_vm_state(context, instance_id, vm_state): # vm_state = running, halted, suspended, paused session = get_session() partial = session.query(models.Instance) - + if utils.is_uuid_like(instance_id): result = partial.filter_by(uuid=instance_id) else: @@ -1469,7 +1469,7 @@ def instance_set_task_state(context, instance_id, task_state): # task_state = running, halted, suspended, paused session = get_session() partial = session.query(models.Instance) - + if utils.is_uuid_like(instance_id): result = partial.filter_by(uuid=instance_id) else: -- cgit From bd2e98c064b7c1e9c866f3013e13af7883e11e05 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Wed, 17 Aug 2011 13:30:47 -0400 Subject: Initial instance states migration. --- .../versions/037_update_instance_states.py | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/037_update_instance_states.py diff --git a/nova/db/sqlalchemy/migrate_repo/versions/037_update_instance_states.py b/nova/db/sqlalchemy/migrate_repo/versions/037_update_instance_states.py new file mode 100644 index 000000000..0bbe39def --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/037_update_instance_states.py @@ -0,0 +1,57 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from sqlalchemy import MetaData, Table + +meta = MetaData() + +c_task_state = Column('task_state', + String(length=255, convert_unicode=False, + assert_unicode=None, unicode_error=None, + _warn_on_bytestring=False), + nullable=True) + + +def upgrade(migrate_engine): + # Upgrade operations go here. Don't create your own engine; + # bind migrate_engine to your metadata + meta.bind = migrate_engine + + instances = Table('instances', meta, autoload=True, + autoload_with=migrate_engine) + + c_state = instances.c.state + c_state.alter(name='power_state') + + c_vm_state = instances.c.state_description + c_vm_state.alter(name='vm_state') + + instances.create_column(c_task_state) + + +def downgrade(migrate_engine): + meta.bind = migrate_engine + + instances = Table('instances', meta, autoload=True, + autoload_with=migrate_engine) + + c_state = instances.c.power_state + c_state.alter(name='state') + + c_vm_state = instances.c.vm_state + c_vm_state.alter(name='state_description') + + instances.drop_column('task_state') -- cgit From 1d1d027554d6be355bd9b52b2d87081d06f05045 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Wed, 17 Aug 2011 16:23:40 -0400 Subject: Updated compute manager/API to use vm/task states. Updated vm/task states to cover a few more cases I encountered. --- nova/compute/api.py | 57 ++++-- nova/compute/manager.py | 441 ++++++++++++++++++++++++--------------------- nova/compute/task_state.py | 17 +- nova/compute/vm_state.py | 8 +- 4 files changed, 296 insertions(+), 227 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index e909e9959..ec760853e 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -36,6 +36,7 @@ from nova import utils from nova import volume from nova.compute import instance_types from nova.compute import power_state +from nova.compute import vm_state from nova.compute.utils import terminate_volumes from nova.scheduler import api as scheduler_api from nova.db import base @@ -74,10 +75,13 @@ def generate_default_hostname(instance): def _is_able_to_shutdown(instance, instance_id): - states = {'terminating': "Instance %s is already being terminated", - 'migrating': "Instance %s is being migrated", - 'stopping': "Instance %s is being stopped"} - msg = states.get(instance['state_description']) + states = { + vm_state.DELETE: "Instance %s is already being terminated", + vm_state.MIGRATE: "Instance %s is being migrated", + vm_state.RESIZE: "Instance %s is being resized", + vm_state.STOP: "Instance %s is being stopped", + } + msg = states.get(instance['vm_state']) if msg: LOG.warning(_(msg), instance_id) return False @@ -231,8 +235,8 @@ class API(base.Base): 'image_ref': image_href, 'kernel_id': kernel_id or '', 'ramdisk_id': ramdisk_id or '', - 'state': 0, - 'state_description': 'scheduling', + 'power_state': power_state.NOSTATE, + 'vm_state': vm_state.BUILD, 'user_id': context.user_id, 'project_id': context.project_id, 'launch_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()), @@ -648,9 +652,8 @@ class API(base.Base): return self.update(context, - instance['id'], - state_description='terminating', - state=0, + instance_id, + vm_state=vm_state.DELETE, terminated_at=utils.utcnow()) host = instance['host'] @@ -671,9 +674,8 @@ class API(base.Base): return self.update(context, - instance['id'], - state_description='stopping', - state=power_state.NOSTATE, + instance_id, + vm_state=vm_state.STOP, terminated_at=utils.utcnow()) host = instance['host'] @@ -685,12 +687,15 @@ class API(base.Base): """Start an instance.""" LOG.debug(_("Going to try to start %s"), instance_id) instance = self._get_instance(context, instance_id, 'starting') - if instance['state_description'] != 'stopped': - _state_description = instance['state_description'] + vm_state = instance["vm_state"] + + if vm_state != vm_state.STOP: LOG.warning(_("Instance %(instance_id)s is not " - "stopped(%(_state_description)s)") % locals()) + "stopped. (%(vm_state)s)") % locals()) return + self.update(context, instance_id, vm_state=vm_state.ACTIVE) + # TODO(yamahata): injected_files isn't supported right now. # It is used only for osapi. not for ec2 api. # availability_zone isn't used by run_instance. @@ -918,6 +923,7 @@ class API(base.Base): @scheduler_api.reroute_compute("reboot") def reboot(self, context, instance_id): """Reboot the given instance.""" + self.update(context, instance_id, vm_state=vm_state.REBOOT) self._cast_compute_message('reboot_instance', context, instance_id) @scheduler_api.reroute_compute("rebuild") @@ -925,8 +931,12 @@ class API(base.Base): metadata=None, files_to_inject=None): """Rebuild the given instance with the provided metadata.""" instance = db.api.instance_get(context, instance_id) + invalid_rebuild_states = [ + vm_state.BUILD, + vm_state.REBUILD, + ] - if instance["state"] == power_state.BUILDING: + if instance["vm_state"] in invalid_rebuild_states: msg = _("Instance already building") raise exception.BuildInProgress(msg) @@ -946,6 +956,8 @@ class API(base.Base): "injected_files": files_to_inject, } + self.update(context, instance_id, vm_state=vm_state.REBUILD) + self._cast_compute_message('rebuild_instance', context, instance_id, @@ -963,6 +975,8 @@ class API(base.Base): raise exception.MigrationNotFoundByStatus(instance_id=instance_id, status='finished') + self.update(context, instance_id, vm_state=vm_state.ACTIVE) + params = {'migration_id': migration_ref['id']} self._cast_compute_message('revert_resize', context, instance_ref['uuid'], @@ -983,6 +997,9 @@ class API(base.Base): if not migration_ref: raise exception.MigrationNotFoundByStatus(instance_id=instance_id, status='finished') + + self.update(context, instance_id, vm_state=vm_state.ACTIVE) + params = {'migration_id': migration_ref['id']} self._cast_compute_message('confirm_resize', context, instance_ref['uuid'], @@ -1028,6 +1045,8 @@ class API(base.Base): if (current_memory_mb == new_memory_mb) and flavor_id: raise exception.CannotResizeToSameSize() + self.update(context, instance_id, vm_state=vm_state.RESIZE) + instance_ref = self._get_instance(context, instance_id, 'resize') self._cast_scheduler_message(context, {"method": "prep_resize", @@ -1061,11 +1080,13 @@ class API(base.Base): @scheduler_api.reroute_compute("pause") def pause(self, context, instance_id): """Pause the given instance.""" + self.update(context, instance_id, vm_state=vm_state.PAUSE) self._cast_compute_message('pause_instance', context, instance_id) @scheduler_api.reroute_compute("unpause") def unpause(self, context, instance_id): """Unpause the given instance.""" + self.update(context, instance_id, vm_state=vm_state.ACTIVE) self._cast_compute_message('unpause_instance', context, instance_id) def set_host_enabled(self, context, host, enabled): @@ -1092,21 +1113,25 @@ class API(base.Base): @scheduler_api.reroute_compute("suspend") def suspend(self, context, instance_id): """Suspend the given instance.""" + self.update(context, instance_id, vm_state=vm_state.SUSPEND) self._cast_compute_message('suspend_instance', context, instance_id) @scheduler_api.reroute_compute("resume") def resume(self, context, instance_id): """Resume the given instance.""" + self.update(context, instance_id, vm_state=vm_state.ACTIVE) self._cast_compute_message('resume_instance', context, instance_id) @scheduler_api.reroute_compute("rescue") def rescue(self, context, instance_id): """Rescue the given instance.""" + self.update(context, instance_id, vm_state=vm_state.RESCUE) self._cast_compute_message('rescue_instance', context, instance_id) @scheduler_api.reroute_compute("unrescue") def unrescue(self, context, instance_id): """Unrescue the given instance.""" + self.update(context, instance_id, vm_state=vm_state.ACTIVE) self._cast_compute_message('unrescue_instance', context, instance_id) @scheduler_api.reroute_compute("set_admin_password") diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 3299268f2..34c6bc1ea 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -56,6 +56,8 @@ from nova import rpc from nova import utils from nova import volume from nova.compute import power_state +from nova.compute import task_state +from nova.compute import vm_state from nova.notifier import api as notifier from nova.compute.utils import terminate_volumes from nova.virt import driver @@ -146,6 +148,10 @@ class ComputeManager(manager.SchedulerDependentManager): super(ComputeManager, self).__init__(service_name="compute", *args, **kwargs) + def _instance_update(self, context, instance_id, **kwargs): + """Update an instance in the database using kwargs as value.""" + return self.db.instance_update(context, instance_id, kwargs) + def init_host(self): """Initialization for a standalone compute service.""" self.driver.init_host(host=self.host) @@ -153,8 +159,8 @@ class ComputeManager(manager.SchedulerDependentManager): instances = self.db.instance_get_all_by_host(context, self.host) for instance in instances: inst_name = instance['name'] - db_state = instance['state'] - drv_state = self._update_state(context, instance['id']) + db_state = instance['power_state'] + drv_state = self._get_power_state(context, instance) expect_running = db_state == power_state.RUNNING \ and drv_state != db_state @@ -177,34 +183,13 @@ class ComputeManager(manager.SchedulerDependentManager): LOG.warning(_('Hypervisor driver does not ' 'support firewall rules')) - def _update_state(self, context, instance_id, state=None): - """Update the state of an instance from the driver info.""" - instance_ref = self.db.instance_get(context, instance_id) - - if state is None: - try: - LOG.debug(_('Checking state of %s'), instance_ref['name']) - 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) - return 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 utils.utcnow()} - self.db.instance_update(context, instance_id, data) - - def _update_image_ref(self, context, instance_id, image_ref): - """Update the image_id for the given instance.""" - data = {'image_ref': image_ref} - self.db.instance_update(context, instance_id, data) + def _get_power_state(self, context, instance): + """Retrieve the power state for the given instance.""" + LOG.debug(_('Checking state of %s'), instance['name']) + try: + return self.driver.get_info(instance['name'])["state"] + except exception.NotFound: + return power_state.FAILED def get_console_topic(self, context, **kwargs): """Retrieves the console host for a project on this host. @@ -388,13 +373,10 @@ class ComputeManager(manager.SchedulerDependentManager): # NOTE(vish): used by virt but not in database updates['injected_files'] = kwargs.get('injected_files', []) updates['admin_pass'] = kwargs.get('admin_password', None) - instance = self.db.instance_update(context, - instance_id, - updates) - self.db.instance_set_state(context, - instance_id, - power_state.NOSTATE, - 'networking') + updates['vm_state'] = vm_state.BUILD + updates['task_state'] = task_state.NETWORKING + + instance = self.db.instance_update(context, instance_id, updates) is_vpn = instance['image_ref'] == str(FLAGS.vpn_image_id) try: @@ -413,6 +395,11 @@ class ComputeManager(manager.SchedulerDependentManager): # all vif creation and network injection, maybe this is correct network_info = [] + self._instance_update(context, + instance_id, + vm_state=vm_state.BUILD, + task_state=task_state.BLOCK_DEVICE_MAPPING) + (swap, ephemerals, block_device_mapping) = self._setup_block_device_mapping( context, instance_id) @@ -422,9 +409,11 @@ class ComputeManager(manager.SchedulerDependentManager): 'ephemerals': ephemerals, 'block_device_mapping': block_device_mapping} - # TODO(vish) check to make sure the availability zone matches - self._update_state(context, instance_id, power_state.BUILDING) + self._instance_update(context, + instance_id, + task_state=task_state.SPAWN) + # TODO(vish) check to make sure the availability zone matches try: self.driver.spawn(context, instance, network_info, block_device_info) @@ -433,13 +422,21 @@ class ComputeManager(manager.SchedulerDependentManager): "virtualization enabled in the BIOS? Details: " "%(ex)s") % locals() LOG.exception(msg) + return + + current_power_state = self._get_power_state(context, instance) + self._instance_update(context, + instance_id, + power_state=current_power_state, + vm_state=vm_state.ACTIVE, + task_state=None, + launched_at=utils.utcnow()) - self._update_launched_at(context, instance_id) - self._update_state(context, instance_id) usage_info = utils.usage_from_instance(instance) notifier.notify('compute.%s' % self.host, 'compute.instance.create', notifier.INFO, usage_info) + except exception.InstanceNotFound: # FIXME(wwolf): We are just ignoring InstanceNotFound # exceptions here in case the instance was immediately @@ -523,11 +520,22 @@ class ComputeManager(manager.SchedulerDependentManager): 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) + current_power_state = self._get_power_state(context, instance_ref) + self._instance_update(context, + instance_id, + power_state=current_power_state, + vm_state=vm_state.REBUILD, + task_state=task_state.REBUILDING) network_info = self._get_instance_nw_info(context, instance_ref) - self.driver.destroy(instance_ref, network_info) + + self._instance_update(context, + instance_id, + power_state=current_power_state, + vm_state=vm_state.REBUILD, + task_state=task_state.SPAWN) + image_ref = kwargs.get('image_ref') instance_ref.image_ref = image_ref instance_ref.injected_files = kwargs.get('injected_files', []) @@ -536,9 +544,15 @@ class ComputeManager(manager.SchedulerDependentManager): bd_mapping = self._setup_block_device_mapping(context, instance_id) self.driver.spawn(context, instance_ref, network_info, bd_mapping) - self._update_image_ref(context, instance_id, image_ref) - self._update_launched_at(context, instance_id) - self._update_state(context, instance_id) + current_power_state = self._get_power_state(context, instance_ref) + self._instance_update(context, + instance_id, + power_state=current_power_state, + vm_state=vm_state.ACTIVE, + task_state=None, + image_ref=image_ref, + launched_at=utils.utcnow()) + usage_info = utils.usage_from_instance(instance_ref, image_ref=image_ref) notifier.notify('compute.%s' % self.host, @@ -550,26 +564,34 @@ class ComputeManager(manager.SchedulerDependentManager): @checks_instance_lock def reboot_instance(self, context, instance_id): """Reboot an instance on this host.""" + LOG.audit(_("Rebooting instance %s"), instance_id, context=context) context = context.elevated() - self._update_state(context, instance_id) instance_ref = self.db.instance_get(context, instance_id) - LOG.audit(_("Rebooting instance %s"), instance_id, context=context) - if instance_ref['state'] != power_state.RUNNING: - state = instance_ref['state'] + current_power_state = self._get_power_state(context, instance_ref) + self._instance_update(context, + instance_id, + power_state=current_power_state, + vm_state=vm_state.REBOOT, + task_state=task_state.REBOOTING) + + if instance_ref['power_state'] != power_state.RUNNING: + state = instance_ref['power_state'] running = power_state.RUNNING LOG.warn(_('trying to reboot a non-running ' 'instance: %(instance_id)s (state: %(state)s ' 'expected: %(running)s)') % locals(), context=context) - self.db.instance_set_state(context, - instance_id, - power_state.NOSTATE, - 'rebooting') network_info = self._get_instance_nw_info(context, instance_ref) self.driver.reboot(instance_ref, network_info) - self._update_state(context, instance_id) + + current_power_state = self._get_power_state(context, instance_ref) + self._instance_update(context, + instance_id, + power_state=current_power_state, + vm_state=vm_state.ACTIVE, + task_state=None) @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) def snapshot_instance(self, context, instance_id, image_id, @@ -585,37 +607,41 @@ class ComputeManager(manager.SchedulerDependentManager): :param rotation: int representing how many backups to keep around; None if rotation shouldn't be used (as in the case of snapshots) """ + if image_type != "snapshot" and image_type != "backup": + raise Exception(_('Image type not recognized %s') % image_type) + context = context.elevated() instance_ref = self.db.instance_get(context, instance_id) - #NOTE(sirp): update_state currently only refreshes the state field - # if we add is_snapshotting, we will need this refreshed too, - # potentially? - self._update_state(context, instance_id) + current_power_state = self._get_power_state(context, instance_ref) + self._instance_update(context, + instance_id, + power_state=current_power_state, + vm_state=vm_state.ACTIVE, + task_state=image_type) LOG.audit(_('instance %s: snapshotting'), instance_id, context=context) - if instance_ref['state'] != power_state.RUNNING: - state = instance_ref['state'] + + if instance_ref['power_state'] != power_state.RUNNING: + state = instance_ref['power_state'] running = power_state.RUNNING LOG.warn(_('trying to snapshot a non-running ' 'instance: %(instance_id)s (state: %(state)s ' 'expected: %(running)s)') % locals()) self.driver.snapshot(context, instance_ref, image_id) + self._instance_update(context, instance_id, task_state=None) + + if image_type == 'snapshot' and rotation: + raise exception.ImageRotationNotAllowed() + + elif image_type == 'backup' and rotation: + instance_uuid = instance_ref['uuid'] + self.rotate_backups(context, instance_uuid, backup_type, rotation) - if image_type == 'snapshot': - if rotation: - raise exception.ImageRotationNotAllowed() elif image_type == 'backup': - if rotation: - instance_uuid = instance_ref['uuid'] - self.rotate_backups(context, instance_uuid, backup_type, - rotation) - else: - raise exception.RotationRequiredForBackup() - else: - raise Exception(_('Image type not recognized %s') % image_type) + raise exception.RotationRequiredForBackup() def rotate_backups(self, context, instance_uuid, backup_type, rotation): """Delete excess backups associated to an instance. @@ -751,40 +777,51 @@ class ComputeManager(manager.SchedulerDependentManager): @checks_instance_lock def rescue_instance(self, context, instance_id): """Rescue an instance on this host.""" + LOG.audit(_('instance %s: rescuing'), instance_id, context=context) context = context.elevated() + + self._instance_update(context, + instance_id, + vm_state=vm_state.RESCUE, + task_state=task_state.RESCUING) + instance_ref = self.db.instance_get(context, instance_id) - LOG.audit(_('instance %s: rescuing'), instance_id, context=context) - self.db.instance_set_state(context, - instance_id, - power_state.NOSTATE, - 'rescuing') - _update_state = lambda result: self._update_state_callback( - self, context, instance_id, result) network_info = self._get_instance_nw_info(context, instance_ref) - self.driver.rescue(context, instance_ref, _update_state, network_info) - self._update_state(context, instance_id) + + # NOTE(blamar): None of the virt drivers use the 'callback' param + self.driver.rescue(context, instance_ref, None, network_info) + + current_power_state = self._get_power_state(context, instance_ref) + self._instance_update(context, + instance_id, + vm_state=vm_state.RESCUE, + task_state=task_state.RESCUED, + power_state=current_power_state) @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) @checks_instance_lock def unrescue_instance(self, context, instance_id): """Rescue an instance on this host.""" + LOG.audit(_('instance %s: unrescuing'), instance_id, context=context) context = context.elevated() + + self._instance_update(context, + instance_id, + vm_state=vm_state.ACTIVE, + task_state=task_state.UNRESCUING) + instance_ref = self.db.instance_get(context, instance_id) - LOG.audit(_('instance %s: unrescuing'), instance_id, context=context) - self.db.instance_set_state(context, - instance_id, - power_state.NOSTATE, - 'unrescuing') - _update_state = lambda result: self._update_state_callback( - self, context, instance_id, result) network_info = self._get_instance_nw_info(context, instance_ref) - self.driver.unrescue(instance_ref, _update_state, network_info) - self._update_state(context, instance_id) - @staticmethod - def _update_state_callback(self, context, instance_id, result): - """Update instance state when async task completes.""" - self._update_state(context, instance_id) + # NOTE(blamar): None of the virt drivers use the 'callback' param + self.driver.unrescue(instance_ref, None, network_info) + + current_power_state = self._get_power_state(context, instance_ref) + self._instance_update(context, + instance_id, + vm_state=vm_state.ACTIVE, + task_state=None, + power_state=current_power_state) @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) @checks_instance_lock @@ -843,11 +880,12 @@ class ComputeManager(manager.SchedulerDependentManager): # Just roll back the record. There's no need to resize down since # the 'old' VM already has the preferred attributes - self.db.instance_update(context, instance_ref['uuid'], - dict(memory_mb=instance_type['memory_mb'], - vcpus=instance_type['vcpus'], - local_gb=instance_type['local_gb'], - instance_type_id=instance_type['id'])) + self._instance_update(context, + instance_ref["uuid"], + memory_mb=instance_type['memory_mb'], + vcpus=instance_type['vcpus'], + local_gb=instance_type['local_gb'], + instance_type_id=instance_type['id']) self.driver.revert_migration(instance_ref) self.db.migration_update(context, migration_id, @@ -1000,35 +1038,45 @@ class ComputeManager(manager.SchedulerDependentManager): @checks_instance_lock def pause_instance(self, context, instance_id): """Pause an instance on this host.""" + LOG.audit(_('instance %s: pausing'), instance_id, context=context) context = context.elevated() + + self._instance_update(context, + instance_id, + vm_state=vm_state.PAUSE, + task_state=task_state.PAUSING) + instance_ref = self.db.instance_get(context, instance_id) - LOG.audit(_('instance %s: pausing'), instance_id, context=context) - self.db.instance_set_state(context, - instance_id, - power_state.NOSTATE, - 'pausing') - self.driver.pause(instance_ref, - lambda result: self._update_state_callback(self, - context, - instance_id, - result)) + self.driver.pause(instance_ref, lambda result: None) + + current_power_state = self._get_power_state(context, instance_ref) + self._instance_update(context, + instance_id, + power_state=current_power_state, + vm_state=vm_state.PAUSE, + task_state=None) @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) @checks_instance_lock def unpause_instance(self, context, instance_id): """Unpause a paused instance on this host.""" + LOG.audit(_('instance %s: unpausing'), instance_id, context=context) context = context.elevated() + + self._instance_update(context, + instance_id, + vm_state=vm_state.ACTIVE, + task_state=task_state.UNPAUSING) + instance_ref = self.db.instance_get(context, instance_id) - LOG.audit(_('instance %s: unpausing'), instance_id, context=context) - self.db.instance_set_state(context, - instance_id, - power_state.NOSTATE, - 'unpausing') - self.driver.unpause(instance_ref, - lambda result: self._update_state_callback(self, - context, - instance_id, - result)) + self.driver.unpause(instance_ref, lambda result: None) + + current_power_state = self._get_power_state(context, instance_ref) + self._instance_update(context, + instance_id, + power_state=current_power_state, + vm_state=vm_state.ACTIVE, + task_state=None) @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) def host_power_action(self, context, host=None, action=None): @@ -1053,33 +1101,45 @@ class ComputeManager(manager.SchedulerDependentManager): @checks_instance_lock def suspend_instance(self, context, instance_id): """Suspend the given instance.""" + LOG.audit(_('instance %s: suspending'), instance_id, context=context) context = context.elevated() + + self._instance_update(context, + instance_id, + vm_state=vm_state.SUSPEND, + task_state=task_state.SUSPENDING) + instance_ref = self.db.instance_get(context, instance_id) - LOG.audit(_('instance %s: suspending'), instance_id, context=context) - self.db.instance_set_state(context, instance_id, - power_state.NOSTATE, - 'suspending') - self.driver.suspend(instance_ref, - lambda result: self._update_state_callback(self, - context, - instance_id, - result)) + self.driver.suspend(instance_ref, lambda result: None) + + current_power_state = self._get_power_state(context, instance_ref) + self._instance_update(context, + instance_id, + power_state=current_power_state, + vm_state=vm_state.SUSPEND, + task_state=None) @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) @checks_instance_lock def resume_instance(self, context, instance_id): """Resume the given suspended instance.""" + LOG.audit(_('instance %s: resuming'), instance_id, context=context) context = context.elevated() + + self._instance_update(context, + instance_id, + vm_state=vm_state.ACTIVE, + task_state=task_state.RESUMING) + instance_ref = self.db.instance_get(context, instance_id) - LOG.audit(_('instance %s: resuming'), instance_id, context=context) - self.db.instance_set_state(context, instance_id, - power_state.NOSTATE, - 'resuming') - self.driver.resume(instance_ref, - lambda result: self._update_state_callback(self, - context, - instance_id, - result)) + self.driver.resume(instance_ref, lambda result: None) + + current_power_state = self._get_power_state(context, instance_ref) + self._instance_update(context, + instance_id, + power_state=current_power_state, + vm_state=vm_state.ACTIVE, + task_state=None) @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) def lock_instance(self, context, instance_id): @@ -1489,11 +1549,14 @@ class ComputeManager(manager.SchedulerDependentManager): 'block_migration': block_migration}}) # Restore instance state - self.db.instance_update(ctxt, - instance_ref['id'], - {'state_description': 'running', - 'state': power_state.RUNNING, - 'host': dest}) + current_power_state = self._get_power_state(ctxt, instance_ref) + self._instance_update(ctxt, + instance_ref["id"], + host=dest, + power_state=current_power_state, + vm_state=vm_state.ACTIVE, + task_state=None) + # Restore volume state for volume_ref in instance_ref['volumes']: volume_id = volume_ref['id'] @@ -1539,11 +1602,11 @@ class ComputeManager(manager.SchedulerDependentManager): This param specifies destination host. """ host = instance_ref['host'] - self.db.instance_update(context, - instance_ref['id'], - {'state_description': 'running', - 'state': power_state.RUNNING, - 'host': host}) + self._instance_update(context, + instance_ref['id'], + host=host, + vm_state=vm_state.ACTIVE, + task_state=None) for volume_ref in instance_ref['volumes']: volume_id = volume_ref['id'] @@ -1591,10 +1654,9 @@ class ComputeManager(manager.SchedulerDependentManager): error_list.append(ex) try: - self._poll_instance_states(context) + self._sync_power_states(context) except Exception as ex: - LOG.warning(_("Error during instance poll: %s"), - unicode(ex)) + LOG.warning(_("Error during power_state sync: %s"), unicode(ex)) error_list.append(ex) return error_list @@ -1609,68 +1671,39 @@ class ComputeManager(manager.SchedulerDependentManager): 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) + def _sync_power_states(self, context): + """Align power states between the database and the hypervisor. - # Keep a list of VMs not in the DB, cross them off as we find them - vms_not_found_in_db = list(vm_instances.keys()) + The hypervisor is authoritative for the power_state data, so we + simply loop over all known instances for this host and update the + power_state according to the hypervisor. If the instance is not found + then it will be set to power_state.NOSTATE, because it doesn't exist + on the hypervisor. + """ + vm_instances = self.driver.list_instances_detail() db_instances = self.db.instance_get_all_by_host(context, self.host) + num_vm_instances = len(vm_instances) + num_db_instances = len(db_instances) + + if num_vm_instances != num_db_instances: + LOG.info(_("Found %(num_db_instances)s in the database and " + "%(num_vm_instances)s on the hypervisor.") % locals()) + for db_instance in db_instances: - name = db_instance['name'] - db_state = db_instance['state'] + name = db_instance["name"] + db_power_state = db_instance['power_state'] vm_instance = vm_instances.get(name) 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.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 - # trying to correct that problem. - # We could have a separate task to correct this error. - # TODO(justinsb): What happens during a live migration? - LOG.info(_("Found instance '%(name)s' in DB but no VM. " - "State=%(db_state)s, so assuming spawn is in " - "progress.") % locals()) - vm_state = db_state - else: - LOG.info(_("Found instance '%(name)s' in DB but no VM. " - "State=%(db_state)s, so setting state to " - "shutoff.") % locals()) - vm_state = power_state.SHUTOFF - if db_instance['state_description'] == 'stopping': - self.db.instance_stop(context, db_instance['id']) - continue + vm_power_state = power_state.NOSTATE else: - vm_state = vm_instance.state - vms_not_found_in_db.remove(name) - - if (db_instance['state_description'] in ['migrating', 'stopping']): - # A situation which db record exists, but no instance" - # sometimes occurs while live-migration at src compute, - # this case should be ignored. - LOG.debug(_("Ignoring %(name)s, as it's currently being " - "migrated.") % locals()) - continue - - if vm_state != db_state: - LOG.info(_("DB/VM state mismatch. Changing state from " - "'%(db_state)s' to '%(vm_state)s'") % locals()) - self._update_state(context, db_instance['id'], vm_state) + vm_power_state = vm_instance["power_state"] - # NOTE(justinsb): We no longer auto-remove SHUTOFF instances - # It's quite hard to get them back when we do. - - # Are there VMs not in the DB? - for vm_not_found_in_db in vms_not_found_in_db: - name = vm_not_found_in_db + if vm_power_state == db_power_state: + continue - # We only care about instances that compute *should* know about - if name.startswith("instance-"): - # TODO(justinsb): What to do here? Adopt it? Shut it down? - LOG.warning(_("Found VM not in DB: '%(name)s'. Ignoring") - % locals()) + self._instance_update(context, + db_instance["id"], + power_state=vm_power_state) diff --git a/nova/compute/task_state.py b/nova/compute/task_state.py index b4dc9af51..55466c783 100644 --- a/nova/compute/task_state.py +++ b/nova/compute/task_state.py @@ -17,12 +17,27 @@ """Possible task states for instances""" -BUILD_BLOCK_DEVICE_MAPPING='block_device_mapping' +BLOCK_DEVICE_MAPPING='block_device_mapping' NETWORKING='networking' +SPAWN='spawn' +SNAPSHOT='snapshot' +BACKUP='backup' PASSWORD='password' RESIZE_PREP='resize_prep' RESIZE_MIGRATING='resize_migrating' RESIZE_MIGRATED='resize_migrated' RESIZE_FINISH='resize_finish' + +REBUILDING='rebuilding' + +REBOOTING='rebooting' +PAUSING='pausing' +UNPAUSING='unpausing' +SUSPENDING='suspending' +RESUMING='resuming' + +RESCUING='rescuing' +RESCUED='rescued' +UNRESCUING='unrescuing' diff --git a/nova/compute/vm_state.py b/nova/compute/vm_state.py index e81cba1f0..a1bca6ef4 100644 --- a/nova/compute/vm_state.py +++ b/nova/compute/vm_state.py @@ -17,19 +17,15 @@ """Possible vm states for instances""" +ACTIVE='active' BUILD='build' REBUILD='rebuild' REBOOT='reboot' DELETE='delete' STOP='stop' -START='start' +MIGRATE='migrate' RESIZE='resize' VERIFY_RESIZE='verify_resize' PAUSE='pause' -UNPAUSE='unpause' - SUSPEND='suspend' -RESUME='resume' - RESCUE='rescue' -UNRESCUE='unrescue' -- cgit From cab13dbfd652d1fcf9443e796e50f7eb374fc3fc Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Thu, 18 Aug 2011 12:34:01 -0400 Subject: Updated a number of items to pave the way for new states. --- nova/compute/manager.py | 31 +++++++++++----------- nova/db/sqlalchemy/api.py | 4 +-- .../versions/037_update_instance_states.py | 2 +- nova/db/sqlalchemy/models.py | 16 +++-------- nova/scheduler/driver.py | 11 ++++---- nova/tests/scheduler/test_scheduler.py | 13 ++++++--- nova/tests/test_compute.py | 29 ++++++++++---------- 7 files changed, 51 insertions(+), 55 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 34c6bc1ea..cb19a19cc 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -241,11 +241,6 @@ class ComputeManager(manager.SchedulerDependentManager): def _setup_block_device_mapping(self, context, instance_id): """setup volumes for block device mapping""" - self.db.instance_set_state(context, - instance_id, - power_state.NOSTATE, - 'block_device_mapping') - volume_api = volume.API() block_device_mapping = [] swap = None @@ -472,8 +467,7 @@ class ComputeManager(manager.SchedulerDependentManager): for volume in volumes: self._detach_volume(context, instance_id, volume['id'], False) - if (instance['state'] == power_state.SHUTOFF and - instance['state_description'] != 'stopped'): + if instance['power_state'] == power_state.SHUTOFF: self.db.instance_destroy(context, instance_id) raise exception.Error(_('trying to destroy already destroyed' ' instance: %s') % instance_id) @@ -532,16 +526,22 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, - power_state=current_power_state, vm_state=vm_state.REBUILD, - task_state=task_state.SPAWN) + task_state=task_state.BLOCK_DEVICE_MAPPING) + + bd_mapping = self._setup_block_device_mapping(context, instance_id) image_ref = kwargs.get('image_ref') instance_ref.image_ref = image_ref instance_ref.injected_files = kwargs.get('injected_files', []) network_info = self.network_api.get_instance_nw_info(context, - instance_ref) - bd_mapping = self._setup_block_device_mapping(context, instance_id) + instance_ref) + + self._instance_update(context, + instance_id, + vm_state=vm_state.REBUILD, + task_state=task_state.SPAWN) + self.driver.spawn(context, instance_ref, network_info, bd_mapping) current_power_state = self._get_power_state(context, instance_ref) @@ -709,7 +709,7 @@ class ComputeManager(manager.SchedulerDependentManager): 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"] + instance_state = instance_ref["power_state"] expected_state = power_state.RUNNING if instance_state != expected_state: @@ -744,7 +744,7 @@ class ComputeManager(manager.SchedulerDependentManager): context = context.elevated() instance_ref = self.db.instance_get(context, instance_id) instance_id = instance_ref['id'] - instance_state = instance_ref['state'] + instance_state = instance_ref['power_state'] expected_state = power_state.RUNNING if instance_state != expected_state: LOG.warn(_('trying to inject a file into a non-running ' @@ -762,7 +762,7 @@ class ComputeManager(manager.SchedulerDependentManager): context = context.elevated() instance_ref = self.db.instance_get(context, instance_id) instance_id = instance_ref['id'] - instance_state = instance_ref['state'] + instance_state = instance_ref['power_state'] expected_state = power_state.RUNNING if instance_state != expected_state: LOG.warn(_('trying to update agent on a non-running ' @@ -1092,7 +1092,7 @@ class ComputeManager(manager.SchedulerDependentManager): def get_diagnostics(self, context, instance_id): """Retrieve diagnostics for an instance on this host.""" instance_ref = self.db.instance_get(context, instance_id) - if instance_ref["state"] == power_state.RUNNING: + if instance_ref["power_state"] == power_state.RUNNING: LOG.audit(_("instance %s: retrieving diagnostics"), instance_id, context=context) return self.driver.get_diagnostics(instance_ref) @@ -1682,6 +1682,7 @@ class ComputeManager(manager.SchedulerDependentManager): """ vm_instances = self.driver.list_instances_detail() + vm_instances = dict((vm.name, vm) for vm in vm_instances) db_instances = self.db.instance_get_all_by_host(context, self.host) num_vm_instances = len(vm_instances) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index e7d02cb5d..67736dea2 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1079,8 +1079,8 @@ def instance_stop(context, instance_id): session.query(models.Instance).\ filter_by(id=instance_id).\ update({'host': None, - 'state': power_state.SHUTOFF, - 'state_description': 'stopped', + 'vm_state': vm_state.STOP, + 'task_state': None, 'updated_at': literal_column('updated_at')}) session.query(models.SecurityGroupInstanceAssociation).\ filter_by(instance_id=instance_id).\ diff --git a/nova/db/sqlalchemy/migrate_repo/versions/037_update_instance_states.py b/nova/db/sqlalchemy/migrate_repo/versions/037_update_instance_states.py index 0bbe39def..07efbf90f 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/037_update_instance_states.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/037_update_instance_states.py @@ -14,7 +14,7 @@ # License for the specific language governing permissions and limitations # under the License. -from sqlalchemy import MetaData, Table +from sqlalchemy import MetaData, Table, Column, String meta = MetaData() diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index f2a4680b0..d2987cacc 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -193,8 +193,9 @@ class Instance(BASE, NovaBase): key_name = Column(String(255)) key_data = Column(Text) - state = Column(Integer) - state_description = Column(String(255)) + power_state = Column(Integer) + vm_state = Column(String(255)) + task_state = Column(String(255)) memory_mb = Column(Integer) vcpus = Column(Integer) @@ -232,17 +233,6 @@ class Instance(BASE, NovaBase): root_device_name = Column(String(255)) - # TODO(vish): see Ewan's email about state improvements, probably - # should be in a driver base class or some such - # vmstate_state = running, halted, suspended, paused - # power_state = what we have - # task_state = transitory and may trigger power state transition - - #@validates('state') - #def validate_state(self, key, state): - # assert(state in ['nostate', 'running', 'blocked', 'paused', - # 'shutdown', 'shutoff', 'crashed']) - class InstanceActions(BASE, NovaBase): """Represents a guest VM's actions and results""" diff --git a/nova/scheduler/driver.py b/nova/scheduler/driver.py index f28353f05..b788b996f 100644 --- a/nova/scheduler/driver.py +++ b/nova/scheduler/driver.py @@ -30,6 +30,8 @@ from nova import log as logging from nova import rpc from nova import utils from nova.compute import power_state +from nova.compute import task_state +from nova.compute import vm_state from nova.api.ec2 import ec2utils @@ -104,10 +106,8 @@ class Scheduler(object): dest, block_migration) # Changing instance_state. - db.instance_set_state(context, - instance_id, - power_state.PAUSED, - 'migrating') + values = {"vm_state": vm_state.MIGRATE} + db.instance_update(context, instance_id, values) # Changing volume state for volume_ref in instance_ref['volumes']: @@ -129,8 +129,7 @@ class Scheduler(object): """ # Checking instance is running. - if (power_state.RUNNING != instance_ref['state'] or \ - 'running' != instance_ref['state_description']): + if instance_ref['power_state'] != power_state.RUNNING: instance_id = ec2utils.id_to_ec2_id(instance_ref['id']) raise exception.InstanceNotRunning(instance_id=instance_id) diff --git a/nova/tests/scheduler/test_scheduler.py b/nova/tests/scheduler/test_scheduler.py index 158df2a27..1b5e131c9 100644 --- a/nova/tests/scheduler/test_scheduler.py +++ b/nova/tests/scheduler/test_scheduler.py @@ -40,6 +40,7 @@ from nova.scheduler import driver from nova.scheduler import manager from nova.scheduler import multi from nova.compute import power_state +from nova.compute import vm_state FLAGS = flags.FLAGS @@ -94,6 +95,9 @@ class SchedulerTestCase(test.TestCase): inst['vcpus'] = kwargs.get('vcpus', 1) inst['memory_mb'] = kwargs.get('memory_mb', 10) inst['local_gb'] = kwargs.get('local_gb', 20) + inst['vm_state'] = kwargs.get('vm_state', vm_state.ACTIVE) + inst['power_state'] = kwargs.get('power_state', power_state.RUNNING) + inst['task_state'] = kwargs.get('task_state', None) return db.instance_create(ctxt, inst) def test_fallback(self): @@ -271,8 +275,9 @@ class SimpleDriverTestCase(test.TestCase): inst['memory_mb'] = kwargs.get('memory_mb', 20) inst['local_gb'] = kwargs.get('local_gb', 30) inst['launched_on'] = kwargs.get('launghed_on', 'dummy') - inst['state_description'] = kwargs.get('state_description', 'running') - inst['state'] = kwargs.get('state', power_state.RUNNING) + inst['vm_state'] = kwargs.get('vm_state', vm_state.ACTIVE) + inst['task_state'] = kwargs.get('task_state', None) + inst['power_state'] = kwargs.get('power_state', power_state.RUNNING) return db.instance_create(self.context, inst)['id'] def _create_volume(self): @@ -664,14 +669,14 @@ class SimpleDriverTestCase(test.TestCase): block_migration=False) i_ref = db.instance_get(self.context, instance_id) - self.assertTrue(i_ref['state_description'] == 'migrating') + self.assertTrue(i_ref['vm_state'] == vm_state.MIGRATE) db.instance_destroy(self.context, instance_id) db.volume_destroy(self.context, v_ref['id']) def test_live_migration_src_check_instance_not_running(self): """The instance given by instance_id is not running.""" - instance_id = self._create_instance(state_description='migrating') + instance_id = self._create_instance(power_state=power_state.NOSTATE) i_ref = db.instance_get(self.context, instance_id) try: diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index e2fa3b140..f310eaff6 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -23,6 +23,7 @@ from nova import compute from nova.compute import instance_types from nova.compute import manager as compute_manager from nova.compute import power_state +from nova.compute import vm_state from nova import context from nova import db from nova.db.sqlalchemy import models @@ -747,8 +748,8 @@ class ComputeTestCase(test.TestCase): 'block_migration': False, 'disk': None}}).\ AndRaise(rpc.RemoteError('', '', '')) - dbmock.instance_update(c, i_ref['id'], {'state_description': 'running', - 'state': power_state.RUNNING, + dbmock.instance_update(c, i_ref['id'], {'vm_state': vm_state.ACTIVE, + 'task_state': None, 'host': i_ref['host']}) for v in i_ref['volumes']: dbmock.volume_update(c, v['id'], {'status': 'in-use'}) @@ -779,8 +780,8 @@ class ComputeTestCase(test.TestCase): 'block_migration': False, 'disk': None}}).\ AndRaise(rpc.RemoteError('', '', '')) - dbmock.instance_update(c, i_ref['id'], {'state_description': 'running', - 'state': power_state.RUNNING, + dbmock.instance_update(c, i_ref['id'], {'vm_state': vm_state.ACTIVE, + 'task_state': None, 'host': i_ref['host']}) self.compute.db = dbmock @@ -825,8 +826,8 @@ class ComputeTestCase(test.TestCase): c = context.get_admin_context() instance_id = self._create_instance() i_ref = db.instance_get(c, instance_id) - db.instance_update(c, i_ref['id'], {'state_description': 'migrating', - 'state': power_state.PAUSED}) + db.instance_update(c, i_ref['id'], {'vm_state': vm_state.MIGRATE, + 'power_state': power_state.PAUSED}) v_ref = db.volume_create(c, {'size': 1, 'instance_id': instance_id}) fix_addr = db.fixed_ip_create(c, {'address': '1.1.1.1', 'instance_id': instance_id}) @@ -887,7 +888,7 @@ class ComputeTestCase(test.TestCase): instances = db.instance_get_all(context.get_admin_context()) LOG.info(_("After force-killing instances: %s"), instances) self.assertEqual(len(instances), 1) - self.assertEqual(power_state.SHUTOFF, instances[0]['state']) + self.assertEqual(power_state.NOSTATE, instances[0]['power_state']) def test_get_all_by_name_regexp(self): """Test searching instances by name (display_name)""" @@ -1307,25 +1308,25 @@ class ComputeTestCase(test.TestCase): """Test searching instances by state""" c = context.get_admin_context() - instance_id1 = self._create_instance({'state': power_state.SHUTDOWN}) + instance_id1 = self._create_instance({'power_state': power_state.SHUTDOWN}) instance_id2 = self._create_instance({ 'id': 2, - 'state': power_state.RUNNING}) + 'power_state': power_state.RUNNING}) instance_id3 = self._create_instance({ 'id': 10, - 'state': power_state.RUNNING}) + 'power_state': power_state.RUNNING}) instances = self.compute_api.get_all(c, - search_opts={'state': power_state.SUSPENDED}) + search_opts={'power_state': power_state.SUSPENDED}) self.assertEqual(len(instances), 0) instances = self.compute_api.get_all(c, - search_opts={'state': power_state.SHUTDOWN}) + search_opts={'power_state': power_state.SHUTDOWN}) self.assertEqual(len(instances), 1) self.assertEqual(instances[0].id, instance_id1) instances = self.compute_api.get_all(c, - search_opts={'state': power_state.RUNNING}) + search_opts={'power_state': power_state.RUNNING}) self.assertEqual(len(instances), 2) instance_ids = [instance.id for instance in instances] self.assertTrue(instance_id2 in instance_ids) @@ -1333,7 +1334,7 @@ class ComputeTestCase(test.TestCase): # Test passing a list as search arg instances = self.compute_api.get_all(c, - search_opts={'state': [power_state.SHUTDOWN, + search_opts={'power_state': [power_state.SHUTDOWN, power_state.RUNNING]}) self.assertEqual(len(instances), 3) -- cgit From 9b96b24ec93864731b6fc5031d2eceb22398be24 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Fri, 19 Aug 2011 09:30:52 -0400 Subject: Bump migration number. --- .../versions/037_update_instance_states.py | 57 ---------------------- .../versions/039_update_instance_states.py | 57 ++++++++++++++++++++++ 2 files changed, 57 insertions(+), 57 deletions(-) delete mode 100644 nova/db/sqlalchemy/migrate_repo/versions/037_update_instance_states.py create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/039_update_instance_states.py diff --git a/nova/db/sqlalchemy/migrate_repo/versions/037_update_instance_states.py b/nova/db/sqlalchemy/migrate_repo/versions/037_update_instance_states.py deleted file mode 100644 index 07efbf90f..000000000 --- a/nova/db/sqlalchemy/migrate_repo/versions/037_update_instance_states.py +++ /dev/null @@ -1,57 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010 OpenStack LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from sqlalchemy import MetaData, Table, Column, String - -meta = MetaData() - -c_task_state = Column('task_state', - String(length=255, convert_unicode=False, - assert_unicode=None, unicode_error=None, - _warn_on_bytestring=False), - nullable=True) - - -def upgrade(migrate_engine): - # Upgrade operations go here. Don't create your own engine; - # bind migrate_engine to your metadata - meta.bind = migrate_engine - - instances = Table('instances', meta, autoload=True, - autoload_with=migrate_engine) - - c_state = instances.c.state - c_state.alter(name='power_state') - - c_vm_state = instances.c.state_description - c_vm_state.alter(name='vm_state') - - instances.create_column(c_task_state) - - -def downgrade(migrate_engine): - meta.bind = migrate_engine - - instances = Table('instances', meta, autoload=True, - autoload_with=migrate_engine) - - c_state = instances.c.power_state - c_state.alter(name='state') - - c_vm_state = instances.c.vm_state - c_vm_state.alter(name='state_description') - - instances.drop_column('task_state') diff --git a/nova/db/sqlalchemy/migrate_repo/versions/039_update_instance_states.py b/nova/db/sqlalchemy/migrate_repo/versions/039_update_instance_states.py new file mode 100644 index 000000000..07efbf90f --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/039_update_instance_states.py @@ -0,0 +1,57 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from sqlalchemy import MetaData, Table, Column, String + +meta = MetaData() + +c_task_state = Column('task_state', + String(length=255, convert_unicode=False, + assert_unicode=None, unicode_error=None, + _warn_on_bytestring=False), + nullable=True) + + +def upgrade(migrate_engine): + # Upgrade operations go here. Don't create your own engine; + # bind migrate_engine to your metadata + meta.bind = migrate_engine + + instances = Table('instances', meta, autoload=True, + autoload_with=migrate_engine) + + c_state = instances.c.state + c_state.alter(name='power_state') + + c_vm_state = instances.c.state_description + c_vm_state.alter(name='vm_state') + + instances.create_column(c_task_state) + + +def downgrade(migrate_engine): + meta.bind = migrate_engine + + instances = Table('instances', meta, autoload=True, + autoload_with=migrate_engine) + + c_state = instances.c.power_state + c_state.alter(name='state') + + c_vm_state = instances.c.vm_state + c_vm_state.alter(name='state_description') + + instances.drop_column('task_state') -- cgit From 3bd386cdba53f6a54a29e510c0f9eecf9b9ea7d9 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Fri, 19 Aug 2011 15:13:40 -0400 Subject: vm_state --> vm_states --- nova/api/ec2/cloud.py | 24 ++++++++-------- nova/compute/api.py | 46 +++++++++++++++---------------- nova/compute/manager.py | 50 +++++++++++++++++----------------- nova/compute/vm_state.py | 31 --------------------- nova/compute/vm_states.py | 31 +++++++++++++++++++++ nova/scheduler/driver.py | 4 +-- nova/tests/scheduler/test_scheduler.py | 2 +- nova/tests/test_compute.py | 8 +++--- 8 files changed, 98 insertions(+), 98 deletions(-) delete mode 100644 nova/compute/vm_state.py create mode 100644 nova/compute/vm_states.py diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 9aebf92e3..4b69cc272 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -47,6 +47,7 @@ from nova import utils from nova import volume from nova.api.ec2 import ec2utils from nova.compute import instance_types +from nova.compute import vm_states from nova.image import s3 @@ -1039,11 +1040,10 @@ class CloudController(object): def _format_attr_instance_initiated_shutdown_behavior(instance, result): - state_description = instance['state_description'] - state_to_value = {'stopping': 'stop', - 'stopped': 'stop', - 'terminating': 'terminate'} - value = state_to_value.get(state_description) + vm_state = instance['vm_state'] + state_to_value = {vm_states.STOP: 'stop', + vm_states.DELETE: 'terminate'} + value = state_to_value.get(vm_state) if value: result['instanceInitiatedShutdownBehavior'] = value @@ -1198,8 +1198,8 @@ class CloudController(object): self._format_kernel_id(instance, i, 'kernelId') self._format_ramdisk_id(instance, i, 'ramdiskId') i['instanceState'] = { - 'code': instance['state'], - 'name': instance['state_description']} + 'code': instance['power_state'], + 'name': instance['vm_state']} #FIXME fixed_addr = None floating_addr = None if instance['fixed_ips']: @@ -1618,22 +1618,22 @@ class CloudController(object): # stop the instance if necessary restart_instance = False if not no_reboot: - state_description = instance['state_description'] + vm_state = instance['vm_state'] # if the instance is in subtle state, refuse to proceed. - if state_description not in ('running', 'stopping', 'stopped'): + if vm_state not in (vm_states.ACTIVE, vm_states.STOP): raise exception.InstanceNotRunning(instance_id=ec2_instance_id) - if state_description == 'running': + if vm_state == vm_states.ACTIVE: restart_instance = True self.compute_api.stop(context, instance_id=instance_id) # wait instance for really stopped start_time = time.time() - while state_description != 'stopped': + while vm_state != vm_states.STOP: time.sleep(1) instance = self.compute_api.get(context, instance_id) - state_description = instance['state_description'] + vm_state = instance['vm_state'] # NOTE(yamahata): timeout and error. 1 hour for now for safety. # Is it too short/long? # Or is there any better way? diff --git a/nova/compute/api.py b/nova/compute/api.py index 77397f90e..8634ad27a 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -36,7 +36,7 @@ from nova import utils from nova import volume from nova.compute import instance_types from nova.compute import power_state -from nova.compute import vm_state +from nova.compute import vm_states from nova.compute.utils import terminate_volumes from nova.scheduler import api as scheduler_api from nova.db import base @@ -76,10 +76,10 @@ def generate_default_hostname(instance): def _is_able_to_shutdown(instance, instance_id): states = { - vm_state.DELETE: "Instance %s is already being terminated", - vm_state.MIGRATE: "Instance %s is being migrated", - vm_state.RESIZE: "Instance %s is being resized", - vm_state.STOP: "Instance %s is being stopped", + vm_states.DELETE: "Instance %s is already being terminated", + vm_states.MIGRATE: "Instance %s is being migrated", + vm_states.RESIZE: "Instance %s is being resized", + vm_states.STOP: "Instance %s is being stopped", } msg = states.get(instance['vm_state']) if msg: @@ -236,7 +236,7 @@ class API(base.Base): 'kernel_id': kernel_id or '', 'ramdisk_id': ramdisk_id or '', 'power_state': power_state.NOSTATE, - 'vm_state': vm_state.BUILD, + 'vm_state': vm_states.BUILD, 'user_id': context.user_id, 'project_id': context.project_id, 'launch_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()), @@ -653,7 +653,7 @@ class API(base.Base): self.update(context, instance_id, - vm_state=vm_state.DELETE, + vm_state=vm_states.DELETE, terminated_at=utils.utcnow()) host = instance['host'] @@ -675,7 +675,7 @@ class API(base.Base): self.update(context, instance_id, - vm_state=vm_state.STOP, + vm_state=vm_states.STOP, terminated_at=utils.utcnow()) host = instance['host'] @@ -689,12 +689,12 @@ class API(base.Base): instance = self._get_instance(context, instance_id, 'starting') vm_state = instance["vm_state"] - if vm_state != vm_state.STOP: + if vm_state != vm_states.STOP: LOG.warning(_("Instance %(instance_id)s is not " "stopped. (%(vm_state)s)") % locals()) return - self.update(context, instance_id, vm_state=vm_state.ACTIVE) + self.update(context, instance_id, vm_state=vm_states.ACTIVE) # TODO(yamahata): injected_files isn't supported right now. # It is used only for osapi. not for ec2 api. @@ -923,7 +923,7 @@ class API(base.Base): @scheduler_api.reroute_compute("reboot") def reboot(self, context, instance_id): """Reboot the given instance.""" - self.update(context, instance_id, vm_state=vm_state.REBOOT) + self.update(context, instance_id, vm_state=vm_states.REBOOT) self._cast_compute_message('reboot_instance', context, instance_id) @scheduler_api.reroute_compute("rebuild") @@ -932,8 +932,8 @@ class API(base.Base): """Rebuild the given instance with the provided metadata.""" instance = db.api.instance_get(context, instance_id) invalid_rebuild_states = [ - vm_state.BUILD, - vm_state.REBUILD, + vm_states.BUILD, + vm_states.REBUILD, ] if instance["vm_state"] in invalid_rebuild_states: @@ -956,7 +956,7 @@ class API(base.Base): "injected_files": files_to_inject, } - self.update(context, instance_id, vm_state=vm_state.REBUILD) + self.update(context, instance_id, vm_state=vm_states.REBUILD) self._cast_compute_message('rebuild_instance', context, @@ -975,7 +975,7 @@ class API(base.Base): raise exception.MigrationNotFoundByStatus(instance_id=instance_id, status='finished') - self.update(context, instance_id, vm_state=vm_state.ACTIVE) + self.update(context, instance_id, vm_state=vm_states.ACTIVE) params = {'migration_id': migration_ref['id']} self._cast_compute_message('revert_resize', context, @@ -998,7 +998,7 @@ class API(base.Base): raise exception.MigrationNotFoundByStatus(instance_id=instance_id, status='finished') - self.update(context, instance_id, vm_state=vm_state.ACTIVE) + self.update(context, instance_id, vm_state=vm_states.ACTIVE) params = {'migration_id': migration_ref['id']} self._cast_compute_message('confirm_resize', context, @@ -1045,7 +1045,7 @@ class API(base.Base): if (current_memory_mb == new_memory_mb) and flavor_id: raise exception.CannotResizeToSameSize() - self.update(context, instance_id, vm_state=vm_state.RESIZE) + self.update(context, instance_id, vm_state=vm_states.RESIZE) instance_ref = self._get_instance(context, instance_id, 'resize') self._cast_scheduler_message(context, @@ -1080,13 +1080,13 @@ class API(base.Base): @scheduler_api.reroute_compute("pause") def pause(self, context, instance_id): """Pause the given instance.""" - self.update(context, instance_id, vm_state=vm_state.PAUSE) + self.update(context, instance_id, vm_state=vm_states.PAUSE) self._cast_compute_message('pause_instance', context, instance_id) @scheduler_api.reroute_compute("unpause") def unpause(self, context, instance_id): """Unpause the given instance.""" - self.update(context, instance_id, vm_state=vm_state.ACTIVE) + self.update(context, instance_id, vm_state=vm_states.ACTIVE) self._cast_compute_message('unpause_instance', context, instance_id) def _call_compute_message_for_host(self, action, context, host, params): @@ -1119,25 +1119,25 @@ class API(base.Base): @scheduler_api.reroute_compute("suspend") def suspend(self, context, instance_id): """Suspend the given instance.""" - self.update(context, instance_id, vm_state=vm_state.SUSPEND) + self.update(context, instance_id, vm_state=vm_states.SUSPEND) self._cast_compute_message('suspend_instance', context, instance_id) @scheduler_api.reroute_compute("resume") def resume(self, context, instance_id): """Resume the given instance.""" - self.update(context, instance_id, vm_state=vm_state.ACTIVE) + self.update(context, instance_id, vm_state=vm_states.ACTIVE) self._cast_compute_message('resume_instance', context, instance_id) @scheduler_api.reroute_compute("rescue") def rescue(self, context, instance_id): """Rescue the given instance.""" - self.update(context, instance_id, vm_state=vm_state.RESCUE) + self.update(context, instance_id, vm_state=vm_states.RESCUE) self._cast_compute_message('rescue_instance', context, instance_id) @scheduler_api.reroute_compute("unrescue") def unrescue(self, context, instance_id): """Unrescue the given instance.""" - self.update(context, instance_id, vm_state=vm_state.ACTIVE) + self.update(context, instance_id, vm_state=vm_states.ACTIVE) self._cast_compute_message('unrescue_instance', context, instance_id) @scheduler_api.reroute_compute("set_admin_password") diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 0d7f3ad71..4be5bdd69 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -57,7 +57,7 @@ from nova import utils from nova import volume from nova.compute import power_state from nova.compute import task_state -from nova.compute import vm_state +from nova.compute import vm_states from nova.notifier import api as notifier from nova.compute.utils import terminate_volumes from nova.virt import driver @@ -372,7 +372,7 @@ class ComputeManager(manager.SchedulerDependentManager): updates = {} updates['host'] = self.host updates['launched_on'] = self.host - updates['vm_state'] = vm_state.BUILD + updates['vm_state'] = vm_states.BUILD updates['task_state'] = task_state.NETWORKING instance = self.db.instance_update(context, instance_id, updates) instance['injected_files'] = kwargs.get('injected_files', []) @@ -397,7 +397,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, - vm_state=vm_state.BUILD, + vm_state=vm_states.BUILD, task_state=task_state.BLOCK_DEVICE_MAPPING) (swap, ephemerals, @@ -428,7 +428,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, power_state=current_power_state, - vm_state=vm_state.ACTIVE, + vm_state=vm_states.ACTIVE, task_state=None, launched_at=utils.utcnow()) @@ -523,7 +523,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, power_state=current_power_state, - vm_state=vm_state.REBUILD, + vm_state=vm_states.REBUILD, task_state=task_state.REBUILDING) network_info = self._get_instance_nw_info(context, instance_ref) @@ -531,7 +531,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, - vm_state=vm_state.REBUILD, + vm_state=vm_states.REBUILD, task_state=task_state.BLOCK_DEVICE_MAPPING) bd_mapping = self._setup_block_device_mapping(context, instance_id) @@ -544,7 +544,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, - vm_state=vm_state.REBUILD, + vm_state=vm_states.REBUILD, task_state=task_state.SPAWN) self.driver.spawn(context, instance_ref, network_info, bd_mapping) @@ -553,7 +553,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, power_state=current_power_state, - vm_state=vm_state.ACTIVE, + vm_state=vm_states.ACTIVE, task_state=None, image_ref=image_ref, launched_at=utils.utcnow()) @@ -577,7 +577,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, power_state=current_power_state, - vm_state=vm_state.REBOOT, + vm_state=vm_states.REBOOT, task_state=task_state.REBOOTING) if instance_ref['power_state'] != power_state.RUNNING: @@ -595,7 +595,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, power_state=current_power_state, - vm_state=vm_state.ACTIVE, + vm_state=vm_states.ACTIVE, task_state=None) @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) @@ -622,7 +622,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, power_state=current_power_state, - vm_state=vm_state.ACTIVE, + vm_state=vm_states.ACTIVE, task_state=image_type) LOG.audit(_('instance %s: snapshotting'), instance_id, @@ -787,7 +787,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, - vm_state=vm_state.RESCUE, + vm_state=vm_states.RESCUE, task_state=task_state.RESCUING) instance_ref = self.db.instance_get(context, instance_id) @@ -799,7 +799,7 @@ class ComputeManager(manager.SchedulerDependentManager): current_power_state = self._get_power_state(context, instance_ref) self._instance_update(context, instance_id, - vm_state=vm_state.RESCUE, + vm_state=vm_states.RESCUE, task_state=task_state.RESCUED, power_state=current_power_state) @@ -812,7 +812,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, - vm_state=vm_state.ACTIVE, + vm_state=vm_states.ACTIVE, task_state=task_state.UNRESCUING) instance_ref = self.db.instance_get(context, instance_id) @@ -824,7 +824,7 @@ class ComputeManager(manager.SchedulerDependentManager): current_power_state = self._get_power_state(context, instance_ref) self._instance_update(context, instance_id, - vm_state=vm_state.ACTIVE, + vm_state=vm_states.ACTIVE, task_state=None, power_state=current_power_state) @@ -1048,7 +1048,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, - vm_state=vm_state.PAUSE, + vm_state=vm_states.PAUSE, task_state=task_state.PAUSING) instance_ref = self.db.instance_get(context, instance_id) @@ -1058,7 +1058,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, power_state=current_power_state, - vm_state=vm_state.PAUSE, + vm_state=vm_states.PAUSE, task_state=None) @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) @@ -1070,7 +1070,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, - vm_state=vm_state.ACTIVE, + vm_state=vm_states.ACTIVE, task_state=task_state.UNPAUSING) instance_ref = self.db.instance_get(context, instance_id) @@ -1080,7 +1080,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, power_state=current_power_state, - vm_state=vm_state.ACTIVE, + vm_state=vm_states.ACTIVE, task_state=None) @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) @@ -1111,7 +1111,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, - vm_state=vm_state.SUSPEND, + vm_state=vm_states.SUSPEND, task_state=task_state.SUSPENDING) instance_ref = self.db.instance_get(context, instance_id) @@ -1121,7 +1121,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, power_state=current_power_state, - vm_state=vm_state.SUSPEND, + vm_state=vm_states.SUSPEND, task_state=None) @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) @@ -1133,7 +1133,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, - vm_state=vm_state.ACTIVE, + vm_state=vm_states.ACTIVE, task_state=task_state.RESUMING) instance_ref = self.db.instance_get(context, instance_id) @@ -1143,7 +1143,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, power_state=current_power_state, - vm_state=vm_state.ACTIVE, + vm_state=vm_states.ACTIVE, task_state=None) @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) @@ -1560,7 +1560,7 @@ class ComputeManager(manager.SchedulerDependentManager): instance_ref["id"], host=dest, power_state=current_power_state, - vm_state=vm_state.ACTIVE, + vm_state=vm_states.ACTIVE, task_state=None) # Restore volume state @@ -1611,7 +1611,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_ref['id'], host=host, - vm_state=vm_state.ACTIVE, + vm_state=vm_states.ACTIVE, task_state=None) for volume_ref in instance_ref['volumes']: diff --git a/nova/compute/vm_state.py b/nova/compute/vm_state.py deleted file mode 100644 index a1bca6ef4..000000000 --- a/nova/compute/vm_state.py +++ /dev/null @@ -1,31 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010 OpenStack LLC. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""Possible vm states for instances""" - -ACTIVE='active' -BUILD='build' -REBUILD='rebuild' -REBOOT='reboot' -DELETE='delete' -STOP='stop' -MIGRATE='migrate' -RESIZE='resize' -VERIFY_RESIZE='verify_resize' -PAUSE='pause' -SUSPEND='suspend' -RESCUE='rescue' diff --git a/nova/compute/vm_states.py b/nova/compute/vm_states.py new file mode 100644 index 000000000..a1bca6ef4 --- /dev/null +++ b/nova/compute/vm_states.py @@ -0,0 +1,31 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""Possible vm states for instances""" + +ACTIVE='active' +BUILD='build' +REBUILD='rebuild' +REBOOT='reboot' +DELETE='delete' +STOP='stop' +MIGRATE='migrate' +RESIZE='resize' +VERIFY_RESIZE='verify_resize' +PAUSE='pause' +SUSPEND='suspend' +RESCUE='rescue' diff --git a/nova/scheduler/driver.py b/nova/scheduler/driver.py index b788b996f..8f9be879b 100644 --- a/nova/scheduler/driver.py +++ b/nova/scheduler/driver.py @@ -31,7 +31,7 @@ from nova import rpc from nova import utils from nova.compute import power_state from nova.compute import task_state -from nova.compute import vm_state +from nova.compute import vm_states from nova.api.ec2 import ec2utils @@ -106,7 +106,7 @@ class Scheduler(object): dest, block_migration) # Changing instance_state. - values = {"vm_state": vm_state.MIGRATE} + values = {"vm_state": vm_states.MIGRATE} db.instance_update(context, instance_id, values) # Changing volume state diff --git a/nova/tests/scheduler/test_scheduler.py b/nova/tests/scheduler/test_scheduler.py index 1b5e131c9..629019eaf 100644 --- a/nova/tests/scheduler/test_scheduler.py +++ b/nova/tests/scheduler/test_scheduler.py @@ -40,7 +40,7 @@ from nova.scheduler import driver from nova.scheduler import manager from nova.scheduler import multi from nova.compute import power_state -from nova.compute import vm_state +from nova.compute import vm_states FLAGS = flags.FLAGS diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index 188398924..ca1bbc69f 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -23,7 +23,7 @@ from nova import compute from nova.compute import instance_types from nova.compute import manager as compute_manager from nova.compute import power_state -from nova.compute import vm_state +from nova.compute import vm_states from nova import context from nova import db from nova.db.sqlalchemy import models @@ -748,7 +748,7 @@ class ComputeTestCase(test.TestCase): 'block_migration': False, 'disk': None}}).\ AndRaise(rpc.RemoteError('', '', '')) - dbmock.instance_update(c, i_ref['id'], {'vm_state': vm_state.ACTIVE, + dbmock.instance_update(c, i_ref['id'], {'vm_state': vm_states.ACTIVE, 'task_state': None, 'host': i_ref['host']}) for v in i_ref['volumes']: @@ -780,7 +780,7 @@ class ComputeTestCase(test.TestCase): 'block_migration': False, 'disk': None}}).\ AndRaise(rpc.RemoteError('', '', '')) - dbmock.instance_update(c, i_ref['id'], {'vm_state': vm_state.ACTIVE, + dbmock.instance_update(c, i_ref['id'], {'vm_state': vm_states.ACTIVE, 'task_state': None, 'host': i_ref['host']}) @@ -826,7 +826,7 @@ class ComputeTestCase(test.TestCase): c = context.get_admin_context() instance_id = self._create_instance() i_ref = db.instance_get(c, instance_id) - db.instance_update(c, i_ref['id'], {'vm_state': vm_state.MIGRATE, + db.instance_update(c, i_ref['id'], {'vm_state': vm_states.MIGRATE, 'power_state': power_state.PAUSED}) v_ref = db.volume_create(c, {'size': 1, 'instance_id': instance_id}) fix_addr = db.fixed_ip_create(c, {'address': '1.1.1.1', -- cgit From c4e77b67a74cb0828bb9a7ccbedcaa1baeb6188d Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Fri, 19 Aug 2011 18:34:34 -0400 Subject: Lots of modifications surrounding the OSAPI to remove any mention of dealing with power states and exclusively using vm_states and task_state modules. Currently there are still a number of tests failing, but this is a stopping place for today. --- nova/api/openstack/common.py | 52 ++++++------ nova/api/openstack/servers.py | 12 ++- nova/api/openstack/views/servers.py | 5 +- nova/compute/vm_states.py | 2 + nova/tests/api/openstack/test_server_actions.py | 28 ++++--- nova/tests/api/openstack/test_servers.py | 102 +++++++++++++++--------- nova/tests/integrated/test_servers.py | 27 ++++--- nova/tests/vmwareapi/db_fakes.py | 5 +- 8 files changed, 138 insertions(+), 95 deletions(-) diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index d9eb832f2..eae0fd916 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -27,7 +27,8 @@ from nova import flags from nova import log as logging from nova import quota from nova.api.openstack import wsgi -from nova.compute import power_state as compute_power_state +from nova.compute import vm_states +from nova.compute import task_state LOG = logging.getLogger('nova.api.openstack.common') @@ -38,36 +39,35 @@ XML_NS_V10 = 'http://docs.rackspacecloud.com/servers/api/v1.0' XML_NS_V11 = 'http://docs.openstack.org/compute/api/v1.1' -_STATUS_MAP = { - None: 'BUILD', - compute_power_state.NOSTATE: 'BUILD', - compute_power_state.RUNNING: 'ACTIVE', - compute_power_state.BLOCKED: 'ACTIVE', - compute_power_state.SUSPENDED: 'SUSPENDED', - compute_power_state.PAUSED: 'PAUSED', - compute_power_state.SHUTDOWN: 'SHUTDOWN', - compute_power_state.SHUTOFF: 'SHUTOFF', - compute_power_state.CRASHED: 'ERROR', - compute_power_state.FAILED: 'ERROR', - compute_power_state.BUILDING: 'BUILD', +_STATE_MAP = { + vm_states.ACTIVE: 'ACTIVE', + vm_states.BUILD: 'BUILD', + vm_states.REBUILD: 'REBUILD', + vm_states.REBOOT: 'REBOOT', + vm_states.HARD_REBOOT: 'HARD_REBOOT', + vm_states.STOP: 'STOPPED', + vm_states.MIGRATE: 'MIGRATING', + vm_states.RESIZE: 'RESIZE', + vm_states.VERIFY_RESIZE: 'VERIFY_RESIZE', + vm_states.PAUSE: 'PAUSED', + vm_states.SUSPEND: 'SUSPENDED', + vm_states.RESCUE: 'RESCUE', + vm_states.ERROR: 'ERROR', } -def status_from_power_state(power_state): - """Map the power state to the server status string""" - return _STATUS_MAP[power_state] +def status_from_state(_vm_state, _task_state=None): + """Given vm_state and task_state, return a status string.""" + if _vm_state == vm_states.ACTIVE and _task_state == task_state.PASSWORD: + return "PASSWORD" + return _STATE_MAP.get(_vm_state, "UNKNOWN_STATE") -def power_states_from_status(status): - """Map the server status string to a list of power states""" - power_states = [] - for power_state, status_map in _STATUS_MAP.iteritems(): - # Skip the 'None' state - if power_state is None: - continue - if status.lower() == status_map.lower(): - power_states.append(power_state) - return power_states +def vm_state_from_status(status): + """Map the server status string to a vm state.""" + for state, status_string in _STATE_MAP.iteritems(): + if status.lower() == status_string.lower(): + return state def get_pagination_params(request): diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 41e63ec3c..0a451caee 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -95,17 +95,15 @@ class Controller(object): search_opts['recurse_zones'] = utils.bool_from_str( search_opts.get('recurse_zones', False)) - # If search by 'status', we need to convert it to 'state' - # If the status is unknown, bail. - # Leave 'state' in search_opts so compute can pass it on to - # child zones.. + # If search by 'status', we need to convert it to 'vm_state' + # to pass on to child zones. if 'status' in search_opts: status = search_opts['status'] - search_opts['state'] = common.power_states_from_status(status) - if len(search_opts['state']) == 0: + state = common.vm_state_from_status(status) + if state is None: reason = _('Invalid server status: %(status)s') % locals() - LOG.error(reason) raise exception.InvalidInput(reason=reason) + search_opts['vm_state'] = state # By default, compute's get_all() will return deleted instances. # If an admin hasn't specified a 'deleted' search option, we need diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py index edc328129..e9a932b0e 100644 --- a/nova/api/openstack/views/servers.py +++ b/nova/api/openstack/views/servers.py @@ -27,6 +27,7 @@ from nova.api.openstack.views import addresses as addresses_view from nova.api.openstack.views import flavors as flavors_view from nova.api.openstack.views import images as images_view from nova import utils +from nova.compute import vm_states class ViewBuilder(object): @@ -60,11 +61,13 @@ class ViewBuilder(object): def _build_detail(self, inst): """Returns a detailed model of a server.""" + vm_state = inst.get('vm_state', vm_states.BUILD) + task_state = inst.get('task_state') inst_dict = { 'id': inst['id'], 'name': inst['display_name'], - 'status': common.status_from_power_state(inst.get('state'))} + 'status': common.status_from_state(vm_state, task_state)} ctxt = nova.context.get_admin_context() compute_api = nova.compute.API() diff --git a/nova/compute/vm_states.py b/nova/compute/vm_states.py index a1bca6ef4..d3d168001 100644 --- a/nova/compute/vm_states.py +++ b/nova/compute/vm_states.py @@ -21,6 +21,7 @@ ACTIVE='active' BUILD='build' REBUILD='rebuild' REBOOT='reboot' +HARD_REBOOT='hard_reboot' DELETE='delete' STOP='stop' MIGRATE='migrate' @@ -29,3 +30,4 @@ VERIFY_RESIZE='verify_resize' PAUSE='pause' SUSPEND='suspend' RESCUE='rescue' +ERROR='error' diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index 80a27e30f..6f8be0f47 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -12,7 +12,8 @@ from nova import utils from nova import flags from nova.api.openstack import create_instance_helper from nova.compute import instance_types -from nova.compute import power_state +from nova.compute import vm_states +from nova.compute import task_state import nova.db.api from nova import test from nova.tests.api.openstack import common @@ -30,17 +31,18 @@ def instance_update(context, instance_id, kwargs): return _get_instance() -def return_server_with_power_state(power_state): +def return_server_with_state(vm_state, task_state=None): def _return_server(context, id): instance = _get_instance() - instance['state'] = power_state + instance['vm_state'] = vm_state + instance['task_state'] = task_state return instance return _return_server -def return_server_with_uuid_and_power_state(power_state): +def return_server_with_uuid_and_state(vm_state, task_state=None): def _return_server(context, id): - return return_server_with_power_state(power_state) + return return_server_with_state(vm_state, task_state) return _return_server @@ -68,8 +70,8 @@ def _get_instance(): "launch_index": 0, "key_name": "", "key_data": "", - "state": 0, - "state_description": "", + "vm_state": vm_states.ACTIVE, + "task_state": None, "memory_mb": 0, "vcpus": 0, "local_gb": 0, @@ -164,11 +166,11 @@ class ServerActionsTest(test.TestCase): }, } - state = power_state.BUILDING - new_return_server = return_server_with_power_state(state) + state = vm_states.BUILD + new_return_server = return_server_with_state(state) self.stubs.Set(nova.db.api, 'instance_get', new_return_server) self.stubs.Set(nova.db, 'instance_get_by_uuid', - return_server_with_uuid_and_power_state(state)) + return_server_with_uuid_and_state(state)) req = webob.Request.blank('/v1.0/servers/1/action') req.method = 'POST' @@ -627,11 +629,11 @@ class ServerActionsTestV11(test.TestCase): }, } - state = power_state.BUILDING - new_return_server = return_server_with_power_state(state) + state = vm_states.BUILD + new_return_server = return_server_with_state(state) self.stubs.Set(nova.db.api, 'instance_get', new_return_server) self.stubs.Set(nova.db, 'instance_get_by_uuid', - return_server_with_uuid_and_power_state(state)) + return_server_with_uuid_and_state(state)) req = webob.Request.blank('/v1.1/servers/1/action') req.method = 'POST' diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 437620854..b500c514e 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -34,7 +34,8 @@ from nova.api.openstack import servers from nova.api.openstack import wsgi import nova.compute.api from nova.compute import instance_types -from nova.compute import power_state +from nova.compute import task_state +from nova.compute import vm_states import nova.db.api import nova.scheduler.api from nova.db.sqlalchemy.models import Instance @@ -86,15 +87,18 @@ def return_server_with_addresses(private, public): return _return_server -def return_server_with_power_state(power_state): +def return_server_with_state(vm_state, task_state=None): def _return_server(context, id): - return stub_instance(id, power_state=power_state) + return stub_instance(id, vm_state=vm_state, task_state=task_state) return _return_server -def return_server_with_uuid_and_power_state(power_state): +def return_server_with_uuid_and_state(vm_state, task_state): def _return_server(context, id): - return stub_instance(id, uuid=FAKE_UUID, power_state=power_state) + return stub_instance(id, + uuid=FAKE_UUID, + vm_state=vm_state, + task_state=task_state) return _return_server @@ -143,7 +147,8 @@ def instance_addresses(context, instance_id): def stub_instance(id, user_id='fake', project_id='fake', private_address=None, - public_addresses=None, host=None, power_state=0, + public_addresses=None, host=None, + vm_state=None, task_state=None, reservation_id="", uuid=FAKE_UUID, image_ref="10", flavor_id="1", interfaces=None, name=None): metadata = [] @@ -178,8 +183,8 @@ def stub_instance(id, user_id='fake', project_id='fake', private_address=None, "launch_index": 0, "key_name": "", "key_data": "", - "state": power_state, - "state_description": "", + "vm_state": vm_state or vm_states.BUILD, + "task_state": task_state, "memory_mb": 0, "vcpus": 0, "local_gb": 0, @@ -481,7 +486,7 @@ class ServersTest(test.TestCase): }, ] new_return_server = return_server_with_attributes( - interfaces=interfaces, power_state=1) + interfaces=interfaces, vm_state=vm_states.ACTIVE) self.stubs.Set(nova.db.api, 'instance_get', new_return_server) req = webob.Request.blank('/v1.1/servers/1') @@ -571,8 +576,8 @@ class ServersTest(test.TestCase): }, ] new_return_server = return_server_with_attributes( - interfaces=interfaces, power_state=1, image_ref=image_ref, - flavor_id=flavor_id) + interfaces=interfaces, vm_state=vm_states.ACTIVE, + image_ref=image_ref, flavor_id=flavor_id) self.stubs.Set(nova.db.api, 'instance_get', new_return_server) req = webob.Request.blank('/v1.1/servers/1') @@ -1169,9 +1174,8 @@ class ServersTest(test.TestCase): def test_get_servers_allows_status_v1_1(self): def fake_get_all(compute_self, context, search_opts=None): self.assertNotEqual(search_opts, None) - self.assertTrue('state' in search_opts) - self.assertEqual(set(search_opts['state']), - set([power_state.RUNNING, power_state.BLOCKED])) + self.assertTrue('vm_state' in search_opts) + self.assertEqual(search_opts['vm_state'], vm_states.ACTIVE) return [stub_instance(100)] self.stubs.Set(nova.compute.API, 'get_all', fake_get_all) @@ -1188,13 +1192,9 @@ class ServersTest(test.TestCase): def test_get_servers_invalid_status_v1_1(self): """Test getting servers by invalid status""" - self.flags(allow_admin_api=False) - req = webob.Request.blank('/v1.1/servers?status=running') res = req.get_response(fakes.wsgi_app()) - # The following assert will fail if either of the asserts in - # fake_get_all() fail self.assertEqual(res.status_int, 400) self.assertTrue(res.body.find('Invalid server status') > -1) @@ -1632,6 +1632,7 @@ class ServersTest(test.TestCase): server = json.loads(res.body)['server'] self.assertEqual(16, len(server['adminPass'])) self.assertEqual(1, server['id']) + self.assertEqual("BUILD", server["status"]) self.assertEqual(0, server['progress']) self.assertEqual('server_test', server['name']) self.assertEqual(expected_flavor, server['flavor']) @@ -2165,23 +2166,52 @@ class ServersTest(test.TestCase): self.assertEqual(res.status_int, 204) self.assertEqual(self.server_delete_called, True) - def test_shutdown_status(self): - new_server = return_server_with_power_state(power_state.SHUTDOWN) - self.stubs.Set(nova.db.api, 'instance_get', new_server) - req = webob.Request.blank('/v1.0/servers/1') - res = req.get_response(fakes.wsgi_app()) - self.assertEqual(res.status_int, 200) - res_dict = json.loads(res.body) - self.assertEqual(res_dict['server']['status'], 'SHUTDOWN') - def test_shutoff_status(self): - new_server = return_server_with_power_state(power_state.SHUTOFF) +class TestServerStatus(test.TestCase): + + def _get_with_state(self, vm_state, task_state=None): + new_server = return_server_with_state(vm_state, task_state) self.stubs.Set(nova.db.api, 'instance_get', new_server) - req = webob.Request.blank('/v1.0/servers/1') - res = req.get_response(fakes.wsgi_app()) - self.assertEqual(res.status_int, 200) - res_dict = json.loads(res.body) - self.assertEqual(res_dict['server']['status'], 'SHUTOFF') + request = webob.Request.blank('/v1.0/servers/1') + response = request.get_response(fakes.wsgi_app()) + self.assertEqual(response.status_int, 200) + return json.loads(response.body) + + def test_active(self): + response = self._get_with_state(vm_states.ACTIVE) + self.assertEqual(response['server']['status'], 'ACTIVE') + + def test_reboot(self): + response = self._get_with_state(vm_states.REBOOT) + self.assertEqual(response['server']['status'], 'REBOOT') + + def test_hard_reboot(self): + response = self._get_with_state(vm_states.HARD_REBOOT) + self.assertEqual(response['server']['status'], 'HARD_REBOOT') + + def test_rebuild(self): + response = self._get_with_state(vm_states.REBUILD) + self.assertEqual(response['server']['status'], 'REBUILD') + + def test_rebuild_error(self): + response = self._get_with_state(vm_states.ERROR) + self.assertEqual(response['server']['status'], 'ERROR') + + def test_resize(self): + response = self._get_with_state(vm_states.RESIZE) + self.assertEqual(response['server']['status'], 'RESIZE') + + def test_verify_resize(self): + response = self._get_with_state(vm_states.VERIFY_RESIZE) + self.assertEqual(response['server']['status'], 'VERIFY_RESIZE') + + def test_password_update(self): + response = self._get_with_state(vm_states.ACTIVE, task_state.PASSWORD) + self.assertEqual(response['server']['status'], 'PASSWORD') + + def test_stopped(self): + response = self._get_with_state(vm_states.STOP) + self.assertEqual(response['server']['status'], 'STOPPED') class TestServerCreateRequestXMLDeserializerV10(unittest.TestCase): @@ -3018,8 +3048,8 @@ class ServersViewBuilderV11Test(test.TestCase): "launch_index": 0, "key_name": "", "key_data": "", - "state": 0, - "state_description": "", + "vm_state": vm_states.BUILD, + "task_state": None, "memory_mb": 0, "vcpus": 0, "local_gb": 0, @@ -3132,7 +3162,7 @@ class ServersViewBuilderV11Test(test.TestCase): def test_build_server_detail_active_status(self): #set the power state of the instance to running - self.instance['state'] = 1 + self.instance['vm_state'] = vm_states.ACTIVE image_bookmark = "http://localhost/images/5" flavor_bookmark = "http://localhost/flavors/1" expected_server = { diff --git a/nova/tests/integrated/test_servers.py b/nova/tests/integrated/test_servers.py index 725f6d529..deeb3d008 100644 --- a/nova/tests/integrated/test_servers.py +++ b/nova/tests/integrated/test_servers.py @@ -28,6 +28,17 @@ LOG = logging.getLogger('nova.tests.integrated') class ServersTest(integrated_helpers._IntegratedTestBase): + def _wait_for_creation(self, server): + retries = 0 + while server['status'] == 'BUILD': + time.sleep(1) + server = self.api.get_server(server['id']) + print server + retries = retries + 1 + if retries > 8: + break + return server + def test_get_servers(self): """Simple check that listing servers works.""" servers = self.api.get_servers() @@ -36,7 +47,7 @@ class ServersTest(integrated_helpers._IntegratedTestBase): def test_create_and_delete_server(self): """Creates and deletes a server.""" - + self.flags(stub_network=True) # Create server # Build the server data gradually, checking errors along the way @@ -91,19 +102,11 @@ class ServersTest(integrated_helpers._IntegratedTestBase): server_ids = [server['id'] for server in servers] self.assertTrue(created_server_id in server_ids) - # Wait (briefly) for creation - retries = 0 - while found_server['status'] == 'build': - LOG.debug("found server: %s" % found_server) - time.sleep(1) - found_server = self.api.get_server(created_server_id) - retries = retries + 1 - if retries > 5: - break + found_server = self._wait_for_creation(found_server) # It should be available... # TODO(justinsb): Mock doesn't yet do this... - #self.assertEqual('available', found_server['status']) + self.assertEqual('ACTIVE', found_server['status']) servers = self.api.get_servers(detail=True) for server in servers: self.assertTrue("image" in server) @@ -190,6 +193,8 @@ class ServersTest(integrated_helpers._IntegratedTestBase): self.assertTrue(created_server['id']) created_server_id = created_server['id'] + created_server = self._wait_for_creation(created_server) + # rebuild the server with metadata post = {} post['rebuild'] = { diff --git a/nova/tests/vmwareapi/db_fakes.py b/nova/tests/vmwareapi/db_fakes.py index afd672c7a..dd38420ce 100644 --- a/nova/tests/vmwareapi/db_fakes.py +++ b/nova/tests/vmwareapi/db_fakes.py @@ -23,6 +23,8 @@ import time from nova import db from nova import utils +from nova.compute import task_state +from nova.compute import vm_states def stub_out_db_instance_api(stubs): @@ -64,7 +66,8 @@ def stub_out_db_instance_api(stubs): 'image_ref': values['image_ref'], 'kernel_id': values['kernel_id'], 'ramdisk_id': values['ramdisk_id'], - 'state_description': 'scheduling', + 'vm_state': vm_states.BUILD, + 'task_state': task_state.SCHEDULE, 'user_id': values['user_id'], 'project_id': values['project_id'], 'launch_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()), -- cgit From f82d2d309a0f826522854fe331d1c53b8c6d6879 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 22 Aug 2011 09:54:33 -0400 Subject: Ec2 API updates. --- nova/api/ec2/cloud.py | 25 ++++++++++++++++++++++++- nova/tests/test_cloud.py | 8 ++++---- nova/virt/fake.py | 12 ++++++------ 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 4b69cc272..b7c7d2e12 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -79,6 +79,29 @@ def _gen_key(context, user_id, key_name): return {'private_key': private_key, 'fingerprint': fingerprint} +# EC2 API: Valid Values: +# pending | running | shutting-down | terminated | stopping | stopped +_STATE_DESCRIPTION_MAP = { + vm_states.ACTIVE: 'running', + vm_states.BUILD: 'pending', + vm_states.REBUILD: 'pending', + vm_states.REBOOT: 'reboot', + vm_states.DELETE: 'terminated', + vm_states.STOP: 'stopped', + vm_states.MIGRATE: 'migrate', + vm_states.RESIZE: 'resize', + vm_states.VERIFY_RESIZE: 'verify_resize', + vm_states.PAUSE: 'pause', + vm_states.SUSPEND: 'suspend', + vm_states.RESCUE: 'rescue' +} + + +def state_description_from_vm_state(vm_state): + """Map the vm state to the server status string""" + return _STATE_DESCRIPTION_MAP[vm_state] + + # TODO(yamahata): hypervisor dependent default device name _DEFAULT_ROOT_DEVICE_NAME = '/dev/sda1' _DEFAULT_MAPPINGS = {'ami': 'sda1', @@ -1199,7 +1222,7 @@ class CloudController(object): self._format_ramdisk_id(instance, i, 'ramdiskId') i['instanceState'] = { 'code': instance['power_state'], - 'name': instance['vm_state']} #FIXME + 'name': state_description_from_vm_state(instance['vm_state'])} fixed_addr = None floating_addr = None if instance['fixed_ips']: diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index 0793784f8..cce9514ec 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -1163,7 +1163,7 @@ class CloudTestCase(test.TestCase): self.compute = self.start_service('compute') def _wait_for_state(self, ctxt, instance_id, predicate): - """Wait for an stopping instance to be a given state""" + """Wait for a stopped instance to be a given state""" id = ec2utils.ec2_id_to_id(instance_id) while True: info = self.cloud.compute_api.get(context=ctxt, instance_id=id) @@ -1174,12 +1174,12 @@ class CloudTestCase(test.TestCase): def _wait_for_running(self, instance_id): def is_running(info): - return info['state_description'] == 'running' + return info['vm_state'] == 'running' self._wait_for_state(self.context, instance_id, is_running) def _wait_for_stopped(self, instance_id): def is_stopped(info): - return info['state_description'] == 'stopped' + return info['vm_state'] == 'stopped' self._wait_for_state(self.context, instance_id, is_stopped) def _wait_for_terminate(self, instance_id): @@ -1562,7 +1562,7 @@ class CloudTestCase(test.TestCase): 'id': 0, 'root_device_name': '/dev/sdh', 'security_groups': [{'name': 'fake0'}, {'name': 'fake1'}], - 'state_description': 'stopping', + 'vm_state': 'stopped', 'instance_type': {'name': 'fake_type'}, 'kernel_id': 1, 'ramdisk_id': 2, diff --git a/nova/virt/fake.py b/nova/virt/fake.py index dc0628772..b42f4ca2f 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -42,9 +42,9 @@ def get_connection(_): class FakeInstance(object): - def __init__(self, name, state): + def __init__(self, name, power_state): self.name = name - self.state = state + self.power_state = power_state class FakeConnection(driver.ComputeDriver): @@ -120,7 +120,7 @@ class FakeConnection(driver.ComputeDriver): def _map_to_instance_info(self, instance): instance = utils.check_isinstance(instance, FakeInstance) - info = driver.InstanceInfo(instance.name, instance.state) + info = driver.InstanceInfo(instance.name, instance.power_state) return info def list_instances_detail(self): @@ -150,8 +150,8 @@ class FakeConnection(driver.ComputeDriver): """ name = instance.name - state = power_state.RUNNING - fake_instance = FakeInstance(name, state) + pstate = power_state.RUNNING + fake_instance = FakeInstance(name, pstate) self.instances[name] = fake_instance def snapshot(self, context, instance, name): @@ -325,7 +325,7 @@ class FakeConnection(driver.ComputeDriver): if instance_name not in self.instances: raise exception.InstanceNotFound(instance_id=instance_name) i = self.instances[instance_name] - return {'state': i.state, + return {'state': i.power_state, 'max_mem': 0, 'mem': 0, 'num_cpu': 2, -- cgit From 44aea954e5efa7d94d8333ddbf54dab6464018a0 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 22 Aug 2011 10:01:13 -0400 Subject: Renamed task_state to task_states... --- nova/api/openstack/common.py | 6 ++-- nova/compute/manager.py | 30 ++++++++--------- nova/compute/task_state.py | 43 ------------------------- nova/compute/task_states.py | 43 +++++++++++++++++++++++++ nova/tests/api/openstack/test_server_actions.py | 1 - nova/tests/vmwareapi/db_fakes.py | 4 +-- 6 files changed, 63 insertions(+), 64 deletions(-) delete mode 100644 nova/compute/task_state.py create mode 100644 nova/compute/task_states.py diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index eae0fd916..778c1e514 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -28,7 +28,7 @@ from nova import log as logging from nova import quota from nova.api.openstack import wsgi from nova.compute import vm_states -from nova.compute import task_state +from nova.compute import task_states LOG = logging.getLogger('nova.api.openstack.common') @@ -56,9 +56,9 @@ _STATE_MAP = { } -def status_from_state(_vm_state, _task_state=None): +def status_from_state(_vm_state, task_state=None): """Given vm_state and task_state, return a status string.""" - if _vm_state == vm_states.ACTIVE and _task_state == task_state.PASSWORD: + if _vm_state == vm_states.ACTIVE and task_state == task_states.PASSWORD: return "PASSWORD" return _STATE_MAP.get(_vm_state, "UNKNOWN_STATE") diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 4be5bdd69..5a4f62b76 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -56,7 +56,7 @@ from nova import rpc from nova import utils from nova import volume from nova.compute import power_state -from nova.compute import task_state +from nova.compute import task_states from nova.compute import vm_states from nova.notifier import api as notifier from nova.compute.utils import terminate_volumes @@ -373,7 +373,7 @@ class ComputeManager(manager.SchedulerDependentManager): updates['host'] = self.host updates['launched_on'] = self.host updates['vm_state'] = vm_states.BUILD - updates['task_state'] = task_state.NETWORKING + updates['task_state'] = task_states.NETWORKING instance = self.db.instance_update(context, instance_id, updates) instance['injected_files'] = kwargs.get('injected_files', []) instance['admin_pass'] = kwargs.get('admin_password', None) @@ -398,7 +398,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, vm_state=vm_states.BUILD, - task_state=task_state.BLOCK_DEVICE_MAPPING) + task_state=task_states.BLOCK_DEVICE_MAPPING) (swap, ephemerals, block_device_mapping) = self._setup_block_device_mapping( @@ -411,7 +411,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, - task_state=task_state.SPAWN) + task_state=task_states.SPAWN) # TODO(vish) check to make sure the availability zone matches try: @@ -524,7 +524,7 @@ class ComputeManager(manager.SchedulerDependentManager): instance_id, power_state=current_power_state, vm_state=vm_states.REBUILD, - task_state=task_state.REBUILDING) + task_state=task_states.REBUILDING) network_info = self._get_instance_nw_info(context, instance_ref) self.driver.destroy(instance_ref, network_info) @@ -532,7 +532,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, vm_state=vm_states.REBUILD, - task_state=task_state.BLOCK_DEVICE_MAPPING) + task_state=task_states.BLOCK_DEVICE_MAPPING) bd_mapping = self._setup_block_device_mapping(context, instance_id) @@ -545,7 +545,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, vm_state=vm_states.REBUILD, - task_state=task_state.SPAWN) + task_state=task_states.SPAWN) self.driver.spawn(context, instance_ref, network_info, bd_mapping) @@ -578,7 +578,7 @@ class ComputeManager(manager.SchedulerDependentManager): instance_id, power_state=current_power_state, vm_state=vm_states.REBOOT, - task_state=task_state.REBOOTING) + task_state=task_states.REBOOTING) if instance_ref['power_state'] != power_state.RUNNING: state = instance_ref['power_state'] @@ -788,7 +788,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, vm_state=vm_states.RESCUE, - task_state=task_state.RESCUING) + task_state=task_states.RESCUING) instance_ref = self.db.instance_get(context, instance_id) network_info = self._get_instance_nw_info(context, instance_ref) @@ -800,7 +800,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, vm_state=vm_states.RESCUE, - task_state=task_state.RESCUED, + task_state=task_states.RESCUED, power_state=current_power_state) @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) @@ -813,7 +813,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, vm_state=vm_states.ACTIVE, - task_state=task_state.UNRESCUING) + task_state=task_states.UNRESCUING) instance_ref = self.db.instance_get(context, instance_id) network_info = self._get_instance_nw_info(context, instance_ref) @@ -1049,7 +1049,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, vm_state=vm_states.PAUSE, - task_state=task_state.PAUSING) + task_state=task_states.PAUSING) instance_ref = self.db.instance_get(context, instance_id) self.driver.pause(instance_ref, lambda result: None) @@ -1071,7 +1071,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, vm_state=vm_states.ACTIVE, - task_state=task_state.UNPAUSING) + task_state=task_states.UNPAUSING) instance_ref = self.db.instance_get(context, instance_id) self.driver.unpause(instance_ref, lambda result: None) @@ -1112,7 +1112,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, vm_state=vm_states.SUSPEND, - task_state=task_state.SUSPENDING) + task_state=task_states.SUSPENDING) instance_ref = self.db.instance_get(context, instance_id) self.driver.suspend(instance_ref, lambda result: None) @@ -1134,7 +1134,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, vm_state=vm_states.ACTIVE, - task_state=task_state.RESUMING) + task_state=task_states.RESUMING) instance_ref = self.db.instance_get(context, instance_id) self.driver.resume(instance_ref, lambda result: None) diff --git a/nova/compute/task_state.py b/nova/compute/task_state.py deleted file mode 100644 index 55466c783..000000000 --- a/nova/compute/task_state.py +++ /dev/null @@ -1,43 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010 OpenStack LLC. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""Possible task states for instances""" - -BLOCK_DEVICE_MAPPING='block_device_mapping' -NETWORKING='networking' -SPAWN='spawn' - -SNAPSHOT='snapshot' -BACKUP='backup' -PASSWORD='password' - -RESIZE_PREP='resize_prep' -RESIZE_MIGRATING='resize_migrating' -RESIZE_MIGRATED='resize_migrated' -RESIZE_FINISH='resize_finish' - -REBUILDING='rebuilding' - -REBOOTING='rebooting' -PAUSING='pausing' -UNPAUSING='unpausing' -SUSPENDING='suspending' -RESUMING='resuming' - -RESCUING='rescuing' -RESCUED='rescued' -UNRESCUING='unrescuing' diff --git a/nova/compute/task_states.py b/nova/compute/task_states.py new file mode 100644 index 000000000..55466c783 --- /dev/null +++ b/nova/compute/task_states.py @@ -0,0 +1,43 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""Possible task states for instances""" + +BLOCK_DEVICE_MAPPING='block_device_mapping' +NETWORKING='networking' +SPAWN='spawn' + +SNAPSHOT='snapshot' +BACKUP='backup' +PASSWORD='password' + +RESIZE_PREP='resize_prep' +RESIZE_MIGRATING='resize_migrating' +RESIZE_MIGRATED='resize_migrated' +RESIZE_FINISH='resize_finish' + +REBUILDING='rebuilding' + +REBOOTING='rebooting' +PAUSING='pausing' +UNPAUSING='unpausing' +SUSPENDING='suspending' +RESUMING='resuming' + +RESCUING='rescuing' +RESCUED='rescued' +UNRESCUING='unrescuing' diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index 6f8be0f47..011f83773 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -13,7 +13,6 @@ from nova import flags from nova.api.openstack import create_instance_helper from nova.compute import instance_types from nova.compute import vm_states -from nova.compute import task_state import nova.db.api from nova import test from nova.tests.api.openstack import common diff --git a/nova/tests/vmwareapi/db_fakes.py b/nova/tests/vmwareapi/db_fakes.py index dd38420ce..b046071c7 100644 --- a/nova/tests/vmwareapi/db_fakes.py +++ b/nova/tests/vmwareapi/db_fakes.py @@ -23,7 +23,7 @@ import time from nova import db from nova import utils -from nova.compute import task_state +from nova.compute import task_states from nova.compute import vm_states @@ -67,7 +67,7 @@ def stub_out_db_instance_api(stubs): 'kernel_id': values['kernel_id'], 'ramdisk_id': values['ramdisk_id'], 'vm_state': vm_states.BUILD, - 'task_state': task_state.SCHEDULE, + 'task_state': task_states.SCHEDULE, 'user_id': values['user_id'], 'project_id': values['project_id'], 'launch_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()), -- cgit From 0ea797cd8e709d910c428234417fb179bdfd1525 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 22 Aug 2011 10:50:05 -0400 Subject: Update virt/fake to correct power state issue. --- nova/virt/fake.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/nova/virt/fake.py b/nova/virt/fake.py index b42f4ca2f..c12ee3ab8 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -42,9 +42,9 @@ def get_connection(_): class FakeInstance(object): - def __init__(self, name, power_state): + def __init__(self, name, state): self.name = name - self.power_state = power_state + self.state = state class FakeConnection(driver.ComputeDriver): @@ -150,8 +150,8 @@ class FakeConnection(driver.ComputeDriver): """ name = instance.name - pstate = power_state.RUNNING - fake_instance = FakeInstance(name, pstate) + state = power_state.RUNNING + fake_instance = FakeInstance(name, state) self.instances[name] = fake_instance def snapshot(self, context, instance, name): @@ -325,7 +325,7 @@ class FakeConnection(driver.ComputeDriver): if instance_name not in self.instances: raise exception.InstanceNotFound(instance_id=instance_name) i = self.instances[instance_name] - return {'state': i.power_state, + return {'state': i.state, 'max_mem': 0, 'mem': 0, 'num_cpu': 2, -- cgit From a450c0f3bcc93fe3ec74939e49b109cb02624913 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 22 Aug 2011 11:09:24 -0400 Subject: Update migration number. --- .../versions/039_update_instance_states.py | 57 ---------------------- .../versions/040_update_instance_states.py | 57 ++++++++++++++++++++++ 2 files changed, 57 insertions(+), 57 deletions(-) delete mode 100644 nova/db/sqlalchemy/migrate_repo/versions/039_update_instance_states.py create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/040_update_instance_states.py diff --git a/nova/db/sqlalchemy/migrate_repo/versions/039_update_instance_states.py b/nova/db/sqlalchemy/migrate_repo/versions/039_update_instance_states.py deleted file mode 100644 index 07efbf90f..000000000 --- a/nova/db/sqlalchemy/migrate_repo/versions/039_update_instance_states.py +++ /dev/null @@ -1,57 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010 OpenStack LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from sqlalchemy import MetaData, Table, Column, String - -meta = MetaData() - -c_task_state = Column('task_state', - String(length=255, convert_unicode=False, - assert_unicode=None, unicode_error=None, - _warn_on_bytestring=False), - nullable=True) - - -def upgrade(migrate_engine): - # Upgrade operations go here. Don't create your own engine; - # bind migrate_engine to your metadata - meta.bind = migrate_engine - - instances = Table('instances', meta, autoload=True, - autoload_with=migrate_engine) - - c_state = instances.c.state - c_state.alter(name='power_state') - - c_vm_state = instances.c.state_description - c_vm_state.alter(name='vm_state') - - instances.create_column(c_task_state) - - -def downgrade(migrate_engine): - meta.bind = migrate_engine - - instances = Table('instances', meta, autoload=True, - autoload_with=migrate_engine) - - c_state = instances.c.power_state - c_state.alter(name='state') - - c_vm_state = instances.c.vm_state - c_vm_state.alter(name='state_description') - - instances.drop_column('task_state') diff --git a/nova/db/sqlalchemy/migrate_repo/versions/040_update_instance_states.py b/nova/db/sqlalchemy/migrate_repo/versions/040_update_instance_states.py new file mode 100644 index 000000000..07efbf90f --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/040_update_instance_states.py @@ -0,0 +1,57 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from sqlalchemy import MetaData, Table, Column, String + +meta = MetaData() + +c_task_state = Column('task_state', + String(length=255, convert_unicode=False, + assert_unicode=None, unicode_error=None, + _warn_on_bytestring=False), + nullable=True) + + +def upgrade(migrate_engine): + # Upgrade operations go here. Don't create your own engine; + # bind migrate_engine to your metadata + meta.bind = migrate_engine + + instances = Table('instances', meta, autoload=True, + autoload_with=migrate_engine) + + c_state = instances.c.state + c_state.alter(name='power_state') + + c_vm_state = instances.c.state_description + c_vm_state.alter(name='vm_state') + + instances.create_column(c_task_state) + + +def downgrade(migrate_engine): + meta.bind = migrate_engine + + instances = Table('instances', meta, autoload=True, + autoload_with=migrate_engine) + + c_state = instances.c.power_state + c_state.alter(name='state') + + c_vm_state = instances.c.vm_state + c_vm_state.alter(name='state_description') + + instances.drop_column('task_state') -- cgit From c2736787be23d0893e2d4aebcc2cad6fdc5c2bd1 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Mon, 22 Aug 2011 11:57:42 -0400 Subject: Fix scheduler and integrated tests. --- nova/tests/integrated/test_servers.py | 11 +++++++++-- nova/tests/scheduler/test_scheduler.py | 6 +++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/nova/tests/integrated/test_servers.py b/nova/tests/integrated/test_servers.py index deeb3d008..0e3a6eefb 100644 --- a/nova/tests/integrated/test_servers.py +++ b/nova/tests/integrated/test_servers.py @@ -35,7 +35,7 @@ class ServersTest(integrated_helpers._IntegratedTestBase): server = self.api.get_server(server['id']) print server retries = retries + 1 - if retries > 8: + if retries > 5: break return server @@ -48,8 +48,8 @@ class ServersTest(integrated_helpers._IntegratedTestBase): def test_create_and_delete_server(self): """Creates and deletes a server.""" self.flags(stub_network=True) - # Create server + # Create server # Build the server data gradually, checking errors along the way server = {} good_server = self._build_minimal_create_server_request() @@ -184,6 +184,7 @@ class ServersTest(integrated_helpers._IntegratedTestBase): def test_create_and_rebuild_server(self): """Rebuild a server.""" + self.flags(stub_network=True) # create a server with initially has no metadata server = self._build_minimal_create_server_request() @@ -216,6 +217,7 @@ class ServersTest(integrated_helpers._IntegratedTestBase): def test_create_and_rebuild_server_with_metadata(self): """Rebuild a server with metadata.""" + self.flags(stub_network=True) # create a server with initially has no metadata server = self._build_minimal_create_server_request() @@ -225,6 +227,8 @@ class ServersTest(integrated_helpers._IntegratedTestBase): self.assertTrue(created_server['id']) created_server_id = created_server['id'] + created_server = self._wait_for_creation(created_server) + # rebuild the server with metadata post = {} post['rebuild'] = { @@ -252,6 +256,7 @@ class ServersTest(integrated_helpers._IntegratedTestBase): def test_create_and_rebuild_server_with_metadata_removal(self): """Rebuild a server with metadata.""" + self.flags(stub_network=True) # create a server with initially has no metadata server = self._build_minimal_create_server_request() @@ -268,6 +273,8 @@ class ServersTest(integrated_helpers._IntegratedTestBase): self.assertTrue(created_server['id']) created_server_id = created_server['id'] + created_server = self._wait_for_creation(created_server) + # rebuild the server with metadata post = {} post['rebuild'] = { diff --git a/nova/tests/scheduler/test_scheduler.py b/nova/tests/scheduler/test_scheduler.py index 629019eaf..a1281ae73 100644 --- a/nova/tests/scheduler/test_scheduler.py +++ b/nova/tests/scheduler/test_scheduler.py @@ -95,7 +95,7 @@ class SchedulerTestCase(test.TestCase): inst['vcpus'] = kwargs.get('vcpus', 1) inst['memory_mb'] = kwargs.get('memory_mb', 10) inst['local_gb'] = kwargs.get('local_gb', 20) - inst['vm_state'] = kwargs.get('vm_state', vm_state.ACTIVE) + inst['vm_state'] = kwargs.get('vm_state', vm_states.ACTIVE) inst['power_state'] = kwargs.get('power_state', power_state.RUNNING) inst['task_state'] = kwargs.get('task_state', None) return db.instance_create(ctxt, inst) @@ -275,7 +275,7 @@ class SimpleDriverTestCase(test.TestCase): inst['memory_mb'] = kwargs.get('memory_mb', 20) inst['local_gb'] = kwargs.get('local_gb', 30) inst['launched_on'] = kwargs.get('launghed_on', 'dummy') - inst['vm_state'] = kwargs.get('vm_state', vm_state.ACTIVE) + inst['vm_state'] = kwargs.get('vm_state', vm_states.ACTIVE) inst['task_state'] = kwargs.get('task_state', None) inst['power_state'] = kwargs.get('power_state', power_state.RUNNING) return db.instance_create(self.context, inst)['id'] @@ -669,7 +669,7 @@ class SimpleDriverTestCase(test.TestCase): block_migration=False) i_ref = db.instance_get(self.context, instance_id) - self.assertTrue(i_ref['vm_state'] == vm_state.MIGRATE) + self.assertTrue(i_ref['vm_state'] == vm_states.MIGRATE) db.instance_destroy(self.context, instance_id) db.volume_destroy(self.context, v_ref['id']) -- cgit From d60f813201df345507ce0aca7bed0f8b719aabfe Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 22 Aug 2011 11:59:08 -0400 Subject: Fixes/updates to make test_cloud pass. --- nova/api/ec2/cloud.py | 1 + nova/compute/manager.py | 2 +- nova/tests/test_cloud.py | 7 ++++--- nova/virt/fake.py | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index b7c7d2e12..8bddf3032 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -82,6 +82,7 @@ def _gen_key(context, user_id, key_name): # EC2 API: Valid Values: # pending | running | shutting-down | terminated | stopping | stopped _STATE_DESCRIPTION_MAP = { + None: 'pending', vm_states.ACTIVE: 'running', vm_states.BUILD: 'pending', vm_states.REBUILD: 'pending', diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 5a4f62b76..75928f7ef 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -1706,7 +1706,7 @@ class ComputeManager(manager.SchedulerDependentManager): if vm_instance is None: vm_power_state = power_state.NOSTATE else: - vm_power_state = vm_instance["power_state"] + vm_power_state = vm_instance.state if vm_power_state == db_power_state: continue diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index cce9514ec..4d148f39e 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -38,6 +38,7 @@ from nova import test from nova import utils from nova.api.ec2 import cloud from nova.api.ec2 import ec2utils +from nova.compute import vm_states from nova.image import fake @@ -1174,12 +1175,12 @@ class CloudTestCase(test.TestCase): def _wait_for_running(self, instance_id): def is_running(info): - return info['vm_state'] == 'running' + return info['vm_state'] == vm_states.ACTIVE self._wait_for_state(self.context, instance_id, is_running) def _wait_for_stopped(self, instance_id): def is_stopped(info): - return info['vm_state'] == 'stopped' + return info['vm_state'] == vm_states.STOP self._wait_for_state(self.context, instance_id, is_stopped) def _wait_for_terminate(self, instance_id): @@ -1562,7 +1563,7 @@ class CloudTestCase(test.TestCase): 'id': 0, 'root_device_name': '/dev/sdh', 'security_groups': [{'name': 'fake0'}, {'name': 'fake1'}], - 'vm_state': 'stopped', + 'vm_state': vm_states.STOP, 'instance_type': {'name': 'fake_type'}, 'kernel_id': 1, 'ramdisk_id': 2, diff --git a/nova/virt/fake.py b/nova/virt/fake.py index c12ee3ab8..dc0628772 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -120,7 +120,7 @@ class FakeConnection(driver.ComputeDriver): def _map_to_instance_info(self, instance): instance = utils.check_isinstance(instance, FakeInstance) - info = driver.InstanceInfo(instance.name, instance.power_state) + info = driver.InstanceInfo(instance.name, instance.state) return info def list_instances_detail(self): -- cgit From 393c9375626812ecb904d9048c833b0d110e9aa8 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 22 Aug 2011 13:04:05 -0400 Subject: Use 'vm_state' instead of 'state' in instance filters query. --- nova/db/sqlalchemy/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index a5ed2363f..3e690e094 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1239,7 +1239,7 @@ def instance_get_all_by_filters(context, filters): # Filters for exact matches that we can do along with the SQL query... # For other filters that don't match this, we will do regexp matching exact_match_filter_names = ['project_id', 'user_id', 'image_ref', - 'state', 'instance_type_id', 'deleted'] + 'vm_state', 'instance_type_id', 'deleted'] query_filters = [key for key in filters.iterkeys() if key in exact_match_filter_names] -- cgit From ea3684d2a2e60f19bdea6b3117be613103a605dc Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Mon, 22 Aug 2011 13:16:48 -0400 Subject: Fixes for a number of tests. --- nova/compute/api.py | 3 +++ nova/compute/task_states.py | 1 + nova/tests/vmwareapi/db_fakes.py | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index 3664be5ed..0f993015b 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -36,6 +36,7 @@ from nova import utils from nova import volume from nova.compute import instance_types from nova.compute import power_state +from nova.compute import task_states from nova.compute import vm_states from nova.compute.utils import terminate_volumes from nova.scheduler import api as scheduler_api @@ -397,6 +398,8 @@ class API(base.Base): updates['display_name'] = "Server %s" % instance_id instance['display_name'] = updates['display_name'] updates['hostname'] = self.hostname_factory(instance) + updates['vm_state'] = vm_states.BUILD + updates['task_state'] = task_states.SCHEDULING instance = self.update(context, instance_id, **updates) return instance diff --git a/nova/compute/task_states.py b/nova/compute/task_states.py index 55466c783..885a30ebe 100644 --- a/nova/compute/task_states.py +++ b/nova/compute/task_states.py @@ -17,6 +17,7 @@ """Possible task states for instances""" +SCHEDULING='scheduling' BLOCK_DEVICE_MAPPING='block_device_mapping' NETWORKING='networking' SPAWN='spawn' diff --git a/nova/tests/vmwareapi/db_fakes.py b/nova/tests/vmwareapi/db_fakes.py index b046071c7..b56956f96 100644 --- a/nova/tests/vmwareapi/db_fakes.py +++ b/nova/tests/vmwareapi/db_fakes.py @@ -67,7 +67,7 @@ def stub_out_db_instance_api(stubs): 'kernel_id': values['kernel_id'], 'ramdisk_id': values['ramdisk_id'], 'vm_state': vm_states.BUILD, - 'task_state': task_states.SCHEDULE, + 'task_state': task_states.SCHEDULING, 'user_id': values['user_id'], 'project_id': values['project_id'], 'launch_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()), -- cgit From 2fbaac5e07b558d7829253915523f073b07e24d4 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Tue, 23 Aug 2011 10:57:47 -0400 Subject: PEP8 fixes --- nova/api/ec2/cloud.py | 18 ++++++++----- nova/compute/task_states.py | 63 ++++++++++++++++++++++----------------------- nova/compute/vm_states.py | 24 ++++++++--------- nova/tests/test_compute.py | 15 ++++++----- 4 files changed, 63 insertions(+), 57 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index a7a343938..c5a360426 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -93,7 +93,7 @@ _STATE_DESCRIPTION_MAP = { vm_states.VERIFY_RESIZE: 'verify_resize', vm_states.PAUSED: 'pause', vm_states.SUSPENDED: 'suspend', - vm_states.RESCUED: 'rescue' + vm_states.RESCUED: 'rescue', } @@ -104,10 +104,12 @@ def state_description_from_vm_state(vm_state): # TODO(yamahata): hypervisor dependent default device name _DEFAULT_ROOT_DEVICE_NAME = '/dev/sda1' -_DEFAULT_MAPPINGS = {'ami': 'sda1', - 'ephemeral0': 'sda2', - 'root': _DEFAULT_ROOT_DEVICE_NAME, - 'swap': 'sda3'} +_DEFAULT_MAPPINGS = { + 'ami': 'sda1', + 'ephemeral0': 'sda2', + 'root': _DEFAULT_ROOT_DEVICE_NAME, + 'swap': 'sda3', +} def _parse_block_device_mapping(bdm): @@ -1064,8 +1066,10 @@ class CloudController(object): def _format_attr_instance_initiated_shutdown_behavior(instance, result): vm_state = instance['vm_state'] - state_to_value = {vm_states.STOPPED: 'stop', - vm_states.DELETED: 'terminate'} + state_to_value = { + vm_states.STOPPED: 'stop', + vm_states.DELETED: 'terminate', + } value = state_to_value.get(vm_state) if value: result['instanceInitiatedShutdownBehavior'] = value diff --git a/nova/compute/task_states.py b/nova/compute/task_states.py index d186edc3f..5f78495ea 100644 --- a/nova/compute/task_states.py +++ b/nova/compute/task_states.py @@ -17,35 +17,34 @@ """Possible task states for instances""" -SCHEDULING='scheduling' -BLOCK_DEVICE_MAPPING='block_device_mapping' -NETWORKING='networking' -SPAWN='spawn' - -SNAPSHOTTING='snapshotting' -BACKING_UP='backing_up' -PASSWORD='password' - -RESIZE_PREP='resize_prep' -RESIZE_MIGRATING='resize_migrating' -RESIZE_MIGRATED='resize_migrated' -RESIZE_FINISH='resize_finish' -RESIZE_REVERTING='resize_reverting' -RESIZE_CONFIRMING='resize_confirming' - -REBUILDING='rebuilding' - -REBOOTING='rebooting' -HARD_REBOOTING='hard_rebooting' -PAUSING='pausing' -UNPAUSING='unpausing' -SUSPENDING='suspending' -RESUMING='resuming' - -RESCUING='rescuing' -RESCUED='rescued' -UNRESCUING='unrescuing' - -DELETING='deleting' -STOPPING='stopping' -STARTING='starting' +SCHEDULING = 'scheduling' +BLOCK_DEVICE_MAPPING = 'block_device_mapping' +NETWORKING = 'networking' +SPAWN = 'spawn' + +SNAPSHOTTING = 'snapshotting' +BACKING_UP = 'backing_up' +PASSWORD = 'password' + +RESIZE_PREP = 'resize_prep' +RESIZE_MIGRATING = 'resize_migrating' +RESIZE_MIGRATED = 'resize_migrated' +RESIZE_FINISH = 'resize_finish' +RESIZE_REVERTING = 'resize_reverting' +RESIZE_CONFIRMING = 'resize_confirming' + +REBUILDING = 'rebuilding' + +REBOOTING = 'rebooting' +HARD_REBOOTING = 'hard_rebooting' +PAUSING = 'pausing' +UNPAUSING = 'unpausing' +SUSPENDING = 'suspending' +RESUMING = 'resuming' + +RESCUING = 'rescuing' +UNRESCUING = 'unrescuing' + +DELETING = 'deleting' +STOPPING = 'stopping' +STARTING = 'starting' diff --git a/nova/compute/vm_states.py b/nova/compute/vm_states.py index 342fa905e..560e6d688 100644 --- a/nova/compute/vm_states.py +++ b/nova/compute/vm_states.py @@ -17,18 +17,18 @@ """Possible vm states for instances""" -ACTIVE='active' -BUILDING='building' -REBUILDING='rebuilding' +ACTIVE = 'active' +BUILDING = 'building' +REBUILDING = 'rebuilding' -PAUSED='paused' -SUSPENDED='suspended' -RESCUED='rescued' -DELETED='deleted' -STOPPED='stopped' +PAUSED = 'paused' +SUSPENDED = 'suspended' +RESCUED = 'rescued' +DELETED = 'deleted' +STOPPED = 'stopped' -MIGRATING='migrating' -RESIZING='resizing' -VERIFY_RESIZE='verify_resize' +MIGRATING = 'migrating' +RESIZING = 'resizing' +VERIFY_RESIZE = 'verify_resize' -ERROR='error' +ERROR = 'error' diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index 2cf694d2c..11e1fd540 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -1308,14 +1308,17 @@ class ComputeTestCase(test.TestCase): """Test searching instances by state""" c = context.get_admin_context() - instance_id1 = self._create_instance({'power_state': power_state.SHUTDOWN}) + instance_id1 = self._create_instance({ + 'power_state': power_state.SHUTDOWN, + }) instance_id2 = self._create_instance({ - 'id': 2, - 'power_state': power_state.RUNNING}) + 'id': 2, + 'power_state': power_state.RUNNING, + }) instance_id3 = self._create_instance({ - 'id': 10, - 'power_state': power_state.RUNNING}) - + 'id': 10, + 'power_state': power_state.RUNNING, + }) instances = self.compute_api.get_all(c, search_opts={'power_state': power_state.SUSPENDED}) self.assertEqual(len(instances), 0) -- cgit From 657e58113d481d5c03cb3395cd714846434675f0 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Tue, 23 Aug 2011 11:01:57 -0400 Subject: Updated migration number. --- .../versions/040_update_instance_states.py | 57 ---------------------- .../versions/042_update_instance_states.py | 57 ++++++++++++++++++++++ 2 files changed, 57 insertions(+), 57 deletions(-) delete mode 100644 nova/db/sqlalchemy/migrate_repo/versions/040_update_instance_states.py create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py diff --git a/nova/db/sqlalchemy/migrate_repo/versions/040_update_instance_states.py b/nova/db/sqlalchemy/migrate_repo/versions/040_update_instance_states.py deleted file mode 100644 index 07efbf90f..000000000 --- a/nova/db/sqlalchemy/migrate_repo/versions/040_update_instance_states.py +++ /dev/null @@ -1,57 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010 OpenStack LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from sqlalchemy import MetaData, Table, Column, String - -meta = MetaData() - -c_task_state = Column('task_state', - String(length=255, convert_unicode=False, - assert_unicode=None, unicode_error=None, - _warn_on_bytestring=False), - nullable=True) - - -def upgrade(migrate_engine): - # Upgrade operations go here. Don't create your own engine; - # bind migrate_engine to your metadata - meta.bind = migrate_engine - - instances = Table('instances', meta, autoload=True, - autoload_with=migrate_engine) - - c_state = instances.c.state - c_state.alter(name='power_state') - - c_vm_state = instances.c.state_description - c_vm_state.alter(name='vm_state') - - instances.create_column(c_task_state) - - -def downgrade(migrate_engine): - meta.bind = migrate_engine - - instances = Table('instances', meta, autoload=True, - autoload_with=migrate_engine) - - c_state = instances.c.power_state - c_state.alter(name='state') - - c_vm_state = instances.c.vm_state - c_vm_state.alter(name='state_description') - - instances.drop_column('task_state') diff --git a/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py b/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py new file mode 100644 index 000000000..07efbf90f --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py @@ -0,0 +1,57 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from sqlalchemy import MetaData, Table, Column, String + +meta = MetaData() + +c_task_state = Column('task_state', + String(length=255, convert_unicode=False, + assert_unicode=None, unicode_error=None, + _warn_on_bytestring=False), + nullable=True) + + +def upgrade(migrate_engine): + # Upgrade operations go here. Don't create your own engine; + # bind migrate_engine to your metadata + meta.bind = migrate_engine + + instances = Table('instances', meta, autoload=True, + autoload_with=migrate_engine) + + c_state = instances.c.state + c_state.alter(name='power_state') + + c_vm_state = instances.c.state_description + c_vm_state.alter(name='vm_state') + + instances.create_column(c_task_state) + + +def downgrade(migrate_engine): + meta.bind = migrate_engine + + instances = Table('instances', meta, autoload=True, + autoload_with=migrate_engine) + + c_state = instances.c.power_state + c_state.alter(name='state') + + c_vm_state = instances.c.vm_state + c_vm_state.alter(name='state_description') + + instances.drop_column('task_state') -- cgit From 8b3ac90bd53ec81e6669c6169969e1e8da3e2d4f Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Wed, 24 Aug 2011 10:59:12 -0400 Subject: Commit with test data in migration. --- nova/compute/api.py | 1 - .../versions/042_update_instance_states.py | 165 ++++++++++++++++++--- nova/exception.py | 3 + 3 files changed, 149 insertions(+), 20 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index a373bed90..eeb8f47d9 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -761,7 +761,6 @@ class API(base.Base): self.update(context, instance_id, - vm_state=vm_states.ACTIVE, task_state=task_states.DELETING) host = instance['host'] diff --git a/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py b/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py index 07efbf90f..e27b84176 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py @@ -14,44 +14,171 @@ # License for the specific language governing permissions and limitations # under the License. +import sqlalchemy from sqlalchemy import MetaData, Table, Column, String +from nova import log +from nova.compute import task_states +from nova.compute import vm_states +from nova.db.sqlalchemy import models + + +LOG = log.getLogger("farts") meta = MetaData() c_task_state = Column('task_state', - String(length=255, convert_unicode=False, - assert_unicode=None, unicode_error=None, - _warn_on_bytestring=False), - nullable=True) + String(length=255, convert_unicode=False, + assert_unicode=None, unicode_error=None, + _warn_on_bytestring=False), + nullable=True) + + +_upgrade_translations = { + "stopping": { + "vm_state": vm_states.ACTIVE, + "task_state": task_states.STOPPING, + }, + "stopped": { + "vm_state": vm_states.STOPPED, + "task_state": None, + }, + "terminated": { + "vm_state": vm_states.DELETED, + "task_state": None, + }, + "terminating": { + "vm_state": vm_states.ACTIVE, + "task_state": task_states.DELETING, + }, + "running": { + "vm_state": vm_states.ACTIVE, + "task_state": None, + }, + "scheduling": { + "vm_state": vm_states.BUILDING, + "task_state": task_states.SCHEDULING, + }, + "migrating": { + "vm_state": vm_states.MIGRATING, + "task_state": None, + }, + "pending": { + "vm_state": vm_states.BUILDING, + "task_state": task_states.SCHEDULING, + }, +} + + +_downgrade_translations = { + vm_states.ACTIVE: { + None: "running", + task_states.DELETING: "terminating", + task_states.STOPPING: "stopping", + }, + vm_states.BUILDING: { + None: "pending", + task_states.SCHEDULING: "scheduling", + }, + vm_states.STOPPED: { + None: "stopped", + }, + vm_states.REBUILDING: { + None: "pending", + }, + vm_states.DELETED: { + None: "terminated", + }, + vm_states.MIGRATING: { + None: "migrating", + }, +} + + +def _insert_test_data(instance_table): + running_instance = models.Instance() + running_instance.state_description = "running" + stopped_instance = models.Instance() + stopped_instance.state_description = "stopped" + terminated_instance = models.Instance() + terminated_instance.state_description = "terminated" + migrating_instance = models.Instance() + migrating_instance.state_description = "migrating" + scheduling_instance = models.Instance() + scheduling_instance.state_description = "scheduling" + bad_instance = models.Instance() + bad_instance.state_description = "bad_state_description" + + instance_table.insert(running_instance).execute() + instance_table.insert(stopped_instance).execute() + instance_table.insert(terminated_instance).execute() + instance_table.insert(migrating_instance).execute() + instance_table.insert(scheduling_instance).execute() + instance_table.insert(bad_instance).execute() def upgrade(migrate_engine): - # Upgrade operations go here. Don't create your own engine; - # bind migrate_engine to your metadata + #migrate_engine.echo = True meta.bind = migrate_engine - instances = Table('instances', meta, autoload=True, - autoload_with=migrate_engine) - - c_state = instances.c.state + instance_table = Table('instances', meta, autoload=True, + autoload_with=migrate_engine) + _insert_test_data(instance_table) + for instance in instance_table.select().execute(): + LOG.info(instance) + c_state = instance_table.c.state c_state.alter(name='power_state') - c_vm_state = instances.c.state_description + c_vm_state = instance_table.c.state_description c_vm_state.alter(name='vm_state') - instances.create_column(c_task_state) + instance_table.create_column(c_task_state) + for old_state, values in _upgrade_translations.iteritems(): + new_values = { + "old_state": old_state, + "vm_state": values["vm_state"], + "task_state": values["task_state"], + } -def downgrade(migrate_engine): - meta.bind = migrate_engine + update = sqlalchemy.text("UPDATE instances SET task_state=:task_state " + "WHERE vm_state=:old_state") + migrate_engine.execute(update, **new_values) + + update = sqlalchemy.text("UPDATE instances SET vm_state=:vm_state " + "WHERE vm_state=:old_state") + migrate_engine.execute(update, **new_values) - instances = Table('instances', meta, autoload=True, - autoload_with=migrate_engine) + for instance in instance_table.select().execute(): + LOG.info(instance) - c_state = instances.c.power_state + meta.bind = migrate_engine + + instance_table = Table('instances', meta, autoload=True, + autoload_with=migrate_engine) + + for old_vm_state, old_task_states in _downgrade_translations.iteritems(): + for old_task_state, new_state_desc in old_task_states.iteritems(): + if old_task_state: + update = sqlalchemy.text("UPDATE instances " + "SET vm_state=:new_state_desc " + "WHERE task_state=:old_task_state " + "AND vm_state=:old_vm_state") + migrate_engine.execute(update, locals()) + else: + update = sqlalchemy.text("UPDATE instances " + "SET vm_state=:new_state_desc " + "WHERE vm_state=:old_vm_state") + migrate_engine.execute(update, locals()) + + #c_state = instance_table.c.power_state c_state.alter(name='state') - c_vm_state = instances.c.vm_state + #c_vm_state = instance_table.c.vm_state c_vm_state.alter(name='state_description') - instances.drop_column('task_state') + instance_table.drop_column('task_state') + + for instance in instance_table.select().execute(): + LOG.info(instance) + + raise Exception() diff --git a/nova/exception.py b/nova/exception.py index 44af8177e..66740019b 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -318,6 +318,9 @@ class InvalidEc2Id(Invalid): class NotFound(NovaException): message = _("Resource could not be found.") + def __init__(self, *args, **kwargs): + super(NotFound, self).__init__(**kwargs) + class FlagNotSet(NotFound): message = _("Required flag %(flag)s not set.") -- cgit From df77c6c168d4370ec582ffbccd43e3b9cb551b98 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Wed, 24 Aug 2011 11:00:21 -0400 Subject: Commit without test data in migration. --- .../versions/042_update_instance_states.py | 43 +++------------------- 1 file changed, 5 insertions(+), 38 deletions(-) diff --git a/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py b/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py index e27b84176..10704d0da 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py @@ -17,15 +17,13 @@ import sqlalchemy from sqlalchemy import MetaData, Table, Column, String -from nova import log from nova.compute import task_states from nova.compute import vm_states -from nova.db.sqlalchemy import models -LOG = log.getLogger("farts") meta = MetaData() + c_task_state = Column('task_state', String(length=255, convert_unicode=False, assert_unicode=None, unicode_error=None, @@ -94,37 +92,12 @@ _downgrade_translations = { } -def _insert_test_data(instance_table): - running_instance = models.Instance() - running_instance.state_description = "running" - stopped_instance = models.Instance() - stopped_instance.state_description = "stopped" - terminated_instance = models.Instance() - terminated_instance.state_description = "terminated" - migrating_instance = models.Instance() - migrating_instance.state_description = "migrating" - scheduling_instance = models.Instance() - scheduling_instance.state_description = "scheduling" - bad_instance = models.Instance() - bad_instance.state_description = "bad_state_description" - - instance_table.insert(running_instance).execute() - instance_table.insert(stopped_instance).execute() - instance_table.insert(terminated_instance).execute() - instance_table.insert(migrating_instance).execute() - instance_table.insert(scheduling_instance).execute() - instance_table.insert(bad_instance).execute() - - def upgrade(migrate_engine): - #migrate_engine.echo = True meta.bind = migrate_engine instance_table = Table('instances', meta, autoload=True, autoload_with=migrate_engine) - _insert_test_data(instance_table) - for instance in instance_table.select().execute(): - LOG.info(instance) + c_state = instance_table.c.state c_state.alter(name='power_state') @@ -148,9 +121,8 @@ def upgrade(migrate_engine): "WHERE vm_state=:old_state") migrate_engine.execute(update, **new_values) - for instance in instance_table.select().execute(): - LOG.info(instance) +def downgrade(migrate_engine): meta.bind = migrate_engine instance_table = Table('instances', meta, autoload=True, @@ -170,15 +142,10 @@ def upgrade(migrate_engine): "WHERE vm_state=:old_vm_state") migrate_engine.execute(update, locals()) - #c_state = instance_table.c.power_state + c_state = instance_table.c.power_state c_state.alter(name='state') - #c_vm_state = instance_table.c.vm_state + c_vm_state = instance_table.c.vm_state c_vm_state.alter(name='state_description') instance_table.drop_column('task_state') - - for instance in instance_table.select().execute(): - LOG.info(instance) - - raise Exception() -- cgit From 1ee1bda6cd164bd1e3cc400838830a747371ce9e Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Wed, 24 Aug 2011 11:27:02 -0400 Subject: Conversion to SQLAlchemy-style. --- .../versions/042_update_instance_states.py | 55 +++++++++------------- 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py b/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py index 10704d0da..1005ee8a4 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py @@ -33,35 +33,35 @@ c_task_state = Column('task_state', _upgrade_translations = { "stopping": { - "vm_state": vm_states.ACTIVE, + "state_description": vm_states.ACTIVE, "task_state": task_states.STOPPING, }, "stopped": { - "vm_state": vm_states.STOPPED, + "state_description": vm_states.STOPPED, "task_state": None, }, "terminated": { - "vm_state": vm_states.DELETED, + "state_description": vm_states.DELETED, "task_state": None, }, "terminating": { - "vm_state": vm_states.ACTIVE, + "state_description": vm_states.ACTIVE, "task_state": task_states.DELETING, }, "running": { - "vm_state": vm_states.ACTIVE, + "state_description": vm_states.ACTIVE, "task_state": None, }, "scheduling": { - "vm_state": vm_states.BUILDING, + "state_description": vm_states.BUILDING, "task_state": task_states.SCHEDULING, }, "migrating": { - "vm_state": vm_states.MIGRATING, + "state_description": vm_states.MIGRATING, "task_state": None, }, "pending": { - "vm_state": vm_states.BUILDING, + "state_description": vm_states.BUILDING, "task_state": task_states.SCHEDULING, }, } @@ -107,19 +107,10 @@ def upgrade(migrate_engine): instance_table.create_column(c_task_state) for old_state, values in _upgrade_translations.iteritems(): - new_values = { - "old_state": old_state, - "vm_state": values["vm_state"], - "task_state": values["task_state"], - } - - update = sqlalchemy.text("UPDATE instances SET task_state=:task_state " - "WHERE vm_state=:old_state") - migrate_engine.execute(update, **new_values) - - update = sqlalchemy.text("UPDATE instances SET vm_state=:vm_state " - "WHERE vm_state=:old_state") - migrate_engine.execute(update, **new_values) + instance_table.update().\ + values(**values).\ + where(c_vm_state == old_state).\ + execute() def downgrade(migrate_engine): @@ -128,19 +119,7 @@ def downgrade(migrate_engine): instance_table = Table('instances', meta, autoload=True, autoload_with=migrate_engine) - for old_vm_state, old_task_states in _downgrade_translations.iteritems(): - for old_task_state, new_state_desc in old_task_states.iteritems(): - if old_task_state: - update = sqlalchemy.text("UPDATE instances " - "SET vm_state=:new_state_desc " - "WHERE task_state=:old_task_state " - "AND vm_state=:old_vm_state") - migrate_engine.execute(update, locals()) - else: - update = sqlalchemy.text("UPDATE instances " - "SET vm_state=:new_state_desc " - "WHERE vm_state=:old_vm_state") - migrate_engine.execute(update, locals()) + c_task_state = instance_table.c.task_state c_state = instance_table.c.power_state c_state.alter(name='state') @@ -148,4 +127,12 @@ def downgrade(migrate_engine): c_vm_state = instance_table.c.vm_state c_vm_state.alter(name='state_description') + for old_vm_state, old_task_states in _downgrade_translations.iteritems(): + for old_task_state, new_state_desc in old_task_states.iteritems(): + instance_table.update().\ + where(c_task_state == old_task_state).\ + where(c_vm_state == old_vm_state).\ + values(state_description=new_state_desc).\ + execute() + instance_table.drop_column('task_state') -- cgit From 53b0a2ea13e148fc5f461211ca9056b30db6c43d Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Wed, 24 Aug 2011 11:32:58 -0400 Subject: Fix for migrations. --- .../versions/042_update_instance_states.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py b/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py index 1005ee8a4..65bdf601d 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py @@ -33,35 +33,35 @@ c_task_state = Column('task_state', _upgrade_translations = { "stopping": { - "state_description": vm_states.ACTIVE, + "vm_state": vm_states.ACTIVE, "task_state": task_states.STOPPING, }, "stopped": { - "state_description": vm_states.STOPPED, + "vm_state": vm_states.STOPPED, "task_state": None, }, "terminated": { - "state_description": vm_states.DELETED, + "vm_state": vm_states.DELETED, "task_state": None, }, "terminating": { - "state_description": vm_states.ACTIVE, + "vm_state": vm_states.ACTIVE, "task_state": task_states.DELETING, }, "running": { - "state_description": vm_states.ACTIVE, + "vm_state": vm_states.ACTIVE, "task_state": None, }, "scheduling": { - "state_description": vm_states.BUILDING, + "vm_state": vm_states.BUILDING, "task_state": task_states.SCHEDULING, }, "migrating": { - "state_description": vm_states.MIGRATING, + "vm_state": vm_states.MIGRATING, "task_state": None, }, "pending": { - "state_description": vm_states.BUILDING, + "vm_state": vm_states.BUILDING, "task_state": task_states.SCHEDULING, }, } @@ -106,6 +106,9 @@ def upgrade(migrate_engine): instance_table.create_column(c_task_state) + instance_table = Table('instances', meta, autoload=True, + autoload_with=migrate_engine) + for old_state, values in _upgrade_translations.iteritems(): instance_table.update().\ values(**values).\ -- cgit From 007efcab4b668e7a4b1d26ff274693824f6d7445 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Wed, 24 Aug 2011 12:26:05 -0400 Subject: Attempt to fix issue when deleting an instance when it's still in BUILD. --- nova/compute/manager.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 0a1dc13be..802d141ef 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -429,10 +429,15 @@ class ComputeManager(manager.SchedulerDependentManager): return current_power_state = self._get_power_state(context, instance) + if current_power_state == power_state.RUNNING: + vm_state = vm_states.ACTIVE + else: + vm_state = vm_states.BUILDING + self._instance_update(context, instance_id, power_state=current_power_state, - vm_state=vm_states.ACTIVE, + vm_state=vm_state, task_state=None, launched_at=utils.utcnow()) -- cgit From ca8b3c7635208ab0776f51661708ecea1bfc222a Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Wed, 24 Aug 2011 12:42:42 -0400 Subject: Fixed rebuild naming issue and reverted other fix which didn't fix anythin. --- nova/compute/api.py | 2 ++ nova/compute/manager.py | 7 +------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index eeb8f47d9..02bae7262 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1045,6 +1045,8 @@ class API(base.Base): metadata=None, files_to_inject=None): """Rebuild the given instance with the provided metadata.""" instance = db.api.instance_get(context, instance_id) + name = name or instance["display_name"] + invalid_rebuild_states = [ vm_states.BUILDING, vm_states.REBUILDING, diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 802d141ef..0a1dc13be 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -429,15 +429,10 @@ class ComputeManager(manager.SchedulerDependentManager): return current_power_state = self._get_power_state(context, instance) - if current_power_state == power_state.RUNNING: - vm_state = vm_states.ACTIVE - else: - vm_state = vm_states.BUILDING - self._instance_update(context, instance_id, power_state=current_power_state, - vm_state=vm_state, + vm_state=vm_states.ACTIVE, task_state=None, launched_at=utils.utcnow()) -- cgit From 64f946a6a0a6e08d7046ab98776928abe24f8d93 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Wed, 24 Aug 2011 13:01:20 -0400 Subject: Fix for trying rebuilds when instance is not active. --- nova/api/openstack/servers.py | 10 ++++------ nova/compute/api.py | 11 +++-------- nova/exception.py | 2 +- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 4ff9264a6..c5fdda1cf 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -604,9 +604,8 @@ class ControllerV10(Controller): try: self.compute_api.rebuild(context, instance_id, image_id) - except exception.BuildInProgress: - msg = _("Instance %s is currently being rebuilt.") % instance_id - LOG.debug(msg) + except exception.RebuildRequiresActiveInstance: + msg = _("Instance %s must be active to rebuild.") % instance_id raise exc.HTTPConflict(explanation=msg) return webob.Response(status_int=202) @@ -742,9 +741,8 @@ class ControllerV11(Controller): try: self.compute_api.rebuild(context, instance_id, image_href, name, metadata, personalities) - except exception.BuildInProgress: - msg = _("Instance %s is currently being rebuilt.") % instance_id - LOG.debug(msg) + except exception.RebuildRequiresActiveInstance: + msg = _("Instance %s must be active to rebuild.") % instance_id raise exc.HTTPConflict(explanation=msg) return webob.Response(status_int=202) diff --git a/nova/compute/api.py b/nova/compute/api.py index 02bae7262..7ed41fbbc 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1047,14 +1047,9 @@ class API(base.Base): instance = db.api.instance_get(context, instance_id) name = name or instance["display_name"] - invalid_rebuild_states = [ - vm_states.BUILDING, - vm_states.REBUILDING, - ] - - if instance["vm_state"] in invalid_rebuild_states: - msg = _("Instance already building") - raise exception.BuildInProgress(msg) + if instance["vm_state"] != vm_states.ACTIVE: + msg = _("Instance must be active to rebuild.") + raise exception.RebuildRequiresActiveInstance(msg) files_to_inject = files_to_inject or [] metadata = metadata or {} diff --git a/nova/exception.py b/nova/exception.py index 66740019b..889d36c96 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -61,7 +61,7 @@ class ApiError(Error): super(ApiError, self).__init__(outstr) -class BuildInProgress(Error): +class RebuildRequiresActiveInstance(Error): pass -- cgit From 1c7002db8be430cded6efb7378103e17c8df21b4 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Wed, 24 Aug 2011 13:24:37 -0400 Subject: Fixed issue where we were setting the state to DELETED before it's actually deleted. --- nova/compute/manager.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 7697e8e6c..924799dc4 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -490,15 +490,15 @@ class ComputeManager(manager.SchedulerDependentManager): def terminate_instance(self, context, instance_id): """Terminate an instance on this host.""" self._shutdown_instance(context, instance_id, 'Terminating') - instance = self.db.instance_get(context.elevated(), instance_id) + self.db.instance_destroy(context, instance_id) + self._instance_update(context, instance_id, vm_state=vm_states.DELETED, task_state=None, terminated_at=utils.utcnow()) - # TODO(ja): should we keep it in a terminated state for a bit? - self.db.instance_destroy(context, instance_id) + instance = self.db.instance_get(context.elevated(), instance_id) usage_info = utils.usage_from_instance(instance) notifier.notify('compute.%s' % self.host, 'compute.instance.delete', -- cgit From a6bf7c0b2522509dda8dd5e537fad49665aa2af2 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Wed, 24 Aug 2011 13:27:23 -0400 Subject: Added DELETED status to OSAPI just in case. --- nova/api/openstack/common.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index 90b2095b8..07c6fbd11 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -76,6 +76,9 @@ _STATE_MAP = { vm_states.ERROR: { 'default': 'ERROR', }, + vm_states.DELETED: { + 'default': 'DELETED', + }, } -- cgit From 575f72693fa20c7c4157c8ce9702751cd54f1a82 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Wed, 24 Aug 2011 18:00:03 -0400 Subject: Fixed silly ordering issue which was causing tons of test failures. --- nova/compute/manager.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 924799dc4..c29eef07f 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -490,15 +490,15 @@ class ComputeManager(manager.SchedulerDependentManager): def terminate_instance(self, context, instance_id): """Terminate an instance on this host.""" self._shutdown_instance(context, instance_id, 'Terminating') - self.db.instance_destroy(context, instance_id) - + instance = self.db.instance_get(context.elevated(), instance_id) self._instance_update(context, instance_id, vm_state=vm_states.DELETED, task_state=None, terminated_at=utils.utcnow()) - instance = self.db.instance_get(context.elevated(), instance_id) + self.db.instance_destroy(context, instance_id) + usage_info = utils.usage_from_instance(instance) notifier.notify('compute.%s' % self.host, 'compute.instance.delete', -- cgit From 5f1380bfc69913f6aeb2a64e3501f77973493bc3 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Wed, 24 Aug 2011 18:14:13 -0400 Subject: Added fix for parallel build test. --- nova/tests/api/openstack/test_server_actions.py | 2 +- run_tests.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index 0cbbe271d..eae74e75e 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -35,7 +35,7 @@ def return_server_with_attributes(**kwargs): return _return_server -def return_server_with_state(vm_state, task_state=None) +def return_server_with_state(vm_state, task_state=None): return return_server_with_attributes(vm_state=vm_state, task_state=task_state) diff --git a/run_tests.py b/run_tests.py index fd836967e..b9a74769e 100644 --- a/run_tests.py +++ b/run_tests.py @@ -55,6 +55,7 @@ To run a single test module: """ +import eventlet import gettext import heapq import os @@ -62,6 +63,7 @@ import unittest import sys import time +eventlet.monkey_patch() gettext.install('nova', unicode=1) from nose import config -- cgit From 6c4329f846685ee54c5265e5cc56e58e6fbd55e9 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Wed, 24 Aug 2011 18:25:21 -0400 Subject: stub_instance fix from merge conflict --- nova/tests/api/openstack/test_server_actions.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index eae74e75e..6fb21fad3 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -46,7 +46,8 @@ def return_server_with_uuid_and_state(vm_state, task_state=None): return _return_server -def stub_instance(id, metadata=None, image_ref="10", flavor_id="1", name=None): +def stub_instance(id, metadata=None, image_ref="10", flavor_id="1", + name=None, vm_state=None, task_state=None): if metadata is not None: metadata_items = [{'key':k, 'value':v} for k, v in metadata.items()] else: @@ -67,8 +68,8 @@ def stub_instance(id, metadata=None, image_ref="10", flavor_id="1", name=None): "launch_index": 0, "key_name": "", "key_data": "", - "vm_state": vm_states.ACTIVE, - "task_state": None, + "vm_state": vm_state or vm_states.ACTIVE, + "task_state": task_state, "memory_mb": 0, "vcpus": 0, "local_gb": 0, -- cgit From f0fcc4ba61b4658b1e28bd69cfcf395cc408496a Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Thu, 25 Aug 2011 09:04:04 -0400 Subject: Another attempt at fixing hanging test. --- nova/tests/test_xenapi.py | 2 ++ run_tests.py | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index 2f0559366..061e9ffea 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -24,6 +24,8 @@ import re import stubout import ast +eventlet.monkey_patch() + from nova import db from nova import context from nova import flags diff --git a/run_tests.py b/run_tests.py index b9a74769e..fd836967e 100644 --- a/run_tests.py +++ b/run_tests.py @@ -55,7 +55,6 @@ To run a single test module: """ -import eventlet import gettext import heapq import os @@ -63,7 +62,6 @@ import unittest import sys import time -eventlet.monkey_patch() gettext.install('nova', unicode=1) from nose import config -- cgit From 881fb85c9a74fc3436d07d3cf3876c2f815b5618 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Thu, 25 Aug 2011 10:59:04 -0400 Subject: Set state to RESIZING during resizing... --- nova/compute/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index 960d28bd0..89e44258c 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1165,7 +1165,7 @@ class API(base.Base): self.update(context, instance_id, - vm_state=vm_states.ACTIVE, + vm_state=vm_states.RESIZING, task_state=task_states.RESIZE_PREP) instance_ref = self._get_instance(context, instance_id, 'resize') -- cgit From 6e14007c09a465374d1b50cd00549c1be6dc536c Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Thu, 25 Aug 2011 11:11:51 -0400 Subject: Removed RESIZE-CONFIRM hack. --- nova/api/openstack/views/servers.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py index 8f8d04ca0..b0daeb7a8 100644 --- a/nova/api/openstack/views/servers.py +++ b/nova/api/openstack/views/servers.py @@ -21,8 +21,6 @@ import hashlib import os from nova import exception -import nova.compute -import nova.context from nova.api.openstack import common from nova.api.openstack.views import addresses as addresses_view from nova.api.openstack.views import flavors as flavors_view @@ -70,12 +68,6 @@ class ViewBuilder(object): 'name': inst['display_name'], 'status': common.status_from_state(vm_state, task_state)} - ctxt = nova.context.get_admin_context() - compute_api = nova.compute.API() - - if compute_api.has_finished_migration(ctxt, inst['uuid']): - inst_dict['status'] = 'RESIZE-CONFIRM' - # Return the metadata as a dictionary metadata = {} for item in inst.get('metadata', []): -- cgit From 0e3986e71f4bbc848e81f18d6c3e6ad33ab3684c Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Thu, 25 Aug 2011 11:12:53 -0400 Subject: Removed invalid test. --- nova/tests/api/openstack/test_server_actions.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index 6fb21fad3..b9ef41465 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -244,19 +244,6 @@ class ServerActionsTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 500) - def test_resized_server_has_correct_status(self): - req = self.webreq('/1', 'GET') - - def fake_migration_get(*args): - return {} - - self.stubs.Set(nova.db, 'migration_get_by_instance_and_status', - fake_migration_get) - res = req.get_response(fakes.wsgi_app()) - self.assertEqual(res.status_int, 200) - body = json.loads(res.body) - self.assertEqual(body['server']['status'], 'RESIZE-CONFIRM') - def test_confirm_resize_server(self): req = self.webreq('/1/action', 'POST', dict(confirmResize=None)) -- cgit From 423a29ff347d3911ba1a98aa224e2a29bdbb8d4c Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Thu, 25 Aug 2011 11:17:31 -0400 Subject: Set error state when migration prep fails. --- nova/compute/manager.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index c29eef07f..de43a5ced 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -929,8 +929,11 @@ class ComputeManager(manager.SchedulerDependentManager): instance_ref = self.db.instance_get_by_uuid(context, instance_id) if instance_ref['host'] == FLAGS.host: - raise exception.Error(_( - 'Migration error: destination same as source!')) + self._instance_update(context, + instance_id, + vm_state=vm_states.ERROR) + msg = _('Migration error: destination same as source!') + raise exception.Error(msg) old_instance_type = self.db.instance_type_get(context, instance_ref['instance_type_id']) -- cgit From a14e2b1d8cbc87d5bcb31b9127035160fde4acc5 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Thu, 25 Aug 2011 11:44:28 -0400 Subject: Verify resize needs to be set. --- nova/compute/api.py | 8 ++++---- nova/compute/manager.py | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index 89e44258c..47ad04930 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1089,8 +1089,8 @@ class API(base.Base): self.update(context, instance_id, - vm_state=vm_states.VERIFY_RESIZE, - task_state=task_states.RESIZE_REVERTING) + vm_state=vm_states.ACTIVE, + task_state=None) params = {'migration_id': migration_ref['id']} self._cast_compute_message('revert_resize', context, @@ -1115,8 +1115,8 @@ class API(base.Base): self.update(context, instance_id, - vm_state=vm_states.VERIFY_RESIZE, - task_state=task_states.RESIZE_CONFIRMING) + vm_state=vm_states.ACTIVE, + task_state=None) params = {'migration_id': migration_ref['id']} self._cast_compute_message('confirm_resize', context, diff --git a/nova/compute/manager.py b/nova/compute/manager.py index de43a5ced..5427b896e 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -1027,6 +1027,11 @@ class ComputeManager(manager.SchedulerDependentManager): self.driver.finish_migration(context, instance_ref, disk_info, network_info, resize_instance) + self._instance_update(context, + instance_id, + vm_state=vm_states.VERIFY_RESIZE, + task_state=None) + self.db.migration_update(context, migration_id, {'status': 'finished', }) -- cgit From 6758779249d490fd21bfdeae6d40adfc33d8cd17 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Thu, 25 Aug 2011 12:50:36 -0400 Subject: Reverted two mistakes when looking over full diff. --- nova/api/ec2/cloud.py | 10 ++++------ nova/compute/manager.py | 2 -- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index c5a360426..cf9437b08 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -104,12 +104,10 @@ def state_description_from_vm_state(vm_state): # TODO(yamahata): hypervisor dependent default device name _DEFAULT_ROOT_DEVICE_NAME = '/dev/sda1' -_DEFAULT_MAPPINGS = { - 'ami': 'sda1', - 'ephemeral0': 'sda2', - 'root': _DEFAULT_ROOT_DEVICE_NAME, - 'swap': 'sda3', -} +_DEFAULT_MAPPINGS = {'ami': 'sda1', + 'ephemeral0': 'sda2', + 'root': _DEFAULT_ROOT_DEVICE_NAME, + 'swap': 'sda3'} def _parse_block_device_mapping(bdm): diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 5427b896e..a3ced1279 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -547,8 +547,6 @@ class ComputeManager(manager.SchedulerDependentManager): vm_state=vm_states.REBUILDING, task_state=task_states.BLOCK_DEVICE_MAPPING) - bd_mapping = self._setup_block_device_mapping(context, instance_id) - image_ref = kwargs.get('image_ref') instance_ref.image_ref = image_ref instance_ref.injected_files = kwargs.get('injected_files', []) -- cgit From d8d4aff908925b2f351e77291f4a8f394994063d Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Thu, 25 Aug 2011 16:38:38 -0400 Subject: Review feedback. --- nova/api/ec2/cloud.py | 8 +++++--- nova/api/openstack/common.py | 7 ++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index cf9437b08..ac247a0ef 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -79,7 +79,9 @@ def _gen_key(context, user_id, key_name): return {'private_key': private_key, 'fingerprint': fingerprint} -# EC2 API: Valid Values: +# EC2 API can return the following values as documented in the EC2 API +# http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ +# ApiReference-ItemType-InstanceStateType.html # pending | running | shutting-down | terminated | stopping | stopped _STATE_DESCRIPTION_MAP = { None: 'pending', @@ -1065,8 +1067,8 @@ class CloudController(object): result): vm_state = instance['vm_state'] state_to_value = { - vm_states.STOPPED: 'stop', - vm_states.DELETED: 'terminate', + vm_states.STOPPED: 'stopped', + vm_states.DELETED: 'terminated', } value = state_to_value.get(vm_state) if value: diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index 07c6fbd11..bdbae0271 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -84,10 +84,11 @@ _STATE_MAP = { def status_from_state(vm_state, task_state='default'): """Given vm_state and task_state, return a status string.""" - LOG.debug("Generating status for vm_state=%(vm_state)s " - "task_state=%(task_state)s." % locals()) task_map = _STATE_MAP.get(vm_state, dict(default='UNKNOWN_STATE')) - return task_map.get(task_state, task_map['default']) + status = task_map.get(task_state, task_map['default']) + LOG.debug("Generated %(status)s from vm_state=%(vm_state)s " + "task_state=%(task_state)s." % locals()) + return status def vm_state_from_status(status): -- cgit From ae1ac682673648f2a2f364eabd525985f3d16a9d Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Thu, 25 Aug 2011 16:40:15 -0400 Subject: Bumped migration number. --- .../versions/042_update_instance_states.py | 141 --------------------- .../versions/043_update_instance_states.py | 141 +++++++++++++++++++++ 2 files changed, 141 insertions(+), 141 deletions(-) delete mode 100644 nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/043_update_instance_states.py diff --git a/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py b/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py deleted file mode 100644 index 65bdf601d..000000000 --- a/nova/db/sqlalchemy/migrate_repo/versions/042_update_instance_states.py +++ /dev/null @@ -1,141 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010 OpenStack LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import sqlalchemy -from sqlalchemy import MetaData, Table, Column, String - -from nova.compute import task_states -from nova.compute import vm_states - - -meta = MetaData() - - -c_task_state = Column('task_state', - String(length=255, convert_unicode=False, - assert_unicode=None, unicode_error=None, - _warn_on_bytestring=False), - nullable=True) - - -_upgrade_translations = { - "stopping": { - "vm_state": vm_states.ACTIVE, - "task_state": task_states.STOPPING, - }, - "stopped": { - "vm_state": vm_states.STOPPED, - "task_state": None, - }, - "terminated": { - "vm_state": vm_states.DELETED, - "task_state": None, - }, - "terminating": { - "vm_state": vm_states.ACTIVE, - "task_state": task_states.DELETING, - }, - "running": { - "vm_state": vm_states.ACTIVE, - "task_state": None, - }, - "scheduling": { - "vm_state": vm_states.BUILDING, - "task_state": task_states.SCHEDULING, - }, - "migrating": { - "vm_state": vm_states.MIGRATING, - "task_state": None, - }, - "pending": { - "vm_state": vm_states.BUILDING, - "task_state": task_states.SCHEDULING, - }, -} - - -_downgrade_translations = { - vm_states.ACTIVE: { - None: "running", - task_states.DELETING: "terminating", - task_states.STOPPING: "stopping", - }, - vm_states.BUILDING: { - None: "pending", - task_states.SCHEDULING: "scheduling", - }, - vm_states.STOPPED: { - None: "stopped", - }, - vm_states.REBUILDING: { - None: "pending", - }, - vm_states.DELETED: { - None: "terminated", - }, - vm_states.MIGRATING: { - None: "migrating", - }, -} - - -def upgrade(migrate_engine): - meta.bind = migrate_engine - - instance_table = Table('instances', meta, autoload=True, - autoload_with=migrate_engine) - - c_state = instance_table.c.state - c_state.alter(name='power_state') - - c_vm_state = instance_table.c.state_description - c_vm_state.alter(name='vm_state') - - instance_table.create_column(c_task_state) - - instance_table = Table('instances', meta, autoload=True, - autoload_with=migrate_engine) - - for old_state, values in _upgrade_translations.iteritems(): - instance_table.update().\ - values(**values).\ - where(c_vm_state == old_state).\ - execute() - - -def downgrade(migrate_engine): - meta.bind = migrate_engine - - instance_table = Table('instances', meta, autoload=True, - autoload_with=migrate_engine) - - c_task_state = instance_table.c.task_state - - c_state = instance_table.c.power_state - c_state.alter(name='state') - - c_vm_state = instance_table.c.vm_state - c_vm_state.alter(name='state_description') - - for old_vm_state, old_task_states in _downgrade_translations.iteritems(): - for old_task_state, new_state_desc in old_task_states.iteritems(): - instance_table.update().\ - where(c_task_state == old_task_state).\ - where(c_vm_state == old_vm_state).\ - values(state_description=new_state_desc).\ - execute() - - instance_table.drop_column('task_state') diff --git a/nova/db/sqlalchemy/migrate_repo/versions/043_update_instance_states.py b/nova/db/sqlalchemy/migrate_repo/versions/043_update_instance_states.py new file mode 100644 index 000000000..65bdf601d --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/043_update_instance_states.py @@ -0,0 +1,141 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import sqlalchemy +from sqlalchemy import MetaData, Table, Column, String + +from nova.compute import task_states +from nova.compute import vm_states + + +meta = MetaData() + + +c_task_state = Column('task_state', + String(length=255, convert_unicode=False, + assert_unicode=None, unicode_error=None, + _warn_on_bytestring=False), + nullable=True) + + +_upgrade_translations = { + "stopping": { + "vm_state": vm_states.ACTIVE, + "task_state": task_states.STOPPING, + }, + "stopped": { + "vm_state": vm_states.STOPPED, + "task_state": None, + }, + "terminated": { + "vm_state": vm_states.DELETED, + "task_state": None, + }, + "terminating": { + "vm_state": vm_states.ACTIVE, + "task_state": task_states.DELETING, + }, + "running": { + "vm_state": vm_states.ACTIVE, + "task_state": None, + }, + "scheduling": { + "vm_state": vm_states.BUILDING, + "task_state": task_states.SCHEDULING, + }, + "migrating": { + "vm_state": vm_states.MIGRATING, + "task_state": None, + }, + "pending": { + "vm_state": vm_states.BUILDING, + "task_state": task_states.SCHEDULING, + }, +} + + +_downgrade_translations = { + vm_states.ACTIVE: { + None: "running", + task_states.DELETING: "terminating", + task_states.STOPPING: "stopping", + }, + vm_states.BUILDING: { + None: "pending", + task_states.SCHEDULING: "scheduling", + }, + vm_states.STOPPED: { + None: "stopped", + }, + vm_states.REBUILDING: { + None: "pending", + }, + vm_states.DELETED: { + None: "terminated", + }, + vm_states.MIGRATING: { + None: "migrating", + }, +} + + +def upgrade(migrate_engine): + meta.bind = migrate_engine + + instance_table = Table('instances', meta, autoload=True, + autoload_with=migrate_engine) + + c_state = instance_table.c.state + c_state.alter(name='power_state') + + c_vm_state = instance_table.c.state_description + c_vm_state.alter(name='vm_state') + + instance_table.create_column(c_task_state) + + instance_table = Table('instances', meta, autoload=True, + autoload_with=migrate_engine) + + for old_state, values in _upgrade_translations.iteritems(): + instance_table.update().\ + values(**values).\ + where(c_vm_state == old_state).\ + execute() + + +def downgrade(migrate_engine): + meta.bind = migrate_engine + + instance_table = Table('instances', meta, autoload=True, + autoload_with=migrate_engine) + + c_task_state = instance_table.c.task_state + + c_state = instance_table.c.power_state + c_state.alter(name='state') + + c_vm_state = instance_table.c.vm_state + c_vm_state.alter(name='state_description') + + for old_vm_state, old_task_states in _downgrade_translations.iteritems(): + for old_task_state, new_state_desc in old_task_states.iteritems(): + instance_table.update().\ + where(c_task_state == old_task_state).\ + where(c_vm_state == old_vm_state).\ + values(state_description=new_state_desc).\ + execute() + + instance_table.drop_column('task_state') -- cgit From c316782f8879ef321c4545b04bc9d24e11bb4ee6 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Thu, 25 Aug 2011 17:27:10 -0400 Subject: review feedback --- nova/api/ec2/cloud.py | 3 +-- nova/api/openstack/common.py | 7 ++----- nova/compute/manager.py | 12 ++++++------ nova/compute/task_states.py | 21 +++++++++++++++------ nova/compute/vm_states.py | 9 +++++++-- nova/db/sqlalchemy/api.py | 40 ---------------------------------------- 6 files changed, 31 insertions(+), 61 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index ac247a0ef..fe44191c8 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -92,7 +92,6 @@ _STATE_DESCRIPTION_MAP = { vm_states.STOPPED: 'stopped', vm_states.MIGRATING: 'migrate', vm_states.RESIZING: 'resize', - vm_states.VERIFY_RESIZE: 'verify_resize', vm_states.PAUSED: 'pause', vm_states.SUSPENDED: 'suspend', vm_states.RESCUED: 'rescue', @@ -101,7 +100,7 @@ _STATE_DESCRIPTION_MAP = { def state_description_from_vm_state(vm_state): """Map the vm state to the server status string""" - return _STATE_DESCRIPTION_MAP[vm_state] + return _STATE_DESCRIPTION_MAP.get(vm_state, vm_state) # TODO(yamahata): hypervisor dependent default device name diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index bdbae0271..d743a66ef 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -43,8 +43,8 @@ _STATE_MAP = { vm_states.ACTIVE: { 'default': 'ACTIVE', task_states.REBOOTING: 'REBOOT', - task_states.HARD_REBOOTING: 'HARD_REBOOT', - task_states.PASSWORD: 'PASSWORD', + task_states.UPDATING_PASSWORD: 'PASSWORD', + task_states.RESIZE_VERIFY: 'VERIFY_RESIZE', }, vm_states.BUILDING: { 'default': 'BUILD', @@ -61,9 +61,6 @@ _STATE_MAP = { vm_states.RESIZING: { 'default': 'RESIZE', }, - vm_states.VERIFY_RESIZE: { - 'default': 'VERIFY_RESIZE', - }, vm_states.PAUSED: { 'default': 'PAUSED', }, diff --git a/nova/compute/manager.py b/nova/compute/manager.py index a3ced1279..b4c6abae0 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -415,7 +415,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, vm_state=vm_states.BUILDING, - task_state=task_states.SPAWN) + task_state=task_states.SPAWNING) # TODO(vish) check to make sure the availability zone matches try: @@ -557,7 +557,7 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, vm_state=vm_states.REBUILDING, - task_state=task_states.SPAWN) + task_state=task_states.SPAWNING) # pull in new password here since the original password isn't in the db instance_ref.admin_pass = kwargs.get('new_pass', @@ -629,9 +629,9 @@ class ComputeManager(manager.SchedulerDependentManager): None if rotation shouldn't be used (as in the case of snapshots) """ if image_type == "snapshot": - task_state = task_states.SNAPSHOTTING + task_state = task_states.IMAGE_SNAPSHOT elif image_type == "backup": - task_state = task_states.BACKING_UP + task_state = task_states.IMAGE_BACKUP else: raise Exception(_('Image type not recognized %s') % image_type) @@ -1027,8 +1027,8 @@ class ComputeManager(manager.SchedulerDependentManager): self._instance_update(context, instance_id, - vm_state=vm_states.VERIFY_RESIZE, - task_state=None) + vm_state=vm_states.ACTIVE, + task_state=task_states.RESIZE_VERIFY) self.db.migration_update(context, migration_id, {'status': 'finished', }) diff --git a/nova/compute/task_states.py b/nova/compute/task_states.py index 5f78495ea..e3315a542 100644 --- a/nova/compute/task_states.py +++ b/nova/compute/task_states.py @@ -15,16 +15,25 @@ # License for the specific language governing permissions and limitations # under the License. -"""Possible task states for instances""" +"""Possible task states for instances. + +Compute instance task states represent what is happening to the instance at the +current moment. These tasks can be generic, such as 'spawning', or specific, +such as 'block_device_mapping'. These task states allow for a better view into +what an instance is doing and should be displayed to users/administrators as +necessary. + +""" SCHEDULING = 'scheduling' BLOCK_DEVICE_MAPPING = 'block_device_mapping' NETWORKING = 'networking' -SPAWN = 'spawn' +SPAWNING = 'spawning' + +IMAGE_SNAPSHOT = 'image_snapshot' +IMAGE_BACKUP = 'image_backup' -SNAPSHOTTING = 'snapshotting' -BACKING_UP = 'backing_up' -PASSWORD = 'password' +UPDATING_PASSWORD = 'updating_password' RESIZE_PREP = 'resize_prep' RESIZE_MIGRATING = 'resize_migrating' @@ -32,11 +41,11 @@ RESIZE_MIGRATED = 'resize_migrated' RESIZE_FINISH = 'resize_finish' RESIZE_REVERTING = 'resize_reverting' RESIZE_CONFIRMING = 'resize_confirming' +RESIZE_VERIFY = 'resize_verify' REBUILDING = 'rebuilding' REBOOTING = 'rebooting' -HARD_REBOOTING = 'hard_rebooting' PAUSING = 'pausing' UNPAUSING = 'unpausing' SUSPENDING = 'suspending' diff --git a/nova/compute/vm_states.py b/nova/compute/vm_states.py index 560e6d688..6f16c1f09 100644 --- a/nova/compute/vm_states.py +++ b/nova/compute/vm_states.py @@ -15,7 +15,13 @@ # License for the specific language governing permissions and limitations # under the License. -"""Possible vm states for instances""" +"""Possible vm states for instances. + +Compute instance vm states represent the state of an instance as it pertains to +a user or administrator. When combined with task states (task_states.py), a +better picture can be formed regarding the instance's health. + +""" ACTIVE = 'active' BUILDING = 'building' @@ -29,6 +35,5 @@ STOPPED = 'stopped' MIGRATING = 'migrating' RESIZING = 'resizing' -VERIFY_RESIZE = 'verify_resize' ERROR = 'error' diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 08fc81759..7b78e286d 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1484,46 +1484,6 @@ def instance_get_floating_address(context, instance_id): return fixed_ip_refs[0].floating_ips[0]['address'] -@require_admin_context -def instance_set_power_state(context, instance_id, power_state): - session = get_session() - partial = session.query(models.Instance) - - if utils.is_uuid_like(instance_id): - result = partial.filter_by(uuid=instance_id) - else: - result = partial.filter_by(id=instance_id) - - result.update({'power_state': power_state}) - - -@require_admin_context -def instance_set_vm_state(context, instance_id, vm_state): - # vm_state = running, halted, suspended, paused - session = get_session() - partial = session.query(models.Instance) - - if utils.is_uuid_like(instance_id): - result = partial.filter_by(uuid=instance_id) - else: - result = partial.filter_by(id=instance_id) - - result.update({'vm_state': vm_state}) - - -def instance_set_task_state(context, instance_id, task_state): - # task_state = running, halted, suspended, paused - session = get_session() - partial = session.query(models.Instance) - - if utils.is_uuid_like(instance_id): - result = partial.filter_by(uuid=instance_id) - else: - result = partial.filter_by(id=instance_id) - - result.update({'task_state': task_state}) - - @require_context def instance_update(context, instance_id, values): session = get_session() -- cgit From 63b26178407423524390b2a47425b6953c910e00 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Thu, 25 Aug 2011 18:00:32 -0400 Subject: Test fixup after last review feedback commit. --- nova/tests/api/openstack/test_servers.py | 11 ++++------- nova/tests/test_cloud.py | 2 +- nova/tests/test_xenapi.py | 2 -- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 3905e4f7a..f75263c45 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -2488,11 +2488,6 @@ class TestServerStatus(test.TestCase): task_states.REBOOTING) self.assertEqual(response['server']['status'], 'REBOOT') - def test_hard_reboot(self): - response = self._get_with_state(vm_states.ACTIVE, - task_states.HARD_REBOOTING) - self.assertEqual(response['server']['status'], 'HARD_REBOOT') - def test_rebuild(self): response = self._get_with_state(vm_states.REBUILDING) self.assertEqual(response['server']['status'], 'REBUILD') @@ -2506,11 +2501,13 @@ class TestServerStatus(test.TestCase): self.assertEqual(response['server']['status'], 'RESIZE') def test_verify_resize(self): - response = self._get_with_state(vm_states.VERIFY_RESIZE) + response = self._get_with_state(vm_states.ACTIVE, + task_states.RESIZE_VERIFY) self.assertEqual(response['server']['status'], 'VERIFY_RESIZE') def test_password_update(self): - response = self._get_with_state(vm_states.ACTIVE, task_states.PASSWORD) + response = self._get_with_state(vm_states.ACTIVE, + task_states.UPDATING_PASSWORD) self.assertEqual(response['server']['status'], 'PASSWORD') def test_stopped(self): diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index 9d58b7341..9deb5c011 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -1611,7 +1611,7 @@ class CloudTestCase(test.TestCase): self.assertEqual(groupSet, expected_groupSet) self.assertEqual(get_attribute('instanceInitiatedShutdownBehavior'), {'instance_id': 'i-12345678', - 'instanceInitiatedShutdownBehavior': 'stop'}) + 'instanceInitiatedShutdownBehavior': 'stopped'}) self.assertEqual(get_attribute('instanceType'), {'instance_id': 'i-12345678', 'instanceType': 'fake_type'}) diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index 061e9ffea..2f0559366 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -24,8 +24,6 @@ import re import stubout import ast -eventlet.monkey_patch() - from nova import db from nova import context from nova import flags -- cgit From b846d22937ac62549832e16105ed06a21a3e34d0 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Fri, 26 Aug 2011 15:36:33 -0400 Subject: Tiny tweaks to the migration script. --- .../versions/043_update_instance_states.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/nova/db/sqlalchemy/migrate_repo/versions/043_update_instance_states.py b/nova/db/sqlalchemy/migrate_repo/versions/043_update_instance_states.py index 65bdf601d..e58ae5362 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/043_update_instance_states.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/043_update_instance_states.py @@ -33,35 +33,35 @@ c_task_state = Column('task_state', _upgrade_translations = { "stopping": { - "vm_state": vm_states.ACTIVE, + "state_description": vm_states.ACTIVE, "task_state": task_states.STOPPING, }, "stopped": { - "vm_state": vm_states.STOPPED, + "state_description": vm_states.STOPPED, "task_state": None, }, "terminated": { - "vm_state": vm_states.DELETED, + "state_description": vm_states.DELETED, "task_state": None, }, "terminating": { - "vm_state": vm_states.ACTIVE, + "state_description": vm_states.ACTIVE, "task_state": task_states.DELETING, }, "running": { - "vm_state": vm_states.ACTIVE, + "state_description": vm_states.ACTIVE, "task_state": None, }, "scheduling": { - "vm_state": vm_states.BUILDING, + "state_description": vm_states.BUILDING, "task_state": task_states.SCHEDULING, }, "migrating": { - "vm_state": vm_states.MIGRATING, + "state_description": vm_states.MIGRATING, "task_state": None, }, "pending": { - "vm_state": vm_states.BUILDING, + "state_description": vm_states.BUILDING, "task_state": task_states.SCHEDULING, }, } @@ -106,9 +106,6 @@ def upgrade(migrate_engine): instance_table.create_column(c_task_state) - instance_table = Table('instances', meta, autoload=True, - autoload_with=migrate_engine) - for old_state, values in _upgrade_translations.iteritems(): instance_table.update().\ values(**values).\ @@ -135,7 +132,7 @@ def downgrade(migrate_engine): instance_table.update().\ where(c_task_state == old_task_state).\ where(c_vm_state == old_vm_state).\ - values(state_description=new_state_desc).\ + values(vm_state=new_state_desc).\ execute() instance_table.drop_column('task_state') -- cgit From 39ca3df042bd3fa9a8ae2bf97d9383be7360d900 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Mon, 29 Aug 2011 09:45:00 -0400 Subject: Increased migration number. --- .../versions/043_update_instance_states.py | 138 --------------------- .../versions/044_update_instance_states.py | 138 +++++++++++++++++++++ 2 files changed, 138 insertions(+), 138 deletions(-) delete mode 100644 nova/db/sqlalchemy/migrate_repo/versions/043_update_instance_states.py create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/044_update_instance_states.py diff --git a/nova/db/sqlalchemy/migrate_repo/versions/043_update_instance_states.py b/nova/db/sqlalchemy/migrate_repo/versions/043_update_instance_states.py deleted file mode 100644 index e58ae5362..000000000 --- a/nova/db/sqlalchemy/migrate_repo/versions/043_update_instance_states.py +++ /dev/null @@ -1,138 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010 OpenStack LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import sqlalchemy -from sqlalchemy import MetaData, Table, Column, String - -from nova.compute import task_states -from nova.compute import vm_states - - -meta = MetaData() - - -c_task_state = Column('task_state', - String(length=255, convert_unicode=False, - assert_unicode=None, unicode_error=None, - _warn_on_bytestring=False), - nullable=True) - - -_upgrade_translations = { - "stopping": { - "state_description": vm_states.ACTIVE, - "task_state": task_states.STOPPING, - }, - "stopped": { - "state_description": vm_states.STOPPED, - "task_state": None, - }, - "terminated": { - "state_description": vm_states.DELETED, - "task_state": None, - }, - "terminating": { - "state_description": vm_states.ACTIVE, - "task_state": task_states.DELETING, - }, - "running": { - "state_description": vm_states.ACTIVE, - "task_state": None, - }, - "scheduling": { - "state_description": vm_states.BUILDING, - "task_state": task_states.SCHEDULING, - }, - "migrating": { - "state_description": vm_states.MIGRATING, - "task_state": None, - }, - "pending": { - "state_description": vm_states.BUILDING, - "task_state": task_states.SCHEDULING, - }, -} - - -_downgrade_translations = { - vm_states.ACTIVE: { - None: "running", - task_states.DELETING: "terminating", - task_states.STOPPING: "stopping", - }, - vm_states.BUILDING: { - None: "pending", - task_states.SCHEDULING: "scheduling", - }, - vm_states.STOPPED: { - None: "stopped", - }, - vm_states.REBUILDING: { - None: "pending", - }, - vm_states.DELETED: { - None: "terminated", - }, - vm_states.MIGRATING: { - None: "migrating", - }, -} - - -def upgrade(migrate_engine): - meta.bind = migrate_engine - - instance_table = Table('instances', meta, autoload=True, - autoload_with=migrate_engine) - - c_state = instance_table.c.state - c_state.alter(name='power_state') - - c_vm_state = instance_table.c.state_description - c_vm_state.alter(name='vm_state') - - instance_table.create_column(c_task_state) - - for old_state, values in _upgrade_translations.iteritems(): - instance_table.update().\ - values(**values).\ - where(c_vm_state == old_state).\ - execute() - - -def downgrade(migrate_engine): - meta.bind = migrate_engine - - instance_table = Table('instances', meta, autoload=True, - autoload_with=migrate_engine) - - c_task_state = instance_table.c.task_state - - c_state = instance_table.c.power_state - c_state.alter(name='state') - - c_vm_state = instance_table.c.vm_state - c_vm_state.alter(name='state_description') - - for old_vm_state, old_task_states in _downgrade_translations.iteritems(): - for old_task_state, new_state_desc in old_task_states.iteritems(): - instance_table.update().\ - where(c_task_state == old_task_state).\ - where(c_vm_state == old_vm_state).\ - values(vm_state=new_state_desc).\ - execute() - - instance_table.drop_column('task_state') diff --git a/nova/db/sqlalchemy/migrate_repo/versions/044_update_instance_states.py b/nova/db/sqlalchemy/migrate_repo/versions/044_update_instance_states.py new file mode 100644 index 000000000..e58ae5362 --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/044_update_instance_states.py @@ -0,0 +1,138 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import sqlalchemy +from sqlalchemy import MetaData, Table, Column, String + +from nova.compute import task_states +from nova.compute import vm_states + + +meta = MetaData() + + +c_task_state = Column('task_state', + String(length=255, convert_unicode=False, + assert_unicode=None, unicode_error=None, + _warn_on_bytestring=False), + nullable=True) + + +_upgrade_translations = { + "stopping": { + "state_description": vm_states.ACTIVE, + "task_state": task_states.STOPPING, + }, + "stopped": { + "state_description": vm_states.STOPPED, + "task_state": None, + }, + "terminated": { + "state_description": vm_states.DELETED, + "task_state": None, + }, + "terminating": { + "state_description": vm_states.ACTIVE, + "task_state": task_states.DELETING, + }, + "running": { + "state_description": vm_states.ACTIVE, + "task_state": None, + }, + "scheduling": { + "state_description": vm_states.BUILDING, + "task_state": task_states.SCHEDULING, + }, + "migrating": { + "state_description": vm_states.MIGRATING, + "task_state": None, + }, + "pending": { + "state_description": vm_states.BUILDING, + "task_state": task_states.SCHEDULING, + }, +} + + +_downgrade_translations = { + vm_states.ACTIVE: { + None: "running", + task_states.DELETING: "terminating", + task_states.STOPPING: "stopping", + }, + vm_states.BUILDING: { + None: "pending", + task_states.SCHEDULING: "scheduling", + }, + vm_states.STOPPED: { + None: "stopped", + }, + vm_states.REBUILDING: { + None: "pending", + }, + vm_states.DELETED: { + None: "terminated", + }, + vm_states.MIGRATING: { + None: "migrating", + }, +} + + +def upgrade(migrate_engine): + meta.bind = migrate_engine + + instance_table = Table('instances', meta, autoload=True, + autoload_with=migrate_engine) + + c_state = instance_table.c.state + c_state.alter(name='power_state') + + c_vm_state = instance_table.c.state_description + c_vm_state.alter(name='vm_state') + + instance_table.create_column(c_task_state) + + for old_state, values in _upgrade_translations.iteritems(): + instance_table.update().\ + values(**values).\ + where(c_vm_state == old_state).\ + execute() + + +def downgrade(migrate_engine): + meta.bind = migrate_engine + + instance_table = Table('instances', meta, autoload=True, + autoload_with=migrate_engine) + + c_task_state = instance_table.c.task_state + + c_state = instance_table.c.power_state + c_state.alter(name='state') + + c_vm_state = instance_table.c.vm_state + c_vm_state.alter(name='state_description') + + for old_vm_state, old_task_states in _downgrade_translations.iteritems(): + for old_task_state, new_state_desc in old_task_states.iteritems(): + instance_table.update().\ + where(c_task_state == old_task_state).\ + where(c_vm_state == old_vm_state).\ + values(vm_state=new_state_desc).\ + execute() + + instance_table.drop_column('task_state') -- cgit From fdbb12e1e4b0b2cc28344510afb1c57620240901 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Tue, 30 Aug 2011 10:42:51 -0400 Subject: Fix a bad merge on my part, this fixes rebuilds\! --- nova/compute/manager.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 167be66db..0477db745 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -547,9 +547,6 @@ class ComputeManager(manager.SchedulerDependentManager): vm_state=vm_states.REBUILDING, task_state=task_states.BLOCK_DEVICE_MAPPING) - image_ref = kwargs.get('image_ref') - instance_ref.image_ref = image_ref - instance_ref.injected_files = kwargs.get('injected_files', []) network_info = self.network_api.get_instance_nw_info(context, instance_ref) @@ -572,11 +569,9 @@ class ComputeManager(manager.SchedulerDependentManager): power_state=current_power_state, vm_state=vm_states.ACTIVE, task_state=None, - image_ref=image_ref, launched_at=utils.utcnow()) - usage_info = utils.usage_from_instance(instance_ref, - image_ref=image_ref) + usage_info = utils.usage_from_instance(instance_ref) notifier.notify('compute.%s' % self.host, 'compute.instance.rebuild', notifier.INFO, -- cgit From c9a6681f484f38778987fbbaa352d07bd8f747c3 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Wed, 31 Aug 2011 10:14:07 -0400 Subject: Removed extraneous import and s/vm_state.STOP/vm_states.STOPPED/ --- nova/db/sqlalchemy/api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 24e1772f6..631e53ceb 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -28,6 +28,7 @@ from nova import flags from nova import ipv6 from nova import utils from nova import log as logging +from nova.compute import vm_states from nova.db.sqlalchemy import models from nova.db.sqlalchemy.session import get_session from sqlalchemy import or_ @@ -1102,11 +1103,10 @@ def instance_destroy(context, instance_id): def instance_stop(context, instance_id): session = get_session() with session.begin(): - from nova.compute import power_state session.query(models.Instance).\ filter_by(id=instance_id).\ update({'host': None, - 'vm_state': vm_state.STOP, + 'vm_state': vm_states.STOPPED, 'task_state': None, 'updated_at': literal_column('updated_at')}) session.query(models.SecurityGroupInstanceAssociation).\ -- cgit