aa07ab62af
This patch fix the issue by changing the call to find the plugin which handles the l3 which is now the l3_router service plugin instead of the old mixin. Also change the unit tests to use the l3 service plugin instead of the l3 mixin and refactor the rpc callbacks part. Co-Authored-By: Ala Rezmerita <ala.rezmerita@cloudwatt.com> Closes-bug: #1257354 Change-Id: Ide26f825005fa63cd3fcc75fa91fffb947e0be7a
240 lines
10 KiB
Python
240 lines
10 KiB
Python
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
|
|
#
|
|
# Author: Sylvain Afchain <sylvain.afchain@enovance.com>
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import netaddr
|
|
import sqlalchemy as sa
|
|
from sqlalchemy import orm
|
|
|
|
from neutron.api.rpc.agentnotifiers import metering_rpc_agent_api
|
|
from neutron.common import constants
|
|
from neutron.db import api as dbapi
|
|
from neutron.db import db_base_plugin_v2 as base_db
|
|
from neutron.db import l3_db
|
|
from neutron.db import model_base
|
|
from neutron.db import models_v2
|
|
from neutron.extensions import metering
|
|
from neutron.openstack.common import log as logging
|
|
from neutron.openstack.common import uuidutils
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class MeteringLabelRule(model_base.BASEV2, models_v2.HasId):
|
|
direction = sa.Column(sa.Enum('ingress', 'egress',
|
|
name='meteringlabels_direction'))
|
|
remote_ip_prefix = sa.Column(sa.String(64))
|
|
metering_label_id = sa.Column(sa.String(36),
|
|
sa.ForeignKey("meteringlabels.id",
|
|
ondelete="CASCADE"),
|
|
nullable=False)
|
|
excluded = sa.Column(sa.Boolean, default=False)
|
|
|
|
|
|
class MeteringLabel(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
|
|
name = sa.Column(sa.String(255))
|
|
description = sa.Column(sa.String(1024))
|
|
rules = orm.relationship(MeteringLabelRule, backref="label",
|
|
cascade="delete", lazy="joined")
|
|
routers = orm.relationship(
|
|
l3_db.Router,
|
|
primaryjoin="MeteringLabel.tenant_id==Router.tenant_id",
|
|
foreign_keys='MeteringLabel.tenant_id',
|
|
uselist=True)
|
|
|
|
|
|
class MeteringDbMixin(metering.MeteringPluginBase,
|
|
base_db.CommonDbMixin):
|
|
|
|
def __init__(self):
|
|
dbapi.register_models()
|
|
|
|
self.meter_rpc = metering_rpc_agent_api.MeteringAgentNotifyAPI()
|
|
|
|
def _make_metering_label_dict(self, metering_label, fields=None):
|
|
res = {'id': metering_label['id'],
|
|
'name': metering_label['name'],
|
|
'description': metering_label['description'],
|
|
'tenant_id': metering_label['tenant_id']}
|
|
return self._fields(res, fields)
|
|
|
|
def create_metering_label(self, context, metering_label):
|
|
m = metering_label['metering_label']
|
|
tenant_id = self._get_tenant_id_for_create(context, m)
|
|
|
|
with context.session.begin(subtransactions=True):
|
|
metering_db = MeteringLabel(id=uuidutils.generate_uuid(),
|
|
description=m['description'],
|
|
tenant_id=tenant_id,
|
|
name=m['name'])
|
|
context.session.add(metering_db)
|
|
|
|
return self._make_metering_label_dict(metering_db)
|
|
|
|
def delete_metering_label(self, context, label_id):
|
|
with context.session.begin(subtransactions=True):
|
|
try:
|
|
label = self._get_by_id(context, MeteringLabel, label_id)
|
|
except orm.exc.NoResultFound:
|
|
raise metering.MeteringLabelNotFound(label_id=label_id)
|
|
|
|
context.session.delete(label)
|
|
|
|
def get_metering_label(self, context, label_id, fields=None):
|
|
try:
|
|
metering_label = self._get_by_id(context, MeteringLabel, label_id)
|
|
except orm.exc.NoResultFound:
|
|
raise metering.MeteringLabelNotFound(label_id=label_id)
|
|
|
|
return self._make_metering_label_dict(metering_label, fields)
|
|
|
|
def get_metering_labels(self, context, filters=None, fields=None,
|
|
sorts=None, limit=None, marker=None,
|
|
page_reverse=False):
|
|
marker_obj = self._get_marker_obj(context, 'metering_labels', limit,
|
|
marker)
|
|
return self._get_collection(context, MeteringLabel,
|
|
self._make_metering_label_dict,
|
|
filters=filters, fields=fields,
|
|
sorts=sorts,
|
|
limit=limit,
|
|
marker_obj=marker_obj,
|
|
page_reverse=page_reverse)
|
|
|
|
def _make_metering_label_rule_dict(self, metering_label_rule, fields=None):
|
|
res = {'id': metering_label_rule['id'],
|
|
'metering_label_id': metering_label_rule['metering_label_id'],
|
|
'direction': metering_label_rule['direction'],
|
|
'remote_ip_prefix': metering_label_rule['remote_ip_prefix'],
|
|
'excluded': metering_label_rule['excluded']}
|
|
return self._fields(res, fields)
|
|
|
|
def get_metering_label_rules(self, context, filters=None, fields=None,
|
|
sorts=None, limit=None, marker=None,
|
|
page_reverse=False):
|
|
marker_obj = self._get_marker_obj(context, 'metering_label_rules',
|
|
limit, marker)
|
|
|
|
return self._get_collection(context, MeteringLabelRule,
|
|
self._make_metering_label_rule_dict,
|
|
filters=filters, fields=fields,
|
|
sorts=sorts,
|
|
limit=limit,
|
|
marker_obj=marker_obj,
|
|
page_reverse=page_reverse)
|
|
|
|
def get_metering_label_rule(self, context, rule_id, fields=None):
|
|
try:
|
|
metering_label_rule = self._get_by_id(context,
|
|
MeteringLabelRule, rule_id)
|
|
except orm.exc.NoResultFound:
|
|
raise metering.MeteringLabelRuleNotFound(rule_id=rule_id)
|
|
|
|
return self._make_metering_label_rule_dict(metering_label_rule, fields)
|
|
|
|
def _validate_cidr(self, context, label_id, remote_ip_prefix,
|
|
direction, excluded):
|
|
r_ips = self.get_metering_label_rules(context,
|
|
filters={'metering_label_id':
|
|
label_id,
|
|
'direction':
|
|
[direction],
|
|
'excluded':
|
|
[excluded]},
|
|
fields=['remote_ip_prefix'])
|
|
|
|
cidrs = [r['remote_ip_prefix'] for r in r_ips]
|
|
new_cidr_ipset = netaddr.IPSet([remote_ip_prefix])
|
|
if (netaddr.IPSet(cidrs) & new_cidr_ipset):
|
|
raise metering.MeteringLabelRuleOverlaps(remote_ip_prefix=
|
|
remote_ip_prefix)
|
|
|
|
def create_metering_label_rule(self, context, metering_label_rule):
|
|
m = metering_label_rule['metering_label_rule']
|
|
with context.session.begin(subtransactions=True):
|
|
label_id = m['metering_label_id']
|
|
ip_prefix = m['remote_ip_prefix']
|
|
direction = m['direction']
|
|
excluded = m['excluded']
|
|
|
|
self._validate_cidr(context, label_id, ip_prefix, direction,
|
|
excluded)
|
|
metering_db = MeteringLabelRule(id=uuidutils.generate_uuid(),
|
|
metering_label_id=label_id,
|
|
direction=direction,
|
|
excluded=m['excluded'],
|
|
remote_ip_prefix=ip_prefix)
|
|
context.session.add(metering_db)
|
|
|
|
return self._make_metering_label_rule_dict(metering_db)
|
|
|
|
def delete_metering_label_rule(self, context, rule_id):
|
|
with context.session.begin(subtransactions=True):
|
|
try:
|
|
rule = self._get_by_id(context, MeteringLabelRule, rule_id)
|
|
except orm.exc.NoResultFound:
|
|
raise metering.MeteringLabelRuleNotFound(rule_id=rule_id)
|
|
|
|
context.session.delete(rule)
|
|
|
|
def _get_metering_rules_dict(self, metering_label):
|
|
rules = []
|
|
for rule in metering_label.rules:
|
|
rule_dict = self._make_metering_label_rule_dict(rule)
|
|
rules.append(rule_dict)
|
|
|
|
return rules
|
|
|
|
def _make_router_dict(self, router):
|
|
res = {'id': router['id'],
|
|
'name': router['name'],
|
|
'tenant_id': router['tenant_id'],
|
|
'admin_state_up': router['admin_state_up'],
|
|
'status': router['status'],
|
|
'gw_port_id': router['gw_port_id'],
|
|
constants.METERING_LABEL_KEY: []}
|
|
|
|
return res
|
|
|
|
def _process_sync_metering_data(self, labels):
|
|
routers_dict = {}
|
|
for label in labels:
|
|
routers = label.routers
|
|
for router in routers:
|
|
router_dict = routers_dict.get(
|
|
router['id'],
|
|
self._make_router_dict(router))
|
|
|
|
rules = self._get_metering_rules_dict(label)
|
|
|
|
data = {'id': label['id'], 'rules': rules}
|
|
router_dict[constants.METERING_LABEL_KEY].append(data)
|
|
|
|
routers_dict[router['id']] = router_dict
|
|
|
|
return routers_dict.values()
|
|
|
|
def get_sync_data_metering(self, context, label_id=None, router_ids=None):
|
|
labels = context.session.query(MeteringLabel)
|
|
|
|
if label_id:
|
|
labels = labels.filter(MeteringLabel.id == label_id)
|
|
elif router_ids:
|
|
labels = (labels.join(MeteringLabel.routers).
|
|
filter(l3_db.Router.id.in_(router_ids)))
|
|
|
|
return self._process_sync_metering_data(labels)
|