OpenStack Python知识(1):with函数使用

来源:互联网 发布:苹果预约软件 编辑:程序博客网 时间:2024/06/02 04:36

基于contextlib使用with

  • contextlib介绍
    contextlib是为了加强with语句,提供上下文机制的模块,它是通过Generator实现的。通过定义类以及写__enter__和__exit__来进行上下文管理虽然不难,但是很繁琐。contextlib中的contextmanager作为装饰器来提供一种针对函数级别的上下文管理机制。常用框架如下:,从而不需要独立定义__enter__()和__exit__函数。实例代码:
from contextlib import contextmanager@contextmanagerdef tag(name):    print "<%s>" % name    yield    print "</%s>" % name>>> with tag("h1"):...    print "foo"...<h1>foo</h1>

contextlib更多详细介绍请参考:https://docs.python.org/2/library/contextlib.html。

  • openstack使用

python中使用with作用是自动释放资源,即使在使用过程中有异常抛出。常规使用with需要定义__enter__, __exit__函数。本文基于openstack使用with做一种补充。先上代码。
/nova/virt/libvirt/driver.py中开始创建虚机。其中一个过程是创建domain和network如下:

    def _create_domain_and_network(self, context, xml, instance, network_info,                                   disk_info, block_device_info=None,                                   power_on=True, reboot=False,                                   vifs_already_plugged=False):        """Do required network setup and create domain."""        block_device_mapping = driver.block_device_info_get_mapping(            block_device_info)        image_meta = objects.ImageMeta.from_instance(instance)        for vol in block_device_mapping:            connection_info = vol['connection_info']            if (not reboot and 'data' in connection_info and                    'volume_id' in connection_info['data']):                volume_id = connection_info['data']['volume_id']                encryption = encryptors.get_encryption_metadata(                    context, self._volume_api, volume_id, connection_info)                if encryption:                    encryptor = self._get_volume_encryptor(connection_info,                                                           encryption)                    encryptor.attach_volume(context, **encryption)        timeout = CONF.vif_plugging_timeout        if (self._conn_supports_start_paused and            utils.is_neutron() and not            vifs_already_plugged and power_on and timeout):            events = self._get_neutron_events(network_info)#获取network-vif-plugged事件        else:            events = []        pause = bool(events)        guest = None        try:            with self.virtapi.wait_for_instance_event(                    instance, events, deadline=timeout,                    error_callback=self._neutron_failed_callback):                self.plug_vifs(instance, network_info)                self.firewall_driver.setup_basic_filtering(instance,                                                           network_info)                self.firewall_driver.prepare_instance_filter(instance,                                                             network_info)                with self._lxc_disk_handler(instance, image_meta,                                            block_device_info, disk_info):                    guest = self._create_domain(                        xml, pause=pause, power_on=power_on)                self.firewall_driver.apply_instance_filter(instance,                                                           network_info)        except exception.VirtualInterfaceCreateException:            # Neutron reported failure and we didn't swallow it, so            # bail here            with excutils.save_and_reraise_exception():                if guest:                    guest.poweroff()                self.cleanup(context, instance, network_info=network_info,                             block_device_info=block_device_info)        except eventlet.timeout.Timeout:            # We never heard from Neutron            LOG.warn(_LW('Timeout waiting for vif plugging callback for '                         'instance %(uuid)s'), {'uuid': instance.uuid},                     instance=instance)            if CONF.vif_plugging_is_fatal:                if guest:                    guest.poweroff()                self.cleanup(context, instance, network_info=network_info,                             block_device_info=block_device_info)                raise exception.VirtualInterfaceCreateException()        # Resume only if domain has been paused        if pause:            guest.resume()        return guest

在此我们看到with后面跟的是一个函数,而非常规的with XXXX as XXXX. 看下wait_for_instance_event函数定义:

    #被contextlib类函数封装    @contextlib.contextmanager     def wait_for_instance_event(self, instance, event_names, deadline=300,                                error_callback=None):        """Plan to wait for some events, run some code, then wait.        This context manager will first create plans to wait for the        provided event_names, yield, and then wait for all the scheduled        events to complete.        Note that this uses an eventlet.timeout.Timeout to bound the        operation, so callers should be prepared to catch that        failure and handle that situation appropriately.        If the event is not received by the specified timeout deadline,        eventlet.timeout.Timeout is raised.        If the event is received but did not have a 'completed'        status, a NovaException is raised.  If an error_callback is        provided, instead of raising an exception as detailed above        for the failure case, the callback will be called with the        event_name and instance, and can return True to continue        waiting for the rest of the events, False to stop processing,        or raise an exception which will bubble up to the waiter.        :param instance: The instance for which an event is expected        :param event_names: A list of event names. Each element can be a                            string event name or tuple of strings to                            indicate (name, tag).        :param deadline: Maximum number of seconds we should wait for all                         of the specified events to arrive.        :param error_callback: A function to be called if an event arrives        """        if error_callback is None:            error_callback = self._default_error_callback        events = {}        for event_name in event_names:            if isinstance(event_name, tuple):                name, tag = event_name                event_name = objects.InstanceExternalEvent.make_key(                    name, tag)            try:                events[event_name] = (                    self._compute.instance_events.prepare_for_instance_event(                        instance, event_name))            except exception.NovaException:                error_callback(event_name, instance)                # NOTE(danms): Don't wait for any of the events. They                # should all be canceled and fired immediately below,                # but don't stick around if not.                deadline = 0        yield #请注意此处的yield        with eventlet.timeout.Timeout(deadline):            for event_name, event in events.items():                actual_event = event.wait()                if actual_event.status == 'completed':                    continue                decision = error_callback(event_name, instance)                if decision is False:                    break

知道contextlib用法之后很容易理解此处代码含义,即生成事件,然后等待plug vif等操作之后等待事件,如果超时则发送eventlet.timeout.Timeout异常,捕获异常之后做相应处理。

0 0