这里简单对nova resize的代码调用简单记录,写得不好的地方还请见谅!

测试环境:OpenStack Liberty(rdo)

# compute-1计算节点下一台test-cirros-1的虚拟机

[root@controller1 ~(keystone_admin)]# nova show test-cirros-1

+--------------------------------------+------------------------------------------------------------+

| Property                             | Value                                                      |

+--------------------------------------+------------------------------------------------------------+

| NetworkA network                     | 192.168.0.26                                               |

| OS-DCF:diskConfig                    | MANUAL                                                     |

| OS-EXT-AZ:availability_zone          | nova                                                       |

| OS-EXT-SRV-ATTR:host                 | compute-1                                                  |

| OS-EXT-SRV-ATTR:hostname             | test-cirros-1                                              |

| OS-EXT-SRV-ATTR:hypervisor_hostname  | compute-1                                                  |

| OS-EXT-SRV-ATTR:instance_name        | instance-00000018                                          |

| OS-EXT-SRV-ATTR:kernel_id            |                                                            |

| OS-EXT-SRV-ATTR:launch_index         | 0                                                          |

| OS-EXT-SRV-ATTR:ramdisk_id           |                                                            |

| OS-EXT-SRV-ATTR:reservation_id       | r-a30b0e7o                                                 |

| OS-EXT-SRV-ATTR:root_device_name     | /dev/vda                                                   |

| OS-EXT-SRV-ATTR:user_data            | -                                                          |

| OS-EXT-STS:power_state               | 1                                                          |

| OS-EXT-STS:task_state                | -                                                          |

| OS-EXT-STS:vm_state                  | active                                                     |

| OS-SRV-USG:launched_at               | 2016-04-17T13:21:54.000000                                 |

| OS-SRV-USG:terminated_at             | -                                                          |

| accessIPv4                           |                                                            |

| accessIPv6                           |                                                            |

| config_drive                         |                                                            |

| created                              | 2016-04-17T12:36:38Z                                       |

| flavor                               | m1.tiny (1)                                                |

| hostId                               | f6f5e4c5991491de79426865084507060287154e125bc2657a21fd23   |

| id                                   | 21015376-8c4f-4fad-a834-245b57f23dcc                       |

| p_w_picpath                                | cirros-0.3.4-x86_64 (1acb04d0-a910-45e4-aad3-5e6686fd1a91) |

| key_name                             | -                                                          |

| locked                               | False                                                      |

| metadata                             | {}                                                         |

| name                                 | test-cirros-1                                              |

| os-extended-volumes:volumes_attached | []                                                         |

| progress                             | 0                                                          |

| security_groups                      | default                                                    |

| status                               | ACTIVE                                                     |

| tenant_id                            | 52b09594cf604d45ae3a12e44da8eac9                           |

| updated                              | 2016-04-17T13:21:55Z                                       |

| user_id                              | 082ef596bad842d180cc5f9326b1fd35                           |

+--------------------------------------+------------------------------------------------------------+

/usr/lib/python2.7/site-packages/nova/compute/api.py(2621)resize()  # 设置断点 @wrap_check_policy    @check_instance_lock    @check_instance_cell    @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED])    def resize(self, context, instance, flavor_id=None, clean_shutdown=True,               **extra_instance_updates):        。。。        self._check_auto_disk_config(instance, **extra_instance_updates)        current_instance_type = instance.get_flavor()        # If flavor_id is not provided, only migrate the instance.        if not flavor_id:            LOG.debug("flavor_id is None. Assuming migration.",                      instance=instance)            new_instance_type = current_instance_type        else:            new_instance_type = flavors.get_flavor_by_flavor_id(                    flavor_id, read_deleted="no")            if (new_instance_type.get('root_gb') == 0 and                current_instance_type.get('root_gb') != 0 and                not self.is_volume_backed_instance(context, instance)):                reason = _('Resize to zero disk flavor is not allowed.')                raise exception.CannotResizeDisk(reason=reason)            if (new_instance_type.get('root_gb') < current_instance_type.get('root_gb')):  # 这个是我加的,防止resize到disk小的flavor。                reason = _('Resize to smaller disk flavor is not allowed.')                raise exception.CannotResizeDisk(reason=reason)        。。。。。。                  instance.task_state = task_states.RESIZE_PREP        instance.progress = 0        instance.update(extra_instance_updates)        instance.save(expected_task_state=[None])          filter_properties = {'ignore_hosts': []}        if not CONF.allow_resize_to_same_host:     # 是否enable allow_resize_to_same_host,还是走调度            filter_properties['ignore_hosts'].append(instance.host)              。。。        scheduler_hint = {'filter_properties': filter_properties}        self.compute_task_api.resize_instance(context, instance,      # self.compute_task_api=conductor.ComputeTaskAPI()                extra_instance_updates, scheduler_hint=scheduler_hint,                flavor=new_instance_type,                reservations=quotas.reservations or [],                clean_shutdown=clean_shutdown)

虚拟机状态发生改变

[root@controller1 ~(keystone_admin)]# nova list+--------------------------------------+---------------+--------+-------------+-------------+-----------------------+| ID                                   | Name          | Status | Task State  | Power State | Networks              |+--------------------------------------+---------------+--------+-------------+-------------+-----------------------+| 21015376-8c4f-4fad-a834-245b57f23dcc | test-cirros-1 | RESIZE | resize_prep | Running     | NetworkA=192.168.0.26 |+--------------------------------------+---------------+--------+-------------+-------------+-----------------------+

进入conductor的resize_instance function

/usr/lib/python2.7/site-packages/nova/conductor/api.py189 class ComputeTaskAPI(object):190     """ComputeTask API that queues up compute tasks for nova-conductor."""191192     def __init__(self):193         self.conductor_compute_rpcapi = rpcapi.ComputeTaskAPI()194195     def resize_instance(self, context, instance, extra_instance_updates,196                         scheduler_hint, flavor, reservations,197                         clean_shutdown=True):198         # NOTE(comstud): 'extra_instance_updates' is not used here but is199         # needed for compatibility with the cells_rpcapi version of this200         # method.201         self.conductor_compute_rpcapi.migrate_server(              # rpc操作,走消息队列202             context, instance, scheduler_hint, live=False, rebuild=False,      # live是False,冷迁移203             flavor=flavor, block_migration=None, disk_over_commit=None,204             reservations=reservations, clean_shutdown=clean_shutdown)

/usr/lib/python2.7/site-packages/nova/conductor/rpcapi.pydef migrate_server(self, context, instance, scheduler_hint, live, rebuild,                  flavor, block_migration, disk_over_commit,                  reservations=None, clean_shutdown=True, request_spec=None):        kw = {'instance': instance, 'scheduler_hint': scheduler_hint,              'live': live, 'rebuild': rebuild, 'flavor': flavor,              'block_migration': block_migration,              'disk_over_commit': disk_over_commit,              'reservations': reservations,              'clean_shutdown': clean_shutdown,              'request_spec': request_spec,              }        version = '1.13'        if not self.client.can_send_version(version):            del kw['request_spec']            version = '1.11'        if not self.client.can_send_version(version):            del kw['clean_shutdown']            version = '1.10'        if not self.client.can_send_version(version):            kw['flavor'] = objects_base.obj_to_primitive(flavor)            version = '1.6'        if not self.client.can_send_version(version):            kw['instance'] = jsonutils.to_primitive(                    objects_base.obj_to_primitive(instance))            version = '1.4'        cctxt = self.client.prepare(version=version)        return cctxt.call(context, 'migrate_server', **kw)

# nova resize实际上是冷迁移的一种

/usr/lib/python2.7/site-packages/nova/conductor/manager.py(551)migrate_server()def migrate_server(self, context, instance, scheduler_hint, live, rebuild,            flavor, block_migration, disk_over_commit, reservations=None,            clean_shutdown=True, request_spec=None):        if instance and not isinstance(instance, nova_object.NovaObject):            # NOTE(danms): Until v2 of the RPC API, we need to tolerate            # old-world instance objects here            attrs = ['metadata', 'system_metadata', 'info_cache',                     'security_groups']            instance = objects.Instance._from_db_object(                context, objects.Instance(), instance,                expected_attrs=attrs)        # NOTE: Remove this when we drop support for v1 of the RPC API        if flavor and not isinstance(flavor, objects.Flavor):            # Code downstream may expect extra_specs to be populated since it            # is receiving an object, so lookup the flavor to ensure this.            flavor = objects.Flavor.get_by_id(context, flavor['id'])        if live and not rebuild and not flavor:            self._live_migrate(context, instance, scheduler_hint,                               block_migration, disk_over_commit, request_spec)        elif not live and not rebuild and flavor:            instance_uuid = instance.uuid            with compute_utils.EventReporter(context, 'cold_migrate',                                             instance_uuid):                self._cold_migrate(context, instance, flavor,                                   scheduler_hint['filter_properties'],                                   reservations, clean_shutdown)        else:            raise NotImplementedError()            # 冷迁移functiondef _cold_migrate(self, context, instance, flavor, filter_properties,                      reservations, clean_shutdown):        p_w_picpath = utils.get_p_w_picpath_from_system_metadata(            instance.system_metadata)        request_spec = scheduler_utils.build_request_spec(            context, p_w_picpath, [instance], instance_type=flavor)        task = self._build_cold_migrate_task(context, instance, flavor,                                             filter_properties, request_spec,                                             reservations, clean_shutdown)        try:            task.execute()def _build_cold_migrate_task(self, context, instance, flavor,                                 filter_properties, request_spec, reservations,                                 clean_shutdown):        return migrate.MigrationTask(context, instance, flavor,                                     filter_properties, request_spec,                                     reservations, clean_shutdown,                                     self.compute_rpcapi,                                     self.scheduler_client)

resize的prepare

/usr/lib/python2.7/site-packages/nova/conductor/tasks/migrate.pyclass MigrationTask(base.TaskBase):    def __init__(self, context, instance, flavor, filter_properties,                 request_spec, reservations, clean_shutdown, compute_rpcapi,                 scheduler_client):        super(MigrationTask, self).__init__(context, instance)        self.clean_shutdown = clean_shutdown        self.request_spec = request_spec        self.reservations = reservations        self.filter_properties = filter_properties        self.flavor = flavor        self.quotas = None        self.compute_rpcapi = compute_rpcapi        self.scheduler_client = scheduler_client    def _execute(self):        p_w_picpath = self.request_spec.get('p_w_picpath')        self.quotas = objects.Quotas.from_reservations(self.context,                                                       self.reservations,                                                       instance=self.instance)        scheduler_utils.setup_instance_group(self.context, self.request_spec,                                             self.filter_properties)        scheduler_utils.populate_retry(self.filter_properties,                                       self.instance.uuid)        # TODO(sbauza): Hydrate here the object until we modify the        # scheduler.utils methods to directly use the RequestSpec object        spec_obj = objects.RequestSpec.from_primitives(            self.context, self.request_spec, self.filter_properties)        hosts = self.scheduler_client.select_destinations(            self.context, spec_obj)        host_state = hosts[0]        scheduler_utils.populate_filter_properties(self.filter_properties,                                                   host_state)        # context is not serializable        self.filter_properties.pop('context', None)        (host, node) = (host_state['host'], host_state['nodename'])        self.compute_rpcapi.prep_resize(            self.context, p_w_picpath, self.instance, self.flavor, host,            self.reservations, request_spec=self.request_spec,            filter_properties=self.filter_properties, node=node,            clean_shutdown=self.clean_shutdown)# 又是rpc/usr/lib/python2.7/site-packages/nova/compute/rpcapi.py def prep_resize(self, ctxt, p_w_picpath, instance, instance_type, host,                    reservations=None, request_spec=None,                    filter_properties=None, node=None,                    clean_shutdown=True):        p_w_picpath_p = jsonutils.to_primitive(p_w_picpath)        msg_args = {'instance': instance,                    'instance_type': instance_type,                    'p_w_picpath': p_w_picpath_p,                    'reservations': reservations,                    'request_spec': request_spec,                    'filter_properties': filter_properties,                    'node': node,                    'clean_shutdown': clean_shutdown}        version = '4.1'        if not self.client.can_send_version(version):            version = '4.0'            msg_args['instance_type'] = objects_base.obj_to_primitive(                                            instance_type)        cctxt = self.client.prepare(server=host, version=version)        cctxt.cast(ctxt, 'prep_resize', **msg_args)                # prep_resize function/usr/lib/python2.7/site-packages/nova/compute/manager.pydef prep_resize(self, context, p_w_picpath, instance, instance_type,                    reservations, request_spec, filter_properties, node,                    clean_shutdown):        """Initiates the process of moving a running instance to another host.        Possibly changes the RAM and disk size in the process.        """        if node is None:            node = self.driver.get_available_nodes(refresh=True)[0]            LOG.debug("No node specified, defaulting to %s", node,                      instance=instance)        # NOTE(melwitt): Remove this in version 5.0 of the RPC API        # Code downstream may expect extra_specs to be populated since it        # is receiving an object, so lookup the flavor to ensure this.        if not isinstance(instance_type, objects.Flavor):            instance_type = objects.Flavor.get_by_id(context,                                                     instance_type['id'])        quotas = objects.Quotas.from_reservations(context,                                                  reservations,                                                  instance=instance)        with self._error_out_instance_on_exception(context, instance,                                                   quotas=quotas):            compute_utils.notify_usage_exists(self.notifier, context, instance,                                              current_period=True)            self._notify_about_instance_usage(                    context, instance, "resize.prep.start")            try:                self._prep_resize(context, p_w_picpath, instance,                                  instance_type, quotas,                                  request_spec, filter_properties,                                  node, clean_shutdown)                                  # _prep_resize functiondef _prep_resize(self, context, p_w_picpath, instance, instance_type,            quotas, request_spec, filter_properties, node,            clean_shutdown=True):        if not filter_properties:            filter_properties = {}        if not instance.host:            self._set_instance_obj_error_state(context, instance)            msg = _('Instance has no source host')            raise exception.MigrationError(reason=msg)        same_host = instance.host == self.host        # if the flavor IDs match, it's migrate; otherwise resize        if same_host and instance_type.id == instance['instance_type_id']:            # check driver whether support migrate to same host            if not self.driver.capabilities['supports_migrate_to_same_host']:                raise exception.UnableToMigrateToSelf(                    instance_id=instance.uuid, host=self.host)        # NOTE(danms): Stash the new instance_type to avoid having to        # look it up in the database later        instance.new_flavor = instance_type        # NOTE(mriedem): Stash the old vm_state so we can set the        # resized/reverted instance back to the same state later.        vm_state = instance.vm_state        LOG.debug('Stashing vm_state: %s', vm_state, instance=instance)        instance.system_metadata['old_vm_state'] = vm_state        instance.save()        limits = filter_properties.get('limits', {})        rt = self._get_resource_tracker(node)        with rt.resize_claim(context, instance, instance_type,                             p_w_picpath_meta=p_w_picpath, limits=limits) as claim:            LOG.info(_LI('Migrating'), context=context, instance=instance)            self.compute_rpcapi.resize_instance(                           #                     context, instance, claim.migration, p_w_picpath,                    instance_type, quotas.reservations,                    clean_shutdown)

又是rpc

/usr/lib/python2.7/site-packages/nova/compute/rpcapi.pydef resize_instance(self, ctxt, instance, migration, p_w_picpath, instance_type,                        reservations=None, clean_shutdown=True):        msg_args = {'instance': instance, 'migration': migration,                    'p_w_picpath': p_w_picpath, 'reservations': reservations,                    'instance_type': instance_type,                    'clean_shutdown': clean_shutdown,        }        version = '4.1'        if not self.client.can_send_version(version):            msg_args['instance_type'] = objects_base.obj_to_primitive(                                            instance_type)            version = '4.0'        cctxt = self.client.prepare(server=_compute_host(None, instance),                version=version)        cctxt.cast(ctxt, 'resize_instance', **msg_args)

 

/usr/lib/python2.7/site-packages/nova/compute/manager.py(3765)resize_instance()def resize_instance(self, context, instance, p_w_picpath,                        reservations, migration, instance_type,                        clean_shutdown):        """Starts the migration of a running instance to another host."""        quotas = objects.Quotas.from_reservations(context,                                                  reservations,                                                  instance=instance)        with self._error_out_instance_on_exception(context, instance,                                                   quotas=quotas):            # TODO(chaochin) Remove this until v5 RPC API            # Code downstream may expect extra_specs to be populated since it            # is receiving an object, so lookup the flavor to ensure this.            if (not instance_type or                not isinstance(instance_type, objects.Flavor)):                instance_type = objects.Flavor.get_by_id(                    context, migration['new_instance_type_id'])            network_info = self.network_api.get_instance_nw_info(context,                                                                 instance)            migration.status = 'migrating'            with migration.obj_as_admin():                migration.save()            instance.task_state = task_states.RESIZE_MIGRATING            instance.save(expected_task_state=task_states.RESIZE_PREP)            self._notify_about_instance_usage(                context, instance, "resize.start", network_info=network_info)            bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(                    context, instance.uuid)            block_device_info = self._get_instance_block_device_info(                                context, instance, bdms=bdms)            timeout, retry_interval = self._get_power_off_values(context,                                            instance, clean_shutdown)            disk_info = self.driver.migrate_disk_and_power_off(        # virt/driver.py                    context, instance, migration.dest_host,                    instance_type, network_info,                    block_device_info,                    timeout, retry_interval)            self._terminate_volume_connections(context, instance, bdms)  # 断开volume的连接            migration_p = obj_base.obj_to_primitive(migration)            self.network_api.migrate_instance_start(context,                                                    instance,                                                    migration_p)            migration.status = 'post-migrating'            with migration.obj_as_admin():                migration.save()            instance.host = migration.dest_compute            instance.node = migration.dest_node            instance.task_state = task_states.RESIZE_MIGRATED            instance.save(expected_task_state=task_states.RESIZE_MIGRATING)            self.compute_rpcapi.finish_resize(context, instance,             # rpc操作                    migration, p_w_picpath, disk_info,                    migration.dest_compute, reservations=quotas.reservations)            self._notify_about_instance_usage(context, instance, "resize.end",                                              network_info=network_info)            self.instance_events.clear_events_for_instance(instance)

虚拟机状态也发生了改变

[root@controller1 ~(keystone_admin)]# nova list

+--------------------------------------+---------------+--------+------------------+-------------+-----------------------+

| ID                                   | Name          | Status | Task State       | Power State | Networks              |

+--------------------------------------+---------------+--------+------------------+-------------+-----------------------+

| 21015376-8c4f-4fad-a834-245b57f23dcc | test-cirros-1 | RESIZE | resize_migrating | Running     | NetworkA=192.168.0.26 |

+--------------------------------------+---------------+--------+------------------+-------------+-----------------------+

[root@controller1 ~(keystone_admin)]# nova list

+--------------------------------------+---------------+--------+-----------------+-------------+-----------------------+

| ID                                   | Name          | Status | Task State      | Power State | Networks              |

+--------------------------------------+---------------+--------+-----------------+-------------+-----------------------+

| 21015376-8c4f-4fad-a834-245b57f23dcc | test-cirros-1 | RESIZE | resize_migrated | Running     | NetworkA=192.168.0.26 |

+--------------------------------------+---------------+--------+-----------------+-------------+-----------------------+

instance.save(expected_task_state=task_states.RESIZE_MIGRATING)  # save写库操作

rpc操作

/usr/lib/python2.7/site-packages/nova/compute/rpcapi.pydef finish_resize(self, ctxt, instance, migration, p_w_picpath, disk_info,            host, reservations=None):        version = '4.0'        cctxt = self.client.prepare(server=host, version=version)        cctxt.cast(ctxt, 'finish_resize',                   instance=instance, migration=migration,                   p_w_picpath=p_w_picpath, disk_info=disk_info, reservations=reservations)

# resize的finish过程

/usr/lib/python2.7/site-packages/nova/compute/manager.pydef finish_resize(self, context, disk_info, p_w_picpath, instance,                      reservations, migration):        """Completes the migration process.        Sets up the newly transferred disk and turns on the instance at its        new host machine.        """        quotas = objects.Quotas.from_reservations(context,                                                  reservations,                                                  instance=instance)        try:            p_w_picpath_meta = objects.ImageMeta.from_dict(p_w_picpath)            self._finish_resize(context, instance, migration,                                disk_info, p_w_picpath_meta)            quotas.commit()        except Exception:            LOG.exception(_LE('Setting instance vm_state to ERROR'),                          instance=instance)            with excutils.save_and_reraise_exception():                try:                    quotas.rollback()                except Exception:                    LOG.exception(_LE("Failed to rollback quota for failed "                                      "finish_resize"),                                  instance=instance)                self._set_instance_obj_error_state(context, instance)                # _finish_resize functiondef _finish_resize(self, context, instance, migration, disk_info,                       p_w_picpath_meta):        resize_instance = False        old_instance_type_id = migration['old_instance_type_id']        new_instance_type_id = migration['new_instance_type_id']        old_instance_type = instance.get_flavor()        # NOTE(mriedem): Get the old_vm_state so we know if we should        # power on the instance. If old_vm_state is not set we need to default        # to ACTIVE for backwards compatibility        old_vm_state = instance.system_metadata.get('old_vm_state',                                                    vm_states.ACTIVE)        instance.old_flavor = old_instance_type        if old_instance_type_id != new_instance_type_id:            instance_type = instance.get_flavor('new')            self._set_instance_info(instance, instance_type)            for key in ('root_gb', 'swap', 'ephemeral_gb'):                if old_instance_type[key] != instance_type[key]:                    resize_instance = True                    break        instance.apply_migration_context()        # NOTE(tr3buchet): setup networks on destination host        self.network_api.setup_networks_on_host(context, instance,                                                migration['dest_compute'])        migration_p = obj_base.obj_to_primitive(migration)        self.network_api.migrate_instance_finish(context,                                                 instance,                                                 migration_p)        network_info = self.network_api.get_instance_nw_info(context, instance)        instance.task_state = task_states.RESIZE_FINISH        instance.save(expected_task_state=task_states.RESIZE_MIGRATED)        self._notify_about_instance_usage(            context, instance, "finish_resize.start",            network_info=network_info)        block_device_info = self._get_instance_block_device_info(                            context, instance, refresh_conn_info=True)        # NOTE(mriedem): If the original vm_state was STOPPED, we don't        # automatically power on the instance after it's migrated        power_on = old_vm_state != vm_states.STOPPED        try:            self.driver.finish_migration(context, migration, instance,                                         disk_info,                                         network_info,                                         p_w_picpath_meta, resize_instance,                                         block_device_info, power_on)        except Exception:            with excutils.save_and_reraise_exception():                if old_instance_type_id != new_instance_type_id:                    self._set_instance_info(instance,                                            old_instance_type)        migration.status = 'finished'        with migration.obj_as_admin():            migration.save()        instance.vm_state = vm_states.RESIZED        instance.task_state = None        instance.launched_at = timeutils.utcnow()        instance.save(expected_task_state=task_states.RESIZE_FINISH)        self._update_scheduler_instance_info(context, instance)        self._notify_about_instance_usage(            context, instance, "finish_resize.end",            network_info=network_info)

虚拟机状态又发生改变

[root@controller1 ~(keystone_admin)]# nova list

+--------------------------------------+---------------+--------+---------------+-------------+-----------------------+

| ID                                   | Name          | Status | Task State    | Power State | Networks              |

+--------------------------------------+---------------+--------+---------------+-------------+-----------------------+

| 21015376-8c4f-4fad-a834-245b57f23dcc | test-cirros-1 | RESIZE | resize_finish | Running     | NetworkA=192.168.0.26 |

+--------------------------------------+---------------+--------+---------------+-------------+-----------------------+

[root@controller1 ~(keystone_admin)]# nova list

+--------------------------------------+---------------+---------------+------------+-------------+-----------------------+

| ID                                   | Name          | Status        | Task State | Power State | Networks              |

+--------------------------------------+---------------+---------------+------------+-------------+-----------------------+

| 21015376-8c4f-4fad-a834-245b57f23dcc | test-cirros-1 | VERIFY_RESIZE | -          | Running     | NetworkA=192.168.0.26 |

+--------------------------------------+---------------+---------------+------------+-------------+-----------------------+

revert_resize、confirm_resize调用后续补充。。。