您的位置:首页 > 编程语言 > Python开发

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

2016-06-12 20:03 393 查看

基于contextlib使用with

contextlib介绍

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

from contextlib import contextmanager

@contextmanager
def 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_mappi
4000
ng = 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异常,捕获异常之后做相应处理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  openstack python