1 # Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
3 # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 # not use this file except in compliance with the License. You may obtain
5 # a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 # License for the specific language governing permissions and limitations
16 from oslo_utils import uuidutils
17 import sqlalchemy as sa
18 from sqlalchemy import orm
19 from sqlalchemy import sql
21 from neutron.api.rpc.agentnotifiers import metering_rpc_agent_api
22 from neutron.api.v2 import attributes as attr
23 from neutron.common import constants
24 from neutron.db import common_db_mixin as base_db
25 from neutron.db import l3_db
26 from neutron.db import model_base
27 from neutron.extensions import metering
30 class MeteringLabelRule(model_base.BASEV2, model_base.HasId):
31 direction = sa.Column(sa.Enum('ingress', 'egress',
32 name='meteringlabels_direction'))
33 remote_ip_prefix = sa.Column(sa.String(64))
34 metering_label_id = sa.Column(sa.String(36),
35 sa.ForeignKey("meteringlabels.id",
38 excluded = sa.Column(sa.Boolean, default=False, server_default=sql.false())
41 class MeteringLabel(model_base.BASEV2, model_base.HasId, model_base.HasTenant):
42 name = sa.Column(sa.String(attr.NAME_MAX_LEN))
43 description = sa.Column(sa.String(attr.LONG_DESCRIPTION_MAX_LEN))
44 rules = orm.relationship(MeteringLabelRule, backref="label",
45 cascade="delete", lazy="joined")
46 routers = orm.relationship(
48 primaryjoin="MeteringLabel.tenant_id==Router.tenant_id",
49 foreign_keys='MeteringLabel.tenant_id',
51 shared = sa.Column(sa.Boolean, default=False, server_default=sql.false())
54 class MeteringDbMixin(metering.MeteringPluginBase,
55 base_db.CommonDbMixin):
58 self.meter_rpc = metering_rpc_agent_api.MeteringAgentNotifyAPI()
60 def _make_metering_label_dict(self, metering_label, fields=None):
61 res = {'id': metering_label['id'],
62 'name': metering_label['name'],
63 'description': metering_label['description'],
64 'shared': metering_label['shared'],
65 'tenant_id': metering_label['tenant_id']}
66 return self._fields(res, fields)
68 def create_metering_label(self, context, metering_label):
69 m = metering_label['metering_label']
71 with context.session.begin(subtransactions=True):
72 metering_db = MeteringLabel(id=uuidutils.generate_uuid(),
73 description=m['description'],
74 tenant_id=m['tenant_id'],
77 context.session.add(metering_db)
79 return self._make_metering_label_dict(metering_db)
81 def delete_metering_label(self, context, label_id):
82 with context.session.begin(subtransactions=True):
84 label = self._get_by_id(context, MeteringLabel, label_id)
85 except orm.exc.NoResultFound:
86 raise metering.MeteringLabelNotFound(label_id=label_id)
88 context.session.delete(label)
90 def get_metering_label(self, context, label_id, fields=None):
92 metering_label = self._get_by_id(context, MeteringLabel, label_id)
93 except orm.exc.NoResultFound:
94 raise metering.MeteringLabelNotFound(label_id=label_id)
96 return self._make_metering_label_dict(metering_label, fields)
98 def get_metering_labels(self, context, filters=None, fields=None,
99 sorts=None, limit=None, marker=None,
101 marker_obj = self._get_marker_obj(context, 'metering_labels', limit,
103 return self._get_collection(context, MeteringLabel,
104 self._make_metering_label_dict,
105 filters=filters, fields=fields,
108 marker_obj=marker_obj,
109 page_reverse=page_reverse)
111 def _make_metering_label_rule_dict(self, metering_label_rule, fields=None):
112 res = {'id': metering_label_rule['id'],
113 'metering_label_id': metering_label_rule['metering_label_id'],
114 'direction': metering_label_rule['direction'],
115 'remote_ip_prefix': metering_label_rule['remote_ip_prefix'],
116 'excluded': metering_label_rule['excluded']}
117 return self._fields(res, fields)
119 def get_metering_label_rules(self, context, filters=None, fields=None,
120 sorts=None, limit=None, marker=None,
122 marker_obj = self._get_marker_obj(context, 'metering_label_rules',
125 return self._get_collection(context, MeteringLabelRule,
126 self._make_metering_label_rule_dict,
127 filters=filters, fields=fields,
130 marker_obj=marker_obj,
131 page_reverse=page_reverse)
133 def get_metering_label_rule(self, context, rule_id, fields=None):
135 metering_label_rule = self._get_by_id(context,
136 MeteringLabelRule, rule_id)
137 except orm.exc.NoResultFound:
138 raise metering.MeteringLabelRuleNotFound(rule_id=rule_id)
140 return self._make_metering_label_rule_dict(metering_label_rule, fields)
142 def _validate_cidr(self, context, label_id, remote_ip_prefix,
143 direction, excluded):
144 r_ips = self.get_metering_label_rules(context,
145 filters={'metering_label_id':
151 fields=['remote_ip_prefix'])
153 cidrs = [r['remote_ip_prefix'] for r in r_ips]
154 new_cidr_ipset = netaddr.IPSet([remote_ip_prefix])
155 if (netaddr.IPSet(cidrs) & new_cidr_ipset):
156 raise metering.MeteringLabelRuleOverlaps(
157 remote_ip_prefix=remote_ip_prefix)
159 def create_metering_label_rule(self, context, metering_label_rule):
160 m = metering_label_rule['metering_label_rule']
161 with context.session.begin(subtransactions=True):
162 label_id = m['metering_label_id']
163 ip_prefix = m['remote_ip_prefix']
164 direction = m['direction']
165 excluded = m['excluded']
167 self._validate_cidr(context, label_id, ip_prefix, direction,
169 metering_db = MeteringLabelRule(id=uuidutils.generate_uuid(),
170 metering_label_id=label_id,
172 excluded=m['excluded'],
173 remote_ip_prefix=ip_prefix)
174 context.session.add(metering_db)
176 return self._make_metering_label_rule_dict(metering_db)
178 def delete_metering_label_rule(self, context, rule_id):
179 with context.session.begin(subtransactions=True):
181 rule = self._get_by_id(context, MeteringLabelRule, rule_id)
182 except orm.exc.NoResultFound:
183 raise metering.MeteringLabelRuleNotFound(rule_id=rule_id)
184 context.session.delete(rule)
186 return self._make_metering_label_rule_dict(rule)
188 def _get_metering_rules_dict(self, metering_label):
190 for rule in metering_label.rules:
191 rule_dict = self._make_metering_label_rule_dict(rule)
192 rules.append(rule_dict)
196 def _make_router_dict(self, router):
197 res = {'id': router['id'],
198 'name': router['name'],
199 'tenant_id': router['tenant_id'],
200 'admin_state_up': router['admin_state_up'],
201 'status': router['status'],
202 'gw_port_id': router['gw_port_id'],
203 constants.METERING_LABEL_KEY: []}
207 def _process_sync_metering_data(self, context, labels):
214 all_routers = self._get_collection_query(context,
216 routers = all_routers
218 routers = label.routers
220 for router in routers:
221 router_dict = routers_dict.get(
223 self._make_router_dict(router))
225 rules = self._get_metering_rules_dict(label)
227 data = {'id': label['id'], 'rules': rules}
228 router_dict[constants.METERING_LABEL_KEY].append(data)
230 routers_dict[router['id']] = router_dict
232 return list(routers_dict.values())
234 def get_sync_data_for_rule(self, context, rule):
235 label = context.session.query(MeteringLabel).get(
236 rule['metering_label_id'])
239 routers = self._get_collection_query(context, l3_db.Router)
241 routers = label.routers
244 for router in routers:
245 router_dict = routers_dict.get(router['id'],
246 self._make_router_dict(router))
247 data = {'id': label['id'], 'rule': rule}
248 router_dict[constants.METERING_LABEL_KEY].append(data)
249 routers_dict[router['id']] = router_dict
251 return list(routers_dict.values())
253 def get_sync_data_metering(self, context, label_id=None, router_ids=None):
254 labels = context.session.query(MeteringLabel)
257 labels = labels.filter(MeteringLabel.id == label_id)
259 labels = (labels.join(MeteringLabel.routers).
260 filter(l3_db.Router.id.in_(router_ids)))
262 return self._process_sync_metering_data(context, labels)