nova的 microversion 实现

之前想写nova的policy的实现, 但是发现网上,有人写的很不错了。

但是个人认为存在一些问题。 ref:  http://www.cnblogs.com/shaohef/p/4527436.html

希望 microversion 还没有人写。

microversion实现

microversion实现的机制,就是在http的头部增加一个请求的小版本, nova的serve大家 搜索 new, type, metaclass, 都会介绍。r 根据这个小版本号,做相应的action。
实在是没有什么好介绍了。

这个我想像的microversion有些gap。 我开始以为是在url中指定版本号,而不是在head中。 

microversion的值得研究的是如下这段代码。

1 class subContorller(wsgi.Controller)
2     @wsgi.Controller.api_version("2.1", "2.3")
3     def my_api_method(self, req, id):
4         .... method_1 ...
5
6     @wsgi.Controller.api_version("2.4") #noqa
7     def my_api_method(self, req, id):
8         .... method_2 ...

来自: http://docs.openstack.org/developer/nova/devref/api_microversions.html#changing-a-method-s-behaviour

这段代码,有点诡异,在一个类中实现了两个同名的属性,后面的那个将覆盖前面的那个。

如果是熟悉python的类和实例创建过程的,肯定认为很easy。

瞬间就能想到实现原理, 比如说 不正直的绅士, 他直接做过类似的代码。 

其实在IBM的kvm的team,做发行版本的同事,也能想到怎么实现的。

因为我之前给他们介绍个python的类和实例创建过程,其实google/so 一大堆。

我的介绍肯定不如他们自己学习效果好,我纯粹就是显摆而已。

我们要在magnum上,实现microversion,所以我我按照自己的思路尝试自己实现一个。

首先,在同一个类中,定义多个同名函数,最后一个函数, 会覆盖其他的。

怎么办呢?

跟大家一样,第一想法是重载 __getattribute__ 的类。

做法是重名的函数,想办法重新命名。 然后在__getattribute__中,知道期望的函数。

发现,没有找到一个合适的位置,来hack重名的函数。

下面代码中的第5行,是我找到的唯一可能问位置,但是,这个代码只有类的实例才会调用。  ~~~~

 1 def operater(min, max):
 2     def operate(fn):
 3         def wraper(self, *args, **kv):
 4             if fn.func_name not in self.funs:
 5                 self.funs[fn.func_name] = [(fn.func_name+"_"+min+"_"+max, wraper)]
 6             else:
 7                 self.funs[fn.func_name].append((fn.func_name+"_"+min+"_"+max, wraper))
 8             print getattr(self, fn.func_name)
 9             print "begin decorate"
10             return fn(self, *args, **kv)
11             print "end decorate"
12             type(self)
13         return wraper
14     return operate
15
16
17 class Controller(object):
18     funs = {}
19     def __init__(self):
20         print self
21
22     def __getattribute__(self, name):
23         if name in self.funs:
24             all_funs = self.funs[name]
25             fun = self.funs[0][1]
26             return fun
27         return object.__getattribute__(self, name)
28
29     @operater("1.0", "1.5") # noqa
30     def fun1(self):
31         print self
32         print "inline fun1"
33
34     @operater("1.0", "1.6") # noqa
35     def fun1(self):
36         print self
37         print "inline fun2"
38
39 if __name__ == ‘__main__‘:
40     print "start main"
41     import pdb
42     pdb.set_trace()
43     i = Controller()
44  print dir(i)
45     i.fun1()

大家可以尝试写一下, 不知道有没有实现的可能, 过程中可能会有不少坑。

实在是给大家做过太多的培训了,类合实例的创建过程,还是比较清楚的。

休息了一下,立马清醒。 发现自己比较傻逼,这个位置是创建类的时候。

大家 搜索 new, type, metaclass, 都会介绍。

查看nova的代码,果真如此。 

nova采用了six.add_metaclass 来构造类。把nova的相关代码摘取如下, 很简单,都不需要解释。

  1 import six
  2
  3 class VersionedMethod(object):
  4
  5     def __init__(self, name, start_version, end_version, func):
  6         self.name = name
  7         self.start_version = start_version
  8         self.end_version = end_version
  9         self.func = func
 10
 11     def __str__(self):
 12         return ("Version Method %s: min: %s, max: %s"
 13                 % (self.name, self.start_version, self.end_version))
 14
 15
 16 VER_METHOD_ATTR = ‘versioned_methods‘
 17 obj_min_ver = "2.0"
 18 obj_max_ver = "2.3"
 19
 20
 21 class ControllerMetaclass(type):
 22     def __new__(mcs, name, bases, cls_dict):
 23         versioned_methods = None
 24         # start with wsgi actions from base classes
 25         for base in bases:
 26             # actions.update(getattr(base, ‘wsgi_actions‘, {}))
 27
 28             if base.__name__ == "Controller":
 29                 # NOTE(cyeoh): This resets the VER_METHOD_ATTR attribute
 30                 # between API controller class creations. This allows us
 31                 # to use a class decorator on the API methods that doesn‘t
 32                 # require naming explicitly what method is being versioned as
 33                 # it can be implicit based on the method decorated. It is a bit
 34                 # ugly.
 35                 print "+" * 80
 36                 print base.__dict__
 37                 if VER_METHOD_ATTR in base.__dict__:
 38                     versioned_methods = getattr(base, VER_METHOD_ATTR)
 39                     delattr(base, VER_METHOD_ATTR)
 40
 41         for key, value in cls_dict.items():
 42             if not callable(value):
 43                 continue
 44         if versioned_methods:
 45             cls_dict[VER_METHOD_ATTR] = versioned_methods
 46
 47         return super(ControllerMetaclass, mcs).__new__(mcs, name, bases,
 48                                                        cls_dict)
 49
 50
 51 class abc(object):
 52     pass
 53
 54 @six.add_metaclass(ControllerMetaclass)
 55 class Controller(abc):
 56
 57
 58     def __getattribute__(self, key):
 59         def version_select(*args, **kwargs):
 60             # The first arg to all versioned methods is always the request
 61             # object. The version for the request is attached to the
 62             # request object
 63             func_list = self.versioned_methods[key]
 64             print func_list
 65             for func in func_list:
 66                 print "^" * 80
 67                 return func.func(self, *args, **kwargs)
 68                 # print func.func_name, func.obj_min_ver, func.obj_max_ver
 69             return func.func(self, *args, **kwargs)
 70             # No version match
 71             raise exception.VersionNotFoundForAPIMethod(version=ver)
 72
 73         try:
 74             # super(LockerDecorator,  self).__getattribute__(self, name)
 75             version_meth_dict = abc.__getattribute__(self, VER_METHOD_ATTR)
 76         except AttributeError:
 77             # No versioning on this class
 78             return abc.__getattribute__(self, key)
 79
 80         if version_meth_dict and  81           key in abc.__getattribute__(self, VER_METHOD_ATTR):
 82             return version_select
 83
 84         return abc.__getattribute__(self, key)
 85
 86
 87     # NOTE(cyeoh): This decorator MUST appear first (the outermost
 88     # decorator) on an API method for it to work correctly
 89     @classmethod
 90     def api_version(cls, min_ver, max_ver=None):
 91         def decorator(f):
 92
 93             # Add to list of versioned methods registered
 94             func_name = f.__name__
 95             new_func = VersionedMethod(func_name, obj_min_ver, obj_max_ver, f)
 96
 97             func_dict = getattr(cls, VER_METHOD_ATTR, {})
 98             if not func_dict:
 99                 setattr(cls, VER_METHOD_ATTR, func_dict)
100
101             # global func_list
102             func_list = func_dict.get(func_name, [])
103             if not func_list:
104                 func_dict[func_name] = func_list
105             func_list.append(new_func)
106             func_list.sort(key=lambda f: f.start_version, reverse=True)
107
108             return f
109
110         return decorator
111
112
113 class MyController(Controller):
114     @Controller.api_version("2.2")
115     def create(self, req, body):
116         print "create v2.2"
117
118     @Controller.api_version("2.1", "2.1")  # noqa
119     def create(self, req, body):
120         print "create v2.1"
121
122     def delete(self, req, body):
123         print "delete no version"
124
125 if __name__ == "__main__":
126     i = MyController()
127     i.create("1", "2")
128     i.delete("1", "2")
129     print "exit"

时间: 2024-08-04 17:08:27

nova的 microversion 实现的相关文章

nova - nova base image id的生成算法

nova spawn instance的时候,会先create_image,下面是获取的base image的函数 def get_cache_fname(images, key):     """Return a filename based on the SHA1 hash of a given image ID.     Image files stored in the _base directory that match this pattern     are c

openstack M版安装 compute(nova)服务篇

配置安装nova compute服务 安装controller节点 一.创建nova数据库 [[email protected] ~]# mysql -u root -p >>CREATE DATABASE nova_api; >>CREATE DATABASE nova; >>GRANT ALL PRIVILEGES ON nova_api.* TO 'nova'@'localhost'   IDENTIFIED BY 'NOVA_DBPASS'; >>G

中小企业openstack私有云布署实践【11.3 计算nova - compute节点-nova用户免密登录(用于云主机冷迁移+扩展云主机大小)】

云主机迁移+扩展云主机大小 ,官方说它依赖nova用户之间的免密登录.确保每个resion区域的compute节点服务器他们可以相互SSH免密 compute1-7     他们相互SSH免密 kxcompute1-9  他们相互SSH免密 1.注意!是每台机器上的nova用户向另一台机器的nova用户的免密登录 每台compute节点修改ssh配置,目的是为了不让其提示输入yes保存密钥 vi /etc/ssh/ssh_config 尾部添加 StrictHostKeyChecking no

中小企业openstack私有云布署实践【11.1 计算nova - compute节点配置(科兴环境)】

这里我只使用kxcompute1节点配置为示例,其它节点的配置基本是一样的,只是声明的管理IP不同而已 计算节点 # yum install openstack-nova-compute sysfsutils 修改配置文件 vi /etc/nova/nova.conf [DEFAULT] vcpu_pin_set = 4-31 resume_guests_state_on_host_boot=True rpc_backend = rabbit auth_strategy = keystone m

OpenStack nova动态添加/删除cpu内存的简单实现

环境 版本: rdo OpenStack Liberty qemu: 2.3.0 libvirt: 1.2.17-13 思路 需要qemu-guest-agent支持,在镜像中安装qemu-guest-agent包,并设置开机自启动,然后镜像设置元数据: 这两种方式设置都可以: glance image-update <image-id> --property hw_qemu_guest_agent=yes nova image-meta {image_id} set hw_qemu_gues

expose nova instance disable_terminate属性api

环境: rdo L版 先来说下nova api删除虚拟机的代码中有这么一个判断: def _delete(self, context, instance, delete_type, cb, **instance_attrs):         if instance.disable_terminate:                # 会判断disable_terminate             LOG.info(_LI('instance termination disabled'),

用pdb.set_trace()设断点,跟nova/api/openstack/compute/servers.py - detail() 流程

由 curl -s -H "X-Auth-Token: $OS_TOKEN" http://192.168.153.128:8774/v2.1/servers/detail | python -m json.tool 命令: 得到结果: { "servers": []       注:因为servers是核心资源,所有返回为空.} 1/opt/stack/nova/nova/api/openstack/compute/servers.py(210)detail()

nova虚拟机启动拉取image的过程

这里只关注Nova virt的spawn函数,glance.nova后端为ceph nova/virt/libvirt/driver.py    def spawn(self, context, instance, image_meta, injected_files,               admin_password, network_info=None, block_device_info=None):         image_meta = objects.ImageMeta.f

Openstack Nova network

对于安装设置来说,Openstack就剩下网络这个地方比较复杂. 我的网络水平,也就是只能吧家里的路由器跑起来.所以这个东西对我来说就是有点超出我的能力范围. 现在比较喜欢看图 整理了一下网络的资料 1:Nova 网络HA http://unchainyourbrain.com/openstack/13-networking-in-nova :2:Rackspace推荐的设计架构,这个设计,其实我们上线是可以考虑的. http://www.referencearchitecture.org/ne