cinder-api

cinder api服务启动子进程分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#!/usr/bin/evn python

#author leidong

#@ 依赖包的分析

#@ webob 模块 简单的说,WebOb是一个用于对WSGI request环境进行包装(也就是变得易用)以及用于创建WSGI response的一个包。

#@ PasteDeploy生成WSGI的Application 就是url 对应的是那些类, 简单来说就是 Application 中的各种url对应的类 使用了 webob 和 Routes 这两个模块

#@ cinder-api 服务的启动 主要包括 主进程 和 子进程

#@ 主进程 功能分析和 start-volume.py 分析一样

#@ 以下分析的是 子进程

if __name__ == '__main__':

CONF(sys.argv[1:], project='cinder',

version=version.version_string())

logging.setup("cinder")

utils.monkey_patch()

#@ monkey_pathch 调用的是 __import__(module)

#@ monkey_patch_modules = cinder.volume.volume_types:paxes_cinder.volume.volume_type_decorator

#@ cinder.volume.volume_types 此类 是 __import__('cinder.volume.volume_types') 导入是一个模块 cinder.volume.volume_types.py

#@ paxes_cinder.volume.volume_type_decorator 做为装饰类 importutils.import_class(paxes_cinder.volume.volume_type_decorator) 导入的是 一个类 或者是 一个 函数

#@ module_data = pyclbr.readmodule_ex(module) 返回字典形式的 模块中的 所有 class 和 function

#@ {'A': ,

#@ 'B': ,

#@ 'f': }

#@ for method, func in inspect.getmembers(clz, inspect.ismethod):

#@ setattr(

#@ clz, method,

#@ decorator("%s.%s.%s" % (module, key, method), func))

#@ 此函数的功能是 给 指定模块所有方法列出来 在根据 decorator 装饰类的 指定给定的模块那个方法进行 重新设置属性值setattr

rpc.init(CONF)

launcher = service.process_launcher()

server = service.WSGIService('osapi_volume')

launcher.launch_service(server, workers=server.workers or 1)

launcher.wait()

#@ 主要分析的是以下代码

server = service.WSGIService('osapi_volume')

#@ 初始化 cinder/service:WSGIService 类

def __init__(self, name, loader=None):

"""Initialize, but do not start the WSGI server.

:param name: The name of the WSGI server given to the loader.

:param loader: Loads the WSGI application using the given name.

:returns: None

"""

self.name = name

#@ self.name = 'osapi_volume'

self.manager = self._get_manager()

#@

#@

fl = '%s_manager' % self.name

#@ f1 = osapi_volume_manager

if fl not in CONF:

#@ 在 配置文件中 没有 osapi_volume_manager 选项

return None

manager_class_name = CONF.get(fl, None)

#@ 如果有则获取 api 的管理类

if not manager_class_name:

#@ 有选项没有指定管理类

return None

manager_class = importutils.import_class(manager_class_name)

#@ 导入api 的管理类

return manager_class()



self.loader = loader or wsgi.Loader()

self.app = self.loader.load_app(name)

#@ 主要是解析 api-paste.ini 文件

#@ /v1: openstack_volume_api_v1

#@

[composite:openstack_volume_api_v1]

use = call:cinder.api.middleware.auth:pipeline_factory

#@ 调用的是 :pipeline_factory 方法

#@ pipeline = local_conf[CONF.auth_strategy]

#@ 获取的是 api-paste.ini 文件中的pipline = request_id faultwrap sizelimit authtoken keystonecontext apiv1

if not CONF.api_rate_limit:

limit_name = CONF.auth_strategy + '_nolimit'

pipeline = local_conf.get(limit_name, pipeline)

#@ 获取的是 api-paste.ini 文件中的keystone_nolimit = request_id faultwrap sizelimit authtoken keystonecontext apiv1

pipeline = pipeline.split()

filters = [loader.get_filter(n) for n in pipeline[:-1]]

#@ 获取列表

#@ request_id : cinder.openstack.common.middleware.request_id:RequestIdMiddleware.factory 对应方法

#@ faultwrap : cinder.api.middleware.fault:FaultWrapper.factory 对应方法

#@ sizelimit : cinder.api.middleware.sizelimit:RequestBodySizeLimiter.factory 对应方法

#@ authtoken : keystoneclient.middleware.auth_token:filter_factory

#@ keystonecontext : cinder.api.middleware.auth:CinderKeystoneContext.factory

app = loader.get_app(pipeline[-1])

#@ 获取 v1 : cinder.api.v1.router:APIRouter.factory

filters.reverse()

#@ 反转 filters 列表

for filter in filters:

app = filter(app)

#@ 装饰的顺序为

#@ request_id(faultwrap(sizelimit(authtoken(keystonecontext(v1)))))

return app #@ app = request_id(faultwrap(sizelimit(authtoken(keystonecontext(v1)))))

#@ app v1 初始化的过程:

v1=cinder.api.v1.router:APIRouter.factory

#@ 调用 父类(cinder.api.openstack.APIRouter) 的 类方法 factory

#@ def factory(cls, global_config, **local_config):

return cls()

#@ 初始化自己 调用 父类的 cinder.api.openstack.APIRouter.__init__ 方法

#@ ExtensionManager = extensions.ExtensionManager

#@ cinder.api.extensions.ExtensionManager 类

#@ if ext_mgr is None:

if self.ExtensionManager:

ext_mgr = self.ExtensionManager()

#@ 初始化cinder.api.extensions.ExtensionManager

#@ def __init__(self):

LOG.audit(_('Initializing extension manager.'))

#@ 打印 日志文件的 第二部分

#@ 2015-06-10 02:32:21.251 1038 AUDIT cinder.api.extensions [-] Initializing extension manager.

self.cls_list = CONF.osapi_volume_extension

#@ osapi_volume_extension=cinder.api.contrib.standard_extensions

self.extensions = {}

self._load_extensions()

else:

raise Exception(_("Must specify an ExtensionManager class"))

mapper = ProjectMapper()

self.resources = {}

self._setup_routes(mapper, ext_mgr)

self._setup_ext_routes(mapper, ext_mgr)

self._setup_extensions(ext_mgr)

super(APIRouter, self).__init__(mapper)



#@ 最后返回 app

#@ if not CONF.enable_v1_api:

del local_conf['/v1']

if not CONF.enable_v2_api:

del local_conf['/v2']

return paste.urlmap.urlmap_factory(loader, global_conf, **local_conf)

#@ 返回一个 dict

self.host = getattr(CONF, '%s_listen' % name, "0.0.0.0")

self.port = getattr(CONF, '%s_listen_port' % name, 0)

self.workers = getattr(CONF, '%s_workers' % name, None)

if self.workers < 1:

LOG.warn(_("Value of config option %(name)s_workers must be "

"integer greater than 1. Input value ignored.") %

{'name': name})

# Reset workers to default

self.workers = None

self.server = wsgi.Server(name,

self.app,

host=self.host,

port=self.port)