ac40c6c177
foreign_keys parameter of orm.relationship should point to local columns. Currently for MeteringLabel it points to Router.tenant_id column which causes routers tenant_id clearing on label deletion. Closes-Bug: #1249188 Change-Id: Iccc0daf4f6edd537fd7f9e4b2fc4be094543ca5d
239 lines
10 KiB
Python
239 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):
|
|
with context.session.begin(subtransactions=True):
|
|
if label_id:
|
|
label = self._get_by_id(context, MeteringLabel, label_id)
|
|
labels = [label]
|
|
else:
|
|
labels = self._get_collection_query(context, MeteringLabel)
|
|
|
|
return self._process_sync_metering_data(labels)
|