• 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()
    View Code

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

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

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

    大家 搜索 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"
    View Code

                                            

  • 相关阅读:
    H5实现魔方游戏
    T-SQL:CTE用法(十)
    c# API接收Base64转图片
    T-SQL :联接查询练习 (杂)
    T-SQL:基础练习(杂)
    UI5-文档-导航栏
    UI5-文档-4.10-Descriptor for Applications
    UI5-文档-4.9-Component Configuration
    UI5-文档-4.8-Translatable Texts
    UI5-文档-4.7-JSON Model
  • 原文地址:https://www.cnblogs.com/shaohef/p/4527117.html
Copyright © 2020-2023  润新知