输入neutron router-update 参数执行后,neutron-server收到neutronclient发来的http请求后,根据路由映射选择相应的controller下的函数。
1.neutron/api/v2/base.py(493)update():所有的关于update操作都将在这处理
def update(self, request, id, body=None, **kwargs):
"""Updates the specified entity's attributes."""
parent_id = kwargs.get(self._parent_id_name)
try:
payload = body.copy()#body是请求部分,在这里body里包含了传过来的路由信息
except AttributeError:
msg = _("Invalid format: %s") % request.body
raise exceptions.BadRequest(resource='body', msg=msg)
payload['id'] = id#id是路由器的id
self._notifier.info(request.context,
self._resource + '.update.start', payload)
body = Controller.prepare_request_body(request.context, body, False,
self._resource, self._attr_info,
allow_bulk=self._allow_bulk)#路由信息
action = self._plugin_handlers[self.UPDATE]
# Load object to check authz
# but pass only attributes in the original body and required
# by the policy engine to the policy 'brain'
field_list = [name for (name, value) in self._attr_info.iteritems()
if (value.get('required_by_policy') or
value.get('primary_key') or
'default' not in value)] #field_list是orig_obj
policy.init()
orig_obj = self._item(request, id, field_list=field_list,
parent_id=parent_id)
orig_object_copy = copy.copy(orig_obj)
orig_obj.update(body[self._resource])
# Ensure policy engine is initialized
policy.init()orig_obj[const.ATTRIBUTES_TO_UPDATE] = body[self._resource].keys()
try:
policy.enforce(request.context,
action,
orig_obj)
except exceptions.PolicyNotAuthorized:
with excutils.save_and_reraise_exception() as ctxt:
# If a tenant is modifying it's own object, it's safe to return
# a 403. Otherwise, pretend that it doesn't exist to avoid
# giving away information.
if request.context.tenant_id != orig_obj['tenant_id']:
ctxt.reraise = False
msg = _('The resource could not be found.')
raise webob.exc.HTTPNotFound(msg)
obj_updater = getattr(self._plugin, action)#bound method L3RouterPlugin.update_router of <neutron.services.l3_router.l3_router_plugin.L3RouterPlugin,实际执行 #update操作的都是class L3RouterPlugin及其父类相应函数
kwargs = {self._resource: body}
if parent_id:
kwargs[self._parent_id_name] = parent_id
obj = obj_updater(request.context, id, **kwargs)#开始更新,跳转到neutron/db/extraroute_db.py(66)update_router()
result = {self._resource: self._view(request.context, obj)}
notifier_method = self._resource + '.update.end'
self._notifier.info(request.context, notifier_method, result)
self._send_dhcp_notification(request.context,
result,
notifier_method)
self._send_nova_notification(action, orig_object_copy, result)
return result
2.neutron/db/extraroute_db.py(66)update_router():处理uodate-router的入口
def update_router(self, context, id, router):
r = router['router'] #r类型为字典,存储路由表信息
with context.session.begin(subtransactions=True):
#check if route exists and have permission to access
#检查路由器是否存在并且是否有操作的权限
router_db = self._get_router(context, id)#/跳转到neutron/neutron/db/l3_db.py(120)_get_router()
if 'routes' in r:
self._update_extra_routes(context, router_db, r['routes'])
routes = self._get_extra_routes_by_router_id(context, id)
router_updated = super(ExtraRoute_dbonly_mixin, self).update_router(context, id, router)
router_updated['routes'] = routes
return router_updated
118 def _update_extra_routes(self, context, router, routes):
119 self._validate_routes(context, router['id'],
120 routes)
121 old_routes, routes_dict = self._get_extra_routes_dict_by_router_id(
122 context, router['id'])
123
124 '''
125 old_routes:existed routes,is a list,like:
126 [{'nexthop': u'10.0.0.3', 'destination': u'10.0.0.0/24'}, {'nexthop': u'192.168.100.3', 'destination': u'192.168.100.0/24'}]
127 routes:new routes to update,is a list,like:
128 [{u'destination': u'10.0.0.0/24', u'nexthop': u'10.0.0.2'}, {u'destination': u'192.168.100.0/24', u'nexthop': u'192.168.100.2'}]
129 '''
130 added, removed = utils.diff_list_of_dict(old_routes,
131 routes)
132
133 '''
134 utils.diff_list_of_dict(old_routes, routes)
135 old_routes and routes change to set type,find new routes to add:added,find routes to delete:removed
136 added,removed both are list,like:
137 [{u'nexthop': u'10.0.0.2', u'destination': u'10.0.0.0/24'}, {u'nexthop': u'192.168.100.2', u'destination': u'192.168.100.0/24'}]
138 '''
139
140 LOG.debug(_('Added routes are %s'), added)
141 for route in added:
142 router_routes = RouterRoute(
143 router_id=router['id'],
144 destination=route['destination'],
145 nexthop=route['nexthop'])
146 context.session.add(router_routes)
147
148 LOG.debug(_('Removed routes are %s'), removed)
149 for route in removed:
150 context.session.delete(
151 routes_dict[(route['destination'], route['nexthop'])])
3./neutron/neutron/db/l3_db.py(120)_get_router():
def _get_router(self, context, router_id):
try:
router = self._get_by_id(context, Router, router_id)#跳转到neutron/db/common_db_mixin.py(123)_get_by_id(),类型neutron.db.l3_db.Router
except exc.NoResultFound:
raise l3.RouterNotFound(router_id=router_id)
return router
4.neutron/db/common_db_mixin.py(123)_get_by_id():
def _get_by_id(self, context, model, id):
query = self._model_query(context, model)
return query.filter(model.id == id).one()
def _model_query(self, context, model):
query = context.session.query(model)
# define basic filter condition for model query
# NOTE(jkoelker) non-admin queries are scoped to their tenant_id
# NOTE(salvatore-orlando): unless the model allows for shared objects
query_filter = None
if not context.is_admin and hasattr(model, 'tenant_id'):
if hasattr(model, 'shared'):
query_filter = ((model.tenant_id == context.tenant_id) |
(model.shared == sql.true()))
else:
query_filter = (model.tenant_id == context.tenant_id)
# Execute query hooks registered from mixins and plugins
for _name, hooks in self._model_query_hooks.get(model,
{}).iteritems():
query_hook = hooks.get('query')
if isinstance(query_hook, basestring):
query_hook = getattr(self, query_hook, None)
if query_hook:
query = query_hook(context, model, query)
filter_hook = hooks.get('filter')
if isinstance(filter_hook, basestring):
filter_hook = getattr(self, filter_hook, None)
if filter_hook:
query_filter = filter_hook(context, model, query_filter)
# NOTE(salvatore-orlando): 'if query_filter' will try to evaluate the
# condition, raising an exception
if query_filter is not None:
query = query.filter(query_filter)
return query