# Copyright (c) 2014 Cisco Systems Inc. # All Rights Reserved. # # 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 sqlalchemy as sa from sqlalchemy import orm from neutron.db import api as db_api from neutron.db import model_base from neutron.db import models_v2 from neutron.plugins.ml2 import models as models_ml2 class RouterContract(model_base.BASEV2, models_v2.HasTenant): """Contracts created on the APIC. tenant_id represents the owner (APIC side) of the contract. router_id is the UUID of the router (Neutron side) this contract is referring to. """ __tablename__ = 'cisco_ml2_apic_contracts' router_id = sa.Column(sa.String(64), sa.ForeignKey('routers.id', ondelete='CASCADE'), primary_key=True) class HostLink(model_base.BASEV2): """Connectivity of host links.""" __tablename__ = 'cisco_ml2_apic_host_links' host = sa.Column(sa.String(255), nullable=False, primary_key=True) ifname = sa.Column(sa.String(64), nullable=False, primary_key=True) ifmac = sa.Column(sa.String(32), nullable=True) swid = sa.Column(sa.String(32), nullable=False) module = sa.Column(sa.String(32), nullable=False) port = sa.Column(sa.String(32), nullable=False) class ApicName(model_base.BASEV2): """Mapping of names created on the APIC.""" __tablename__ = 'cisco_ml2_apic_names' neutron_id = sa.Column(sa.String(36), nullable=False, primary_key=True) neutron_type = sa.Column(sa.String(32), nullable=False, primary_key=True) apic_name = sa.Column(sa.String(255), nullable=False) class ApicDbModel(object): """DB Model to manage all APIC DB interactions.""" def __init__(self): self.session = db_api.get_session() def get_contract_for_router(self, router_id): """Returns the specified router's contract.""" return self.session.query(RouterContract).filter_by( router_id=router_id).first() def write_contract_for_router(self, tenant_id, router_id): """Stores a new contract for the given tenant.""" contract = RouterContract(tenant_id=tenant_id, router_id=router_id) with self.session.begin(subtransactions=True): self.session.add(contract) return contract def update_contract_for_router(self, tenant_id, router_id): with self.session.begin(subtransactions=True): contract = self.session.query(RouterContract).filter_by( router_id=router_id).with_lockmode('update').first() if contract: contract.tenant_id = tenant_id self.session.merge(contract) else: self.write_contract_for_router(tenant_id, router_id) def delete_contract_for_router(self, router_id): with self.session.begin(subtransactions=True): try: self.session.query(RouterContract).filter_by( router_id=router_id).delete() except orm.exc.NoResultFound: return def add_hostlink(self, host, ifname, ifmac, swid, module, port): link = HostLink(host=host, ifname=ifname, ifmac=ifmac, swid=swid, module=module, port=port) with self.session.begin(subtransactions=True): self.session.merge(link) def get_hostlinks(self): return self.session.query(HostLink).all() def get_hostlink(self, host, ifname): return self.session.query(HostLink).filter_by( host=host, ifname=ifname).first() def get_hostlinks_for_host(self, host): return self.session.query(HostLink).filter_by( host=host).all() def get_hostlinks_for_host_switchport(self, host, swid, module, port): return self.session.query(HostLink).filter_by( host=host, swid=swid, module=module, port=port).all() def get_hostlinks_for_switchport(self, swid, module, port): return self.session.query(HostLink).filter_by( swid=swid, module=module, port=port).all() def delete_hostlink(self, host, ifname): with self.session.begin(subtransactions=True): try: self.session.query(HostLink).filter_by(host=host, ifname=ifname).delete() except orm.exc.NoResultFound: return def get_switches(self): return self.session.query(HostLink.swid).distinct() def get_modules_for_switch(self, swid): return self.session.query( HostLink.module).filter_by(swid=swid).distinct() def get_ports_for_switch_module(self, swid, module): return self.session.query( HostLink.port).filter_by(swid=swid, module=module).distinct() def get_switch_and_port_for_host(self, host): return self.session.query( HostLink.swid, HostLink.module, HostLink.port).filter_by( host=host).distinct() def get_tenant_network_vlan_for_host(self, host): pb = models_ml2.PortBinding po = models_v2.Port ns = models_ml2.NetworkSegment return self.session.query( po.tenant_id, ns.network_id, ns.segmentation_id).filter( po.id == pb.port_id).filter(pb.host == host).filter( po.network_id == ns.network_id).distinct() def add_apic_name(self, neutron_id, neutron_type, apic_name): name = ApicName(neutron_id=neutron_id, neutron_type=neutron_type, apic_name=apic_name) with self.session.begin(subtransactions=True): self.session.add(name) def update_apic_name(self, neutron_id, neutron_type, apic_name): with self.session.begin(subtransactions=True): name = self.session.query(ApicName).filter_by( neutron_id=neutron_id, neutron_type=neutron_type).with_lockmode('update').first() if name: name.apic_name = apic_name self.session.merge(name) else: self.add_apic_name(neutron_id, neutron_type, apic_name) def get_apic_names(self): return self.session.query(ApicName).all() def get_apic_name(self, neutron_id, neutron_type): return self.session.query(ApicName.apic_name).filter_by( neutron_id=neutron_id, neutron_type=neutron_type).first() def delete_apic_name(self, neutron_id): with self.session.begin(subtransactions=True): try: self.session.query(ApicName).filter_by( neutron_id=neutron_id).delete() except orm.exc.NoResultFound: return