ceilometer api 源码

介绍

版本:juno

流程

/usr/bin/ceilometer-api

1
2
3
4
import sys
from ceilometer.cmd.api import main
if name == main:
sys.exit(main())

cmd/api.py

1
2
3
4
def main():
service.prepare_service()
srv = app.build_server()
srv.serve_forever()

api/app.py

1
2
3
4
5
6
7
def build_server():
app = load_app()

srv = simple_server.make_server(host, port, app,
server_cls, get_handler_cls())

return srv

1
2
3
4
def load_app():
# Build the WSGI app

return deploy.loadapp(“config:” + cfg_file)

api_paste.ini对应app_factory

1
2
def app_factory(global_config, **local_conf):
return VersionSelectorApplication()

1
2
3
4
class VersionSelectorApplication(object):

self.v2 = setup_app(pecan_config=pc)

1
2
3
4
5
6
7
8
9
10
11
12
13
def setup_app(pecan_config=None, extra_hooks=None):

app = pecan.make_app(
pecan_config.app.root,
static_root=pecan_config.app.static_root,
template_path=pecan_config.app.template_path,
debug=CONF.api.pecan_debug,
force_canonical=getattr(pecan_config.app, ‘force_canonical’, True),
hooks=app_hooks,
wrap_app=middleware.ParsableErrorMiddleware,
guess_content_type_from_ext=False
)
return app

这里用到了pecan。
pecan,一个轻量的web框架,主页http://pecan.readthedocs.org/
ceilometer中主要是用来构建restapi,主页中关于restapi部分的介绍,需要继承rest.RestController;
其中重要的部分URL Mapping:

pecan的配置文件api/config.py

1
2
3
4
5
6
7
8

app = {
‘root’: ‘ceilometer.api.controllers.root.RootController’,
‘modules’: [‘ceilometer.api’],
‘static_root’: ‘%(confdir)s/public’,
‘template_path’: ‘%(confdir)s/ceilometer/api/templates’,
}

ceilometer.api.controllers.root.RootController.py

1
2
3
4
5
6
7
8
class RootController(object):

v2 = v2.V2Controller()

@pecan.expose(generic=True, template=’index.html’)
def index(self):
# FIXME: Return version information
return dict()

这里注意v2 = v2.V2Controller(),其中就写了很多的restapi
api/controllers/v2.py

1
2
3
4
5
6
7
8
9
10
class V2Controller(object):
“”“Version 2 API controller root.”“”
resources = ResourcesController()
meters = MetersController()
samples = SamplesController()
alarms = AlarmsController()
event_types = EventTypesController()
events = EventsController()
query = QueryController()
capabilities = CapabilitiesController()

这里又加载各种对象的restapi
接下来就只分析其中一个,其他类似
这里又用到了wsme和wsmeext.pecan。
wsme即Web Services Made Easy,简化了REST Web服务的编写。
可以运行在另一个框架的顶层,如(Cornice、Flask、Pecan)等,这里就是运行在了pecan之上来更加简单的构建restapi,用法:
wsmeext.pecan.wsexpose(return_type, *arg_types, **options)

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
import wsmeext.pecan as wsme_pecan

class ResourcesController(rest.RestController):
“””Works on resources.”””

def _resource_links(self, resource_id, meter_links=1):
links = [_make_link(‘self’, pecan.request.host_url, ‘resources’,
resource_id)]
if meter_links:
for meter in pecan.request.storage_conn.get_meters(
resource=resource_id):
query = {‘field’: ‘resource_id’, ‘value’: resource_id}
links.append(_make_link(meter.name, pecan.request.host_url,
‘meters’, meter.name, query=query))
return links

#这里的get_one对应的就是GET http://<your ip>:8777/v2/resources/<resource_id>
#返回的为一个Resource类型
#参数为unicode类型
@wsme_pecan.wsexpose(Resource, unicode)
def get_one(self, resource_id):
“””Retrieve details about one resource.
:param resource_id: The UUID of the resource.
“””

authorized_project = acl.get_limited_to_project(pecan.request.headers)
resources = list(pecan.request.storage_conn.get_resources(
resource=resource_id, project=authorized_project))
if not resources:
raise EntityNotFound(_(‘Resource’), resource_id)
return Resource.from_db_and_links(resources[0],
self._resource_links(resource_id))
#这里的get_all对应的就是GET http://<your ip>:8777/v2/resources[?meter_links={meter_links}&
#q.field={field}&q.op={operator}&q.type={type}&q.value={value}]
#返回类型是包含Resource的序列
#参数类型是包含Query的序列
@wsme_pecan.wsexpose([Resource], [Query], int)
def get_all(self, q=None, meter_links=1):
“””Retrieve definitions of all of the resources.
:param q: Filter rules for the resources to be returned.
:param meter_links: option to include related meter links
“””

q = q or []
kwargs = _query_to_kwargs(q, pecan.request.storage_conn.get_resources)
resources = [
Resource.from_db_and_links(r,
self._resource_links(r.resource_id,
meter_links))
for r in pecan.request.storage_conn.get_resources(**kwargs)]
return resources