nova resize

来源:互联网 发布:keil c51软件 编辑:程序博客网 时间:2024/06/13 17:22
resize的入口代码在nova/api/openstack/compute/servers.py,方法是_resize(),如下     def _resize(self, req, instance_id, flavor_id, **kwargs):        """Begin the resize process with given instance/flavor."""        context = req.environ["nova.context"]        instance = self._get_server(context, req, instance_id)        context.can(server_policies.SERVERS % 'resize',                    target={'user_id': instance.user_id,                            'project_id': instance.project_id})        try:            self.compute_api.resize(context, instance, flavor_id, **kwargs)        except exception.InstanceUnknownCell as e:            raise exc.HTTPNotFound(explanation=e.format_message())这里很明显看到是调用nova/compute/api.py 中的resize函数    def resize(self, context, instance, flavor_id=None, clean_shutdown=True,               **extra_instance_updates):        """Resize (ie, migrate) a running instance.        If flavor_id is None, the process is considered a migration, keeping        the original flavor_id. If flavor_id is not None, the instance should        be migrated to a new host and resized to the new flavor_id.        """        self.compute_task_api.resize_instance(context, instance,                extra_instance_updates, scheduler_hint=scheduler_hint,                flavor=new_instance_type,                reservations=quotas.reservations or [],                clean_shutdown=clean_shutdown,                request_spec=request_spec)这里的compute_task_api 是定义在conductor中的ComputeTaskAPI 类。因此这里的resize_instance是定义在ComputeTaskAPI中class ComputeTaskAPI(object):    """ComputeTask API that queues up compute tasks for nova-conductor."""    def __init__(self):        self.conductor_compute_rpcapi = rpcapi.ComputeTaskAPI()    def resize_instance(self, context, instance, extra_instance_updates,                        scheduler_hint, flavor, reservations,                        clean_shutdown=True, request_spec=None):        # NOTE(comstud): 'extra_instance_updates' is not used here but is        # needed for compatibility with the cells_rpcapi version of this        # method.        self.conductor_compute_rpcapi.migrate_server(            context, instance, scheduler_hint, live=False, rebuild=False,            flavor=flavor, block_migration=None, disk_over_commit=None,            reservations=reservations, clean_shutdown=clean_shutdown,            request_spec=request_spec)这里通过conductor_compute_rpcapi调用到conductor/rpcapi.py.按照之前的分析,rpcapi中的函数都会在对应的manager.py 中处理 @wrap_instance_event(prefix='conductor')    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 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, request_spec)        else:            raise NotImplementedError()这里看到resize其实调用的是migrate来完成的,其中migrate又可以分为_live_migrate和_cold_migrate。由于_live_migrate可以失败,这里以_cold_migrate为例同样在manager.py 中处理 def _cold_migrate(self, context, instance, flavor, filter_properties,                      reservations, clean_shutdown, request_spec):        image = utils.get_image_from_system_metadata(            instance.system_metadata)        # NOTE(sbauza): If a reschedule occurs when prep_resize(), then        # it only provides filter_properties legacy dict back to the        # conductor with no RequestSpec part of the payload.        if not request_spec:            # Make sure we hydrate a new RequestSpec object with the new flavor            # and not the nested one from the instance            request_spec = objects.RequestSpec.from_components(                context, instance.uuid, image,                flavor, instance.numa_topology, instance.pci_requests,                filter_properties, None, instance.availability_zone)        else:            # NOTE(sbauza): Resizes means new flavor, so we need to update the            # original RequestSpec object for make sure the scheduler verifies            # the right one and not the original flavor            request_spec.flavor = flavor//得到一个task,然后通过task.execute()来执行.        task = self._build_cold_migrate_task(context, instance, flavor,                                             request_spec,                                             reservations, clean_shutdown)        # TODO(sbauza): Provide directly the RequestSpec object once        # _set_vm_state_and_notify() accepts it        legacy_spec = request_spec.to_legacy_request_spec_dict()        try:            task.execute()        except exception.NoValidHost as ex:    def _build_cold_migrate_task(self, context, instance, flavor,                                 request_spec, reservations,                                 clean_shutdown):        return migrate.MigrationTask(context, instance, flavor,                                     request_spec,                                     reservations, clean_shutdown,                                     self.compute_rpcapi,                                     self.scheduler_client)这个要执行的task其实就是migrate.MigrationTask,而这里的from nova.conductor.tasks import migrate。所以到nova/conductor/tasks/migrate.py中看看。前面的task.execute()其实就是执行下面这个函数    def _execute(self):        image = self.request_spec.image        self.quotas = objects.Quotas.from_reservations(self.context,                                                       self.reservations,                                                       instance=self.instance)        # TODO(sbauza): Remove that once prep_resize() accepts a  RequestSpec        # object in the signature and all the scheduler.utils methods too        legacy_spec = self.request_spec.to_legacy_request_spec_dict()        legacy_props = self.request_spec.to_legacy_filter_properties_dict()        scheduler_utils.setup_instance_group(self.context, legacy_spec,                                             legacy_props)        scheduler_utils.populate_retry(legacy_props,                                       self.instance.uuid)        # TODO(sbauza): Remove that RequestSpec rehydratation once        # scheduler.utils methods use directly the NovaObject.        self.request_spec = objects.RequestSpec.from_components(            self.context, self.instance.uuid, image,            self.flavor, self.instance.numa_topology,            self.instance.pci_requests, legacy_props, None,            self.instance.availability_zone)        # NOTE(sbauza): Force_hosts/nodes needs to be reset        # if we want to make sure that the next destination        # is not forced to be the original host        self.request_spec.reset_forced_destinations()//由于flavor可能会变,所以这里调用scheduler重新选择host        hosts = self.scheduler_client.select_destinations(            self.context, self.request_spec)        host_state = hosts[0]        scheduler_utils.populate_filter_properties(legacy_props,                                                   host_state)        # context is not serializable        legacy_props.pop('context', None)        (host, node) = (host_state['host'], host_state['nodename'])        # FIXME(sbauza): Serialize/Unserialize the legacy dict because of        # oslo.messaging #1529084 to transform datetime values into strings.        # tl;dr: datetimes in dicts are not accepted as correct values by the        # rpc fake driver.        legacy_spec = jsonutils.loads(jsonutils.dumps(legacy_spec))        self.compute_rpcapi.prep_resize(            self.context, self.instance, legacy_spec['image'],            self.flavor, host, self.reservations,            request_spec=legacy_spec, filter_properties=legacy_props,            node=node, clean_shutdown=self.clean_shutdown)这里有调回compute中。我们这里就直接看computer/manager.py 中的 def _prep_resize(self, context, image, instance, instance_type,            quotas, request_spec, filter_properties, node,            clean_shutdown=True):       with rt.resize_claim(context, instance, instance_type,                             image_meta=image, limits=limits) as claim:            LOG.info(_LI('Migrating'), context=context, instance=instance)            self.compute_rpcapi.resize_instance(                    context, instance, claim.migration, image,                    instance_type, quotas.reservations,                    clean_shutdown)这里先调用compute/api.py 中的resize_instance。然后调用manager.py 中的resize_instance    def resize_instance(self, context, instance, image,                        reservations, migration, instance_type,                        clean_shutdown):        """Starts the migration of a running instance to another host."""           self.compute_rpcapi.finish_resize(context, instance,                    migration, image, disk_info,                    migration.dest_compute, reservations=quotas.reservations)继续调用finish_resize    def _finish_resize(self, context, instance, migration, disk_info,                       image_meta):       try:            self.driver.finish_migration(context, migration, instance,                                         disk_info,                                         network_info,                                         image_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)可见最终还是调用driver的finish_migration。我们用的是libvirt的话,就是调用libvirt的finish_migration。

原创粉丝点击