# Please fill in the correct data for all the keys below and uncomment key-value pairs
[restproxy]
+# (StrOpt) Default Network partition in which VSD will
+# orchestrate network resources using openstack
+#
#default_net_partition_name = <default-net-partition-name>
+
+# (StrOpt) Nuage provided uri for initial authorization to
+# access VSD
+#
#auth_resource = /auth
+
+# (StrOpt) IP Address and Port of VSD
+#
#server = ip:port
+
+# (StrOpt) Organization name in which VSD will orchestrate
+# network resources using openstack
+#
#organization = org
+
+# (StrOpt) Username and password of VSD for authentication
+#
#serverauth = uname:pass
+
+# (BoolOpt) Boolean for SSL connection with VSD server
+#
#serverssl = True
+
+# (StrOpt) Nuage provided base uri to reach out to VSD
+#
#base_uri = /base
+[syncmanager]
+# (BoolOpt) Boolean to enable sync between openstack and VSD
+#
+#enable_sync = False
+
+# (IntOpt) Sync interval in seconds between openstack and VSD
+#
+#sync_interval = 0
\ No newline at end of file
help=_("Per Net Partition quota of floating ips")),
]
+syncmanager_opts = [
+ cfg.BoolOpt('enable_sync', default=False,
+ help=_("Nuage plugin will sync resources between openstack "
+ "and VSD")),
+ cfg.IntOpt('sync_interval', default=0,
+ help=_("Sync interval in seconds between openstack and VSD. "
+ "It defines how often the synchronization is done. "
+ "If not set, value of 0 is assumed and sync will be "
+ "performed only once, at the Neutron startup time.")),
+]
+
def nuage_register_cfg_opts():
cfg.CONF.register_opts(restproxy_opts, "RESTPROXY")
+ cfg.CONF.register_opts(syncmanager_opts, "SYNCMANAGER")
\ No newline at end of file
# @author: Ronak Shah, Nuage Networks, Alcatel-Lucent USA Inc.
from neutron.db import common_db_mixin
+from neutron.db import extraroute_db
+from neutron.db import l3_db
+from neutron.db import models_v2
+from neutron.db import securitygroups_db
from neutron.plugins.nuage import nuage_models
session.delete(net_partition)
+def delete_net_partition_by_id(session, netpart_id):
+ query = session.query(nuage_models.NetPartition)
+ query.filter_by(id=netpart_id).delete()
+
+
def get_net_partition_by_name(session, name):
query = session.query(nuage_models.NetPartition)
return query.filter_by(name=name).first()
return query
+def get_net_partition_ids(session):
+ query = session.query(nuage_models.NetPartition.id)
+ return [netpart[0] for netpart in query]
+
+
+def get_net_partition_with_lock(session, netpart_id):
+ query = session.query(nuage_models.NetPartition)
+ netpart_db = query.filter_by(id=netpart_id).with_lockmode('update').one()
+ return make_net_partition_dict(netpart_db)
+
+
+def get_subnet_ids(session):
+ query = session.query(models_v2.Subnet.id)
+ return [subn[0] for subn in query]
+
+
+def get_subnet_with_lock(session, sub_id):
+ query = session.query(models_v2.Subnet)
+ subnet_db = query.filter_by(id=sub_id).with_lockmode('update').one()
+ return subnet_db
+
+
+def get_router_ids(session):
+ query = session.query(l3_db.Router.id)
+ return [router[0] for router in query]
+
+
+def get_router_with_lock(session, router_id):
+ query = session.query(l3_db.Router)
+ router_db = query.filter_by(id=router_id).with_lockmode('update').one()
+ return router_db
+
+
+def get_secgrp_ids(session):
+ query = session.query(securitygroups_db.SecurityGroup.id)
+ return [secgrp[0] for secgrp in query]
+
+
+def get_secgrp_with_lock(session, secgrp_id):
+ query = session.query(securitygroups_db.SecurityGroup)
+ secgrp_db = query.filter_by(id=secgrp_id).with_lockmode('update').one()
+ return secgrp_db
+
+
+def get_secgrprule_ids(session):
+ query = session.query(securitygroups_db.SecurityGroupRule.id)
+ return [secgrprule[0] for secgrprule in query]
+
+
+def get_secgrprule_with_lock(session, secgrprule_id):
+ query = session.query(securitygroups_db.SecurityGroupRule)
+ secgrprule_db = (query.filter_by(id=secgrprule_id).with_lockmode(
+ 'update').one())
+ return secgrprule_db
+
+
+def get_port_with_lock(session, port_id):
+ query = session.query(models_v2.Port)
+ port_db = query.filter_by(id=port_id).with_lockmode('update').one()
+ return port_db
+
+
+def get_fip_with_lock(session, fip_id):
+ query = session.query(l3_db.FloatingIP)
+ fip_db = query.filter_by(id=fip_id).with_lockmode('update').one()
+ return fip_db
+
+
def add_entrouter_mapping(session, np_id,
router_id,
n_l3id):
subnet_l2dom.update(new_dict)
+def get_update_subnetl2dom_mapping(session, new_dict):
+ subnet_l2dom = get_subnet_l2dom_with_lock(session, new_dict['subnet_id'])
+ subnet_l2dom.update(new_dict)
+
+
+def update_entrtr_mapping(ent_rtr, new_dict):
+ ent_rtr.update(new_dict)
+
+
+def get_update_entrtr_mapping(session, new_dict):
+ ent_rtr = get_ent_rtr_mapping_with_lock(session, new_dict['router_id'])
+ ent_rtr.update(new_dict)
+
+
def delete_subnetl2dom_mapping(session, subnet_l2dom):
session.delete(subnet_l2dom)
return query.filter_by(subnet_id=id).first()
-def get_ent_rtr_mapping_by_entid(session,
- entid):
+def get_subnet_l2dom_with_lock(session, id):
+ query = session.query(nuage_models.SubnetL2Domain)
+ subl2dom = query.filter_by(subnet_id=id).with_lockmode('update').one()
+ return subl2dom
+
+
+def get_ent_rtr_mapping_by_entid(session, entid):
query = session.query(nuage_models.NetPartitionRouter)
return query.filter_by(net_partition_id=entid).all()
return (session.query(nuage_models.ProviderNetBinding).
filter_by(network_id=network_id).
first())
+
+
+def get_ent_rtr_mapping_with_lock(session, rtrid):
+ query = session.query(nuage_models.NetPartitionRouter)
+ entrtr = query.filter_by(router_id=rtrid).with_lockmode('update').one()
+ return entrtr
+
+
+def get_ipalloc_for_fip(session, network_id, ip, lock=False):
+ query = session.query(models_v2.IPAllocation)
+ if lock:
+ # Lock is required when the resource is synced
+ ipalloc_db = (query.filter_by(network_id=network_id).filter_by(
+ ip_address=ip).with_lockmode('update').one())
+ else:
+ ipalloc_db = (query.filter_by(network_id=network_id).filter_by(
+ ip_address=ip).one())
+ return make_ipalloc_dict(ipalloc_db)
+
+
+def get_all_net_partitions(session):
+ net_partitions = get_net_partitions(session)
+ return make_net_partition_list(net_partitions)
+
+
+def get_all_routes(session):
+ routes = session.query(extraroute_db.RouterRoute)
+ return make_route_list(routes)
+
+
+def get_route_with_lock(session, dest, nhop):
+ query = session.query(extraroute_db.RouterRoute)
+ route_db = (query.filter_by(destination=dest).filter_by(nexthop=nhop)
+ .with_lockmode('update').one())
+ return make_route_dict(route_db)
+
+
+def make_ipalloc_dict(subnet_db):
+ return {'port_id': subnet_db['port_id'],
+ 'subnet_id': subnet_db['subnet_id'],
+ 'network_id': subnet_db['network_id'],
+ 'ip_address': subnet_db['ip_address']}
+
+
+def make_net_partition_dict(net_partition):
+ return {'id': net_partition['id'],
+ 'name': net_partition['name'],
+ 'l3dom_tmplt_id': net_partition['l3dom_tmplt_id'],
+ 'l2dom_tmplt_id': net_partition['l2dom_tmplt_id']}
+
+
+def make_net_partition_list(net_partitions):
+ return [make_net_partition_dict(net_partition) for net_partition in
+ net_partitions]
+
+
+def make_route_dict(route):
+ return {'destination': route['destination'],
+ 'nexthop': route['nexthop'],
+ 'router_id': route['router_id']}
+
+
+def make_route_list(routes):
+ return [make_route_dict(route) for route in routes]
+
+
+def make_subnl2dom_dict(subl2dom):
+ return {'subnet_id': subl2dom['subnet_id'],
+ 'net_partition_id': subl2dom['net_partition_id'],
+ 'nuage_subnet_id': subl2dom['nuage_subnet_id'],
+ 'nuage_l2dom_tmplt_id': subl2dom['nuage_l2dom_tmplt_id'],
+ 'nuage_user_id': subl2dom['nuage_user_id'],
+ 'nuage_group_id': subl2dom['nuage_group_id']}
+
+
+def make_entrtr_dict(entrtr):
+ return {'net_partition_id': entrtr['net_partition_id'],
+ 'router_id': entrtr['router_id'],
+ 'nuage_router_id': entrtr['nuage_router_id']}
\ No newline at end of file
from neutron.openstack.common import excutils
from neutron.openstack.common import importutils
from neutron.openstack.common import lockutils
+from neutron.openstack.common import loopingcall
from neutron.plugins.nuage.common import config
from neutron.plugins.nuage.common import constants
from neutron.plugins.nuage.common import exceptions as nuage_exc
from neutron.plugins.nuage import extensions
from neutron.plugins.nuage.extensions import netpartition
from neutron.plugins.nuage import nuagedb
+from neutron.plugins.nuage import syncmanager
from neutron import policy
self.nuageclient_init()
net_partition = cfg.CONF.RESTPROXY.default_net_partition_name
self._create_default_net_partition(net_partition)
+ if cfg.CONF.SYNCMANAGER.enable_sync:
+ self.syncmanager = syncmanager.SyncManager(self.nuageclient)
+ self._synchronization_thread()
def nuageclient_init(self):
server = cfg.CONF.RESTPROXY.server
auth_resource,
organization)
+ def _synchronization_thread(self):
+ sync_interval = cfg.CONF.SYNCMANAGER.sync_interval
+ fip_quota = str(cfg.CONF.RESTPROXY.default_floatingip_quota)
+ if sync_interval > 0:
+ sync_loop = loopingcall.FixedIntervalLoopingCall(
+ self.syncmanager.synchronize, fip_quota)
+ sync_loop.start(interval=sync_interval)
+ else:
+ self.syncmanager.synchronize(fip_quota)
+
def _resource_finder(self, context, for_resource, resource, user_req):
match = re.match(attributes.UUID_PATTERN, user_req[resource])
if match:
neutron_fip, port_id):
rtr_id = neutron_fip['router_id']
net_id = neutron_fip['floating_network_id']
+ subn = nuagedb.get_ipalloc_for_fip(context.session,
+ net_id,
+ neutron_fip['floating_ip_address'])
- fip_pool = self.nuageclient.get_nuage_fip_pool_by_id(net_id)
+ fip_pool = self.nuageclient.get_nuage_fip_pool_by_id(subn['subnet_id'])
if not fip_pool:
- msg = _('sharedresource %s not found on VSD') % net_id
+ msg = _('sharedresource %s not found on VSD') % subn['subnet_id']
raise n_exc.BadRequest(resource='floatingip',
msg=msg)
--- /dev/null
+# Copyright 2014 Alcatel-Lucent USA Inc.
+#
+# 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.
+#
+# @author: Sayaji Patil, Nuage Networks, Alcatel-Lucent USA Inc.
+
+from oslo.config import cfg
+import sqlalchemy.orm.exc as db_exc
+
+from neutron import context as ncontext
+from neutron.db import db_base_plugin_v2
+from neutron.db import extraroute_db
+from neutron.db import securitygroups_db
+from neutron.openstack.common import importutils
+from neutron.openstack.common import log
+from neutron.openstack.common.gettextutils import _LE, _LI, _LW
+from neutron.plugins.nuage.common import config
+from neutron.plugins.nuage import nuagedb
+
+
+LOG = log.getLogger(__name__)
+NUAGE_CONFIG_FILE = '/etc/neutron/plugins/nuage/nuage_plugin.ini'
+
+
+class SyncManager(db_base_plugin_v2.NeutronDbPluginV2,
+ extraroute_db.ExtraRoute_db_mixin,
+ securitygroups_db.SecurityGroupDbMixin):
+ """
+ This class provides functionality to sync data between OpenStack and VSD.
+ """
+
+ def __init__(self, nuageclient):
+ self.context = ncontext.get_admin_context()
+ self.nuageclient = nuageclient
+
+ def synchronize(self, fipquota):
+ LOG.info(_LI("Starting the sync between Neutron and VSD"))
+ try:
+ # Get all data to determine the resources to sync
+ data = self._get_all_data()
+ resources = self.nuageclient.get_resources_to_sync(data)
+
+ # Sync all resources
+ self._sync(resources, fipquota)
+ except Exception as e:
+ LOG.error(_LE("Cannot complete the sync between Neutron and VSD "
+ "because of error:%s"), str(e))
+ return
+
+ LOG.info(_LI("Sync between Neutron and VSD completed successfully"))
+
+ def _get_all_data(self):
+ # Get all net-partitions
+ net_partition_list = nuagedb.get_all_net_partitions(
+ self.context.session)
+
+ # Get all subnet ids
+ subnet_id_list = nuagedb.get_subnet_ids(self.context.session)
+
+ # Get all router ids
+ router_id_list = nuagedb.get_router_ids(self.context.session)
+
+ # Get all ports
+ port_list = self.get_ports(self.context)
+
+ # Get all routes
+ route_list = nuagedb.get_all_routes(self.context.session)
+
+ # Get all floatingips
+ fip_list = self.get_floatingips(self.context)
+
+ # Get all securitygrp ids
+ secgrp_id_list = nuagedb.get_secgrp_ids(self.context.session)
+
+ # Get all securitygrprules
+ secgrprule_id_list = self.get_security_group_rules(self.context)
+
+ # Get all portbindings
+ portbinding_list = self._get_port_security_group_bindings(self.context)
+
+ data = {
+ 'netpartition': net_partition_list,
+ 'subnet': subnet_id_list,
+ 'router': router_id_list,
+ 'port': port_list,
+ 'route': route_list,
+ 'fip': fip_list,
+ 'secgroup': secgrp_id_list,
+ 'secgrouprule': secgrprule_id_list,
+ 'portbinding': portbinding_list,
+ }
+ return data
+
+ def _sync(self, resources, fip_quota):
+ # Sync net-partitions
+ net_partition_id_dict = self.sync_net_partitions(fip_quota, resources)
+
+ # Sync sharednetworks
+ self.sync_sharednetworks(resources)
+
+ # Sync l2domains
+ self.sync_l2domains(net_partition_id_dict, resources)
+
+ # Sync domains
+ self.sync_domains(net_partition_id_dict, resources)
+
+ # Sync domainsubnets
+ self.sync_domainsubnets(resources)
+
+ # Sync routes
+ self.sync_routes(resources)
+
+ # Sync vms
+ self.sync_vms(resources)
+
+ # Sync secgrps
+ self.sync_secgrps(resources)
+
+ # Sync secgrprules
+ self.sync_secgrp_rules(resources)
+
+ # Sync fips
+ self._sync_fips(resources)
+
+ # Delete the old net-partitions
+ for net_id in net_partition_id_dict:
+ nuagedb.delete_net_partition_by_id(self.context.session,
+ net_id)
+
+ def sync_net_partitions(self, fip_quota, resources):
+ net_partition_id_dict = {}
+ for netpart_id in resources['netpartition']['add']:
+ with self.context.session.begin(subtransactions=True):
+ netpart = self._get_netpart_data(netpart_id)
+ if netpart:
+ result = self.nuageclient.create_netpart(netpart,
+ fip_quota)
+ netpart = result.get(netpart_id)
+ if netpart:
+ net_partition_id_dict[netpart_id] = netpart['id']
+ nuagedb.add_net_partition(
+ self.context.session,
+ netpart['id'],
+ netpart['l3dom_tmplt_id'],
+ netpart['l2dom_tmplt_id'],
+ netpart['name'])
+
+ return net_partition_id_dict
+
+ def sync_sharednetworks(self, resources):
+ for sharednet_id in resources['sharednetwork']['add']:
+ with self.context.session.begin(subtransactions=True):
+ subnet, subl2dom = self._get_subnet_data(
+ sharednet_id,
+ get_mapping=False)
+ if subnet:
+ self.nuageclient.create_sharednetwork(subnet)
+
+ def sync_l2domains(self, net_partition_id_dict, resources):
+ for l2dom_id in resources['l2domain']['add']:
+ with self.context.session.begin(subtransactions=True):
+ subnet, subl2dom = self._get_subnet_data(l2dom_id)
+ if subnet:
+ # if subnet exists, subl2dom will exist
+ netpart_id = subl2dom['net_partition_id']
+ if netpart_id in net_partition_id_dict.keys():
+ # Use the id of the newly created net_partition
+ netpart_id = net_partition_id_dict[netpart_id]
+
+ result = self.nuageclient.create_l2domain(netpart_id,
+ subnet)
+ if result:
+ nuagedb.get_update_subnetl2dom_mapping(
+ self.context.session,
+ result)
+
+ def sync_domains(self, net_partition_id_dict, resources):
+ for domain_id in resources['domain']['add']:
+ with self.context.session.begin(subtransactions=True):
+ router, entrtr = self._get_router_data(domain_id)
+ if router:
+ # if router exists, entrtr will exist
+ netpart_id = entrtr['net_partition_id']
+ if netpart_id in net_partition_id_dict.keys():
+ # Use the id of the newly created net_partition
+ netpart_id = net_partition_id_dict[netpart_id]
+
+ netpart = nuagedb.get_net_partition_by_id(
+ self.context.session,
+ netpart_id)
+ result = self.nuageclient.create_domain(netpart, router)
+ if result:
+ nuagedb.get_update_entrtr_mapping(self.context.session,
+ result)
+
+ def sync_domainsubnets(self, resources):
+ for domsubn_id in resources['domainsubnet']['add']:
+ # This is a dict of subn_id and the router interface port
+ subn_rtr_intf_port_dict = (
+ resources['port']['sub_rtr_intf_port_dict'])
+ port_id = subn_rtr_intf_port_dict[domsubn_id]
+ port = self._get_port_data(port_id)
+ if port:
+ with self.context.session.begin(subtransactions=True):
+ subnet, subl2dom = self._get_subnet_data(domsubn_id)
+ if subnet:
+ result = self.nuageclient.create_domainsubnet(subnet,
+ port)
+ if result:
+ nuagedb.get_update_subnetl2dom_mapping(
+ self.context.session,
+ result)
+
+ def sync_routes(self, resources):
+ for rt in resources['route']['add']:
+ with self.context.session.begin(subtransactions=True):
+ route = self._get_route_data(rt)
+ if route:
+ self.nuageclient.create_route(route)
+
+ def sync_vms(self, resources):
+ for port_id in resources['port']['vm']:
+ port = self._get_port_data(port_id)
+ if port:
+ self.nuageclient.create_vm(port)
+
+ def sync_secgrps(self, resources):
+ secgrp_dict = resources['security']['secgroup']
+ for secgrp_id, ports in secgrp_dict['l2domain']['add'].iteritems():
+ with self.context.session.begin(subtransactions=True):
+ secgrp = self._get_sec_grp_data(secgrp_id)
+ if secgrp:
+ self.nuageclient.create_security_group(secgrp, ports)
+
+ for secgrp_id, ports in secgrp_dict['domain']['add'].iteritems():
+ with self.context.session.begin(subtransactions=True):
+ secgrp = self._get_sec_grp_data(secgrp_id)
+ if secgrp:
+ self.nuageclient.create_security_group(secgrp, ports)
+
+ def sync_secgrp_rules(self, resources):
+ secrule_list = resources['security']['secgrouprule']
+ for secrule_id in secrule_list['l2domain']['add']:
+ with self.context.session.begin(subtransactions=True):
+ secgrprule = self._get_sec_grp_rule_data(secrule_id)
+ if secgrprule:
+ self.nuageclient.create_security_group_rule(secgrprule)
+
+ for secrule_id in secrule_list['domain']['add']:
+ with self.context.session.begin(subtransactions=True):
+ secgrprule = self._get_sec_grp_rule_data(secrule_id)
+ if secgrprule:
+ self.nuageclient.create_security_group_rule(secgrprule)
+
+ def _sync_fips(self, resources):
+ for fip_id in resources['fip']['add']:
+ with self.context.session.begin(subtransactions=True):
+ fip = self._get_fip_data(fip_id)
+ if fip:
+ ipalloc = self._get_ipalloc_for_fip(fip)
+ self.nuageclient.create_fip(fip, ipalloc)
+
+ for fip_id in resources['fip']['disassociate']:
+ with self.context.session.begin(subtransactions=True):
+ fip = self._get_fip_data(fip_id)
+ if fip:
+ self.nuageclient.disassociate_fip(fip)
+
+ for fip_id in resources['fip']['associate']:
+ with self.context.session.begin(subtransactions=True):
+ fip = self._get_fip_data(fip_id)
+ if fip:
+ self.nuageclient.associate_fip(fip)
+
+ def _get_subnet_data(self, subnet_id, get_mapping=True):
+ subnet = None
+ subl2dom = None
+ try:
+ if get_mapping:
+ subl2dom_db = nuagedb.get_subnet_l2dom_with_lock(
+ self.context.session,
+ subnet_id)
+ subl2dom = nuagedb.make_subnl2dom_dict(subl2dom_db)
+
+ subnet_db = nuagedb.get_subnet_with_lock(self.context.session,
+ subnet_id)
+ subnet = self._make_subnet_dict(subnet_db)
+ except db_exc.NoResultFound:
+ LOG.warning(_LW("Subnet %s not found in neutron for sync"),
+ subnet_id)
+
+ return subnet, subl2dom
+
+ def _get_router_data(self, router_id):
+ router = None
+ entrtr = None
+ try:
+ entrtr_db = nuagedb.get_ent_rtr_mapping_with_lock(
+ self.context.session,
+ router_id)
+ entrtr = nuagedb.make_entrtr_dict(entrtr_db)
+
+ router_db = nuagedb.get_router_with_lock(self.context.session,
+ router_id)
+ router = self._make_router_dict(router_db)
+ except db_exc.NoResultFound:
+ LOG.warning(_LW("Router %s not found in neutron for sync"),
+ router_id)
+
+ return router, entrtr
+
+ def _get_route_data(self, rt):
+ route = None
+ try:
+ route = nuagedb.get_route_with_lock(self.context.session,
+ rt['destination'],
+ rt['nexthop'])
+ except db_exc.NoResultFound:
+ LOG.warning(_LW("Route with destination %(dest)s and nexthop "
+ "%(hop)s not found in neutron for sync"),
+ {'dest': rt['destination'],
+ 'hop': rt['nexthop']})
+
+ return route
+
+ def _get_sec_grp_data(self, secgrp_id):
+ secgrp = None
+ try:
+ secgrp_db = nuagedb.get_secgrp_with_lock(self.context.session,
+ secgrp_id)
+ secgrp = self._make_security_group_dict(secgrp_db)
+ except db_exc.NoResultFound:
+ LOG.warning(_LW("Security group %s not found in neutron for sync"),
+ secgrp_id)
+ return secgrp
+
+ def _get_sec_grp_rule_data(self, secgrprule_id):
+ secgrprule = None
+ try:
+ secrule_db = nuagedb.get_secgrprule_with_lock(self.context.session,
+ secgrprule_id)
+ secgrprule = self._make_security_group_rule_dict(secrule_db)
+ except db_exc.NoResultFound:
+ LOG.warning(_LW("Security group rule %s not found in neutron for "
+ "sync"), secgrprule_id)
+ return secgrprule
+
+ def _get_fip_data(self, fip_id):
+ fip = None
+ try:
+ fip_db = nuagedb.get_fip_with_lock(self.context.session, fip_id)
+ fip = self._make_floatingip_dict(fip_db)
+ except db_exc.NoResultFound:
+ LOG.warning(_LW("Floating ip %s not found in neutron for sync"),
+ fip_id)
+ return fip
+
+ def _get_ipalloc_for_fip(self, fip):
+ ipalloc = None
+ try:
+ ipalloc = nuagedb.get_ipalloc_for_fip(self.context.session,
+ fip['floating_network_id'],
+ fip['floating_ip_address'],
+ lock=True)
+ except db_exc.NoResultFound:
+ LOG.warning(_LW("IP allocation for floating ip %s not found in "
+ "neutron for sync"), fip['id'])
+ return ipalloc
+
+ def _get_netpart_data(self, netpart_id):
+ netpart = None
+ try:
+ netpart = nuagedb.get_net_partition_with_lock(
+ self.context.session,
+ netpart_id)
+ except db_exc.NoResultFound:
+ LOG.warning(_LW("Net-partition %s not found in neutron for sync"),
+ netpart_id)
+ return netpart
+
+ def _get_port_data(self, port_id):
+ port = None
+ try:
+ port_db = nuagedb.get_port_with_lock(self.context.session, port_id)
+ port = self._make_port_dict(port_db)
+ except db_exc.NoResultFound:
+ LOG.warning(_LW("VM port %s not found in neutron for sync"),
+ port_id)
+ return port
+
+
+def main():
+ cfg.CONF(default_config_files=(
+ [NUAGE_CONFIG_FILE]))
+ config.nuage_register_cfg_opts()
+ server = cfg.CONF.RESTPROXY.server
+ serverauth = cfg.CONF.RESTPROXY.serverauth
+ serverssl = cfg.CONF.RESTPROXY.serverssl
+ base_uri = cfg.CONF.RESTPROXY.base_uri
+ auth_resource = cfg.CONF.RESTPROXY.auth_resource
+ organization = cfg.CONF.RESTPROXY.organization
+ fipquota = str(cfg.CONF.RESTPROXY.default_floatingip_quota)
+ logging = importutils.import_module('logging')
+ nuageclientinst = importutils.import_module('nuagenetlib.nuageclient')
+ nuageclient = nuageclientinst.NuageClient(server, base_uri,
+ serverssl, serverauth,
+ auth_resource,
+ organization)
+ logging.basicConfig(level=logging.DEBUG)
+ SyncManager(nuageclient).synchronize(fipquota)
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
def remove_router_interface(self, params):
pass
+
+ def get_resources_to_sync(self, data):
+ netpart_id_list = []
+ for netpart in data['netpartition']:
+ netpart_id_list.append(netpart['id'])
+
+ netpart_dict = {
+ 'add': netpart_id_list,
+ 'sync': []
+ }
+
+ subn_id_list = []
+ if data['subnet']:
+ subn_id_list.append(data['subnet'][0])
+
+ l2domain_dict = {
+ 'add': subn_id_list
+ }
+
+ rtr_id_list = []
+ if data['router']:
+ rtr_id_list.append(data['router'][0])
+
+ domain_dict = {
+ 'add': rtr_id_list
+ }
+
+ domain_subn_id = uuidutils.generate_uuid()
+
+ result = {
+ 'netpartition': netpart_dict,
+ 'l2domain': l2domain_dict,
+ 'domain': domain_dict,
+ 'domainsubnet': {'add': [domain_subn_id]},
+ 'sharednetwork': {'add': [uuidutils.generate_uuid()]},
+ 'route': {'add': []},
+ 'security': {
+ 'secgroup': {
+ 'l2domain': {'add': {
+ uuidutils.generate_uuid(): [uuidutils.generate_uuid()]
+ }},
+ 'domain': {'add': {
+ uuidutils.generate_uuid(): [uuidutils.generate_uuid()]
+ }}
+ },
+ 'secgrouprule': {
+ 'l2domain': {'add': [uuidutils.generate_uuid()]},
+ 'domain': {'add': [uuidutils.generate_uuid()]}
+ },
+ },
+ 'port': {
+ 'vm': [uuidutils.generate_uuid()],
+ 'sub_rtr_intf_port_dict': {
+ domain_subn_id: uuidutils.generate_uuid()
+ },
+ 'secgroup': [uuidutils.generate_uuid()]
+ },
+ 'subl2dommapping': [uuidutils.generate_uuid()],
+ 'fip': {
+ 'add': [uuidutils.generate_uuid()],
+ 'associate': [uuidutils.generate_uuid()],
+ 'disassociate': [uuidutils.generate_uuid()]
+ }
+ }
+ return result
+
+ def create_netpart(self, netpart, fip_quota):
+ if netpart['name'] == 'sync-new-netpartition':
+ oldid = netpart['id']
+ netpart['id'] = 'a917924f-3139-4bdb-a4c3-ea7c8011582f'
+ netpart = {
+ oldid: netpart
+ }
+ return netpart
+ return {}
+
+ def create_sharednetwork(self, subnet):
+ pass
+
+ def create_l2domain(self, netpart_id, subnet):
+ subl2dom = {
+ 'subnet_id': subnet['id'],
+ 'nuage_subnet_id': '52daa465-cf33-4efd-91d3-f5bc2aebd',
+ 'net_partition_id': netpart_id,
+ 'nuage_l2dom_tmplt_id': uuidutils.generate_uuid(),
+ 'nuage_user_id': uuidutils.generate_uuid(),
+ 'nuage_group_id': uuidutils.generate_uuid(),
+ }
+
+ return subl2dom
+
+ def create_domain(self, netpart, router):
+ entrtr = {
+ 'router_id': router['id'],
+ 'nuage_router_id': '2d782c02-b88e-44ad-a79b-4bdf11f7df3d',
+ 'net_partition_id': netpart['id']
+ }
+
+ return entrtr
+
+ def create_domainsubnet(self, subnet, ports):
+ pass
+
+ def create_route(self, route):
+ pass
+
+ def create_vm(self, port):
+ pass
+
+ def create_security_group(self, secgrp, ports):
+ pass
+
+ def create_security_group_rule(self, secgrprule):
+ pass
+
+ def create_fip(self, fip, ipalloc):
+ pass
+
+ def associate_fip(self, fip):
+ pass
+
+ def disassociate_fip(self, fip):
+ pass
_plugin_name = ('%s.NuagePlugin' % NUAGE_PLUGIN_PATH)
+def getNuageClient():
+ server = FAKE_SERVER
+ serverauth = FAKE_SERVER_AUTH
+ serverssl = FAKE_SERVER_SSL
+ base_uri = FAKE_BASE_URI
+ auth_resource = FAKE_AUTH_RESOURCE
+ organization = FAKE_ORGANIZATION
+ nuageclient = fake_nuageclient.FakeNuageClient(server,
+ base_uri,
+ serverssl,
+ serverauth,
+ auth_resource,
+ organization)
+ return nuageclient
+
+
class NuagePluginV2TestCase(test_db_plugin.NeutronDbPluginV2TestCase):
def setUp(self, plugin=_plugin_name,
ext_mgr=None, service_plugins=None):
self.skipTest("Nuage Plugin does not support IPV6.")
def mock_nuageClient_init(self):
- server = FAKE_SERVER
- serverauth = FAKE_SERVER_AUTH
- serverssl = FAKE_SERVER_SSL
- base_uri = FAKE_BASE_URI
- auth_resource = FAKE_AUTH_RESOURCE
- organization = FAKE_ORGANIZATION
- self.nuageclient = None
- self.nuageclient = fake_nuageclient.FakeNuageClient(server,
- base_uri,
- serverssl,
- serverauth,
- auth_resource,
- organization)
+ self.nuageclient = getNuageClient()
with mock.patch.object(nuage_plugin.NuagePlugin,
'nuageclient_init', new=mock_nuageClient_init):
# The Nuage plugin reserve the first port
port = ports['ports'][1]
self.assertEqual(1, len(port[ext_sg.SECURITYGROUPS]))
- self._delete('ports', port['id'])
\ No newline at end of file
+ self._delete('ports', port['id'])
--- /dev/null
+# Copyright 2014 Alcatel-Lucent USA Inc.
+#
+# 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.
+#
+# @author: Sayaji Patil, Nuage Networks, Alcatel-Lucent USA Inc.
+
+import contextlib
+
+from neutron import context
+from neutron.openstack.common import uuidutils
+from neutron.plugins.nuage import nuage_models
+from neutron.plugins.nuage import syncmanager as sync
+from neutron.tests.unit.nuage import test_netpartition
+from neutron.tests.unit.nuage import test_nuage_plugin
+from neutron.tests.unit import test_extension_extraroute as extraroute_test
+from neutron.tests.unit import test_extension_security_group as test_sg
+from neutron.tests.unit import test_l3_plugin
+
+_uuid = uuidutils.generate_uuid
+
+
+class TestL3Sync(test_nuage_plugin.NuagePluginV2TestCase,
+ test_l3_plugin.L3NatDBIntTestCase):
+
+ def setUp(self):
+ self.session = context.get_admin_context().session
+ self.syncmanager = sync.SyncManager(
+ test_nuage_plugin.getNuageClient())
+ super(TestL3Sync, self).setUp()
+
+ def _make_floatingip_for_tenant_port(self, net_id, port_id, tenant_id):
+ data = {'floatingip': {'floating_network_id': net_id,
+ 'tenant_id': tenant_id,
+ 'port_id': port_id}}
+ floatingip_req = self.new_create_request('floatingips', data, self.fmt)
+ res = floatingip_req.get_response(self.ext_api)
+ return self.deserialize(self.fmt, res)
+
+ def test_router_sync(self):
+ # If the router exists in neutron and not in VSD,
+ # sync will create it in VSD. But the nuage_router_id
+ # will now change and will be updated in neutron
+ # accordingly
+ rtr_res = self._create_router('json', 'foo', 'test-router', True)
+ router = self.deserialize('json', rtr_res)
+
+ self.syncmanager.synchronize('250')
+
+ # Check that the nuage_router_id is updated in entrtrmapping table
+ router_db = self.session.query(
+ nuage_models.NetPartitionRouter).filter_by(
+ router_id=router['router']['id']).first()
+
+ self.assertEqual('2d782c02-b88e-44ad-a79b-4bdf11f7df3d',
+ router_db['nuage_router_id'])
+
+ self._delete('routers', router['router']['id'])
+
+ def test_router_deleted_get(self):
+ data = self.syncmanager._get_router_data(_uuid())
+ self.assertIsNone(data[0])
+ self.assertIsNone(data[1])
+
+ def test_fip_sync(self):
+ with self.subnet(cidr='200.0.0.0/24') as public_sub:
+ self._set_net_external(public_sub['subnet']['network_id'])
+ with contextlib.nested(self.port(), self.port(), self.port()) as (
+ p1, p2, p3):
+ p1_id = p1['port']['id']
+ p2_id = p2['port']['id']
+ p3_id = p3['port']['id']
+ with contextlib.nested(self.floatingip_with_assoc(
+ port_id=p1_id), self.floatingip_with_assoc(
+ port_id=p2_id), self.floatingip_with_assoc(
+ port_id=p3_id)) as (fip1, fip2, fip3):
+ fip_dict = {'fip': {
+ 'add': [fip1['floatingip']['id']],
+ 'associate': [fip2['floatingip']['id']],
+ 'disassociate': [fip3['floatingip']['id']]
+ }}
+ self.syncmanager._sync_fips(fip_dict)
+
+ def test_deleted_fip_sync(self):
+ fip_dict = {'fip': {
+ 'add': [_uuid()],
+ 'associate': [_uuid()],
+ 'disassociate': [_uuid()]
+ }}
+ self.syncmanager._sync_fips(fip_dict)
+
+ def test_fip_and_ipalloc_get(self):
+ with self.subnet(cidr='200.0.0.0/24') as public_sub:
+ self._set_net_external(public_sub['subnet']['network_id'])
+ with self.port() as port:
+ p_id = port['port']['id']
+ with self.floatingip_with_assoc(port_id=p_id) as fip:
+
+ data = self.syncmanager._get_fip_data(
+ fip['floatingip']['id'])
+
+ self.assertEqual(fip['floatingip']['id'], data['id'])
+
+ data = self.syncmanager._get_ipalloc_for_fip(
+ fip['floatingip'])
+ self.assertEqual(fip['floatingip']['floating_ip_address'],
+ data['ip_address'])
+
+ def test_fip_and_ipalloc_deleted_get(self):
+ data = self.syncmanager._get_fip_data(_uuid())
+ self.assertIsNone(data)
+
+ fip = {
+ 'id': _uuid(),
+ 'floating_network_id': _uuid(),
+ 'floating_ip_address': '176.176.10.10'
+ }
+ data = self.syncmanager._get_ipalloc_for_fip(fip)
+ self.assertIsNone(data)
+
+ def test_domainsubnet_sync(self):
+ with self.subnet() as s1:
+ with contextlib.nested(
+ self.router(),
+ self.port()) as (r1, p1):
+ self._router_interface_action(
+ 'add', r1['router']['id'],
+ s1['subnet']['id'], p1['port']['id'])
+ domainsubn_dict = {
+ 'domainsubnet': {'add': [s1['subnet']['id']]},
+ 'port': {'sub_rtr_intf_port_dict': {s1['subnet']['id']:
+ p1['port']['id']}}}
+ self.syncmanager.sync_domainsubnets(domainsubn_dict)
+ self._router_interface_action('remove', r1['router']['id'],
+ s1['subnet']['id'], None)
+
+ def test_floatingip_update_different_router(self):
+ self._test_floatingip_update_different_router()
+
+ def test_floatingip_update_different_fixed_ip_same_port(self):
+ self._test_floatingip_update_different_fixed_ip_same_port()
+
+ def test_floatingip_create_different_fixed_ip_same_port(self):
+ self._test_floatingip_create_different_fixed_ip_same_port()
+
+ def test_network_update_external_failure(self):
+ self._test_network_update_external_failure()
+
+
+class TestExtraRouteSync(extraroute_test.ExtraRouteDBIntTestCase):
+
+ def setUp(self):
+ self.session = context.get_admin_context().session
+ self.syncmanager = sync.SyncManager(
+ test_nuage_plugin.getNuageClient())
+ super(TestExtraRouteSync, self).setUp()
+
+ def test_route_sync(self):
+ route = {'destination': '135.207.0.0/16', 'nexthop': '10.0.1.3'}
+ with self.router() as r:
+ with self.subnet(cidr='10.0.1.0/24') as s:
+ net_id = s['subnet']['network_id']
+ res = self._create_port('json', net_id)
+ p = self.deserialize(self.fmt, res)
+ self._routes_update_prepare(r['router']['id'],
+ None, p['port']['id'], [route])
+
+ route_dict = {'route': {'add': [route]}}
+ self.syncmanager.sync_routes(route_dict)
+
+ self._routes_update_cleanup(p['port']['id'],
+ None, r['router']['id'], [])
+
+ def test_route_get(self):
+ routes = [{'destination': '135.207.0.0/16', 'nexthop': '10.0.1.3'}]
+ with self.router() as r:
+ with self.subnet(cidr='10.0.1.0/24') as s:
+ net_id = s['subnet']['network_id']
+ res = self._create_port('json', net_id)
+ p = self.deserialize(self.fmt, res)
+ self._routes_update_prepare(r['router']['id'],
+ None, p['port']['id'], routes)
+
+ data = self.syncmanager._get_route_data(routes[0])
+ self.assertEqual(routes[0]['destination'], data['destination'])
+ self.assertEqual(routes[0]['nexthop'], data['nexthop'])
+ self._routes_update_cleanup(p['port']['id'],
+ None, r['router']['id'], [])
+
+ def test_route_deleted_get(self):
+ route = {'destination': '135.207.0.0/16', 'nexthop': '10.0.1.3'}
+ data = self.syncmanager._get_route_data(route)
+ self.assertIsNone(data)
+
+
+class TestNetPartSync(test_netpartition.NetPartitionTestCase):
+
+ def setUp(self):
+ self.session = context.get_admin_context().session
+ self.syncmanager = sync.SyncManager(
+ test_nuage_plugin.getNuageClient())
+ super(TestNetPartSync, self).setUp()
+
+ def test_net_partition_sync(self):
+ # If the net-partition exists in neutron and not in VSD,
+ # sync will create it in VSD. But the net-partition
+ # id will now change and has to be updated in neutron
+ # accordingly
+ netpart = self._make_netpartition('json', 'sync-new-netpartition')
+
+ self.syncmanager.synchronize('250')
+
+ # Check that the net-partition id is updated in db
+ netpart_db = self.session.query(
+ nuage_models.NetPartition).filter_by(name=netpart['net_partition'][
+ 'name']).first()
+
+ self.assertEqual('a917924f-3139-4bdb-a4c3-ea7c8011582f',
+ netpart_db['id'])
+ self._del_netpartition(netpart_db['id'])
+
+ def test_net_partition_deleted_get(self):
+ data = self.syncmanager._get_netpart_data(_uuid())
+ self.assertIsNone(data)
+
+
+class TestL2Sync(test_nuage_plugin.NuagePluginV2TestCase):
+
+ def setUp(self):
+ self.session = context.get_admin_context().session
+ self.syncmanager = sync.SyncManager(
+ test_nuage_plugin.getNuageClient())
+ super(TestL2Sync, self).setUp()
+
+ def test_subnet_sync(self):
+ # If the subnet exists in neutron and not in VSD,
+ # sync will create it in VSD. But the nuage_subnet_id
+ # will now change and will be updated in neutron
+ # accordingly
+ net_res = self._create_network("json", "pub", True)
+ network = self.deserialize('json', net_res)
+
+ sub_res = self._create_subnet("json", network['network']['id'],
+ '10.0.0.0/24')
+ subnet = self.deserialize('json', sub_res)
+
+ self.syncmanager.synchronize('250')
+
+ # Check that the nuage_subnet_id is updated in db
+ subl2dom_db = self.session.query(
+ nuage_models.SubnetL2Domain).filter_by(subnet_id=subnet[
+ 'subnet']['id']).first()
+ self.assertEqual('52daa465-cf33-4efd-91d3-f5bc2aebd',
+ subl2dom_db['nuage_subnet_id'])
+
+ self._delete('subnets', subnet['subnet']['id'])
+ self._delete('networks', network['network']['id'])
+
+ def test_subnet_deleted_get(self):
+ data = self.syncmanager._get_subnet_data(_uuid())
+ self.assertIsNone(data[0])
+ self.assertIsNone(data[1])
+
+ def test_sharednetwork_sync(self):
+ with self.subnet(cidr='200.0.0.0/24') as public_sub:
+ sharednet_dict = {'sharednetwork': {'add': [public_sub['subnet'][
+ 'id']]}}
+ self.syncmanager.sync_sharednetworks(sharednet_dict)
+
+ def test_vm_sync(self):
+ with self.port() as p:
+ port_dict = {'port': {'vm': [p['port']['id']]}}
+ self.syncmanager.sync_vms(port_dict)
+
+
+class TestSecurityGroupSync(test_sg.TestSecurityGroups):
+
+ def setUp(self):
+ self.session = context.get_admin_context().session
+ self.syncmanager = sync.SyncManager(
+ test_nuage_plugin.getNuageClient())
+ super(TestSecurityGroupSync, self).setUp()
+
+ def test_sg_get(self):
+ with self.security_group() as sg:
+ data = self.syncmanager._get_sec_grp_data(
+ sg['security_group']['id'])
+ self.assertEqual(sg['security_group']['id'], data['id'])
+
+ def test_sg_deleted_get(self):
+ data = self.syncmanager._get_sec_grp_data(_uuid())
+ self.assertIsNone(data)
+
+ def test_sg_rule_get(self):
+ with self.security_group() as sg:
+ sg_rule_id = sg['security_group']['security_group_rules'][0]['id']
+ data = self.syncmanager._get_sec_grp_rule_data(sg_rule_id)
+ self.assertEqual(sg_rule_id, data['id'])
+
+ def test_sg_rule_deleted_get(self):
+ data = self.syncmanager._get_sec_grp_rule_data(_uuid())
+ self.assertIsNone(data)
+
+ def test_sg_grp_sync(self):
+ with contextlib.nested(self.security_group(),
+ self.security_group()) as (sg1, sg2):
+ sg1_id = sg1['security_group']['id']
+ sg2_id = sg2['security_group']['id']
+ sg_dict = {'security': {'secgroup': {'l2domain': {'add': {sg1_id: [
+ _uuid()]}}, 'domain': {'add': {sg2_id: [_uuid()]}}}}}
+ self.syncmanager.sync_secgrps(sg_dict)
+
+ def test_deleted_sg_grp_sync(self):
+ sg_dict = {'security': {'secgroup': {'l2domain': {'add': {_uuid(): [
+ _uuid()]}}, 'domain': {'add': {_uuid(): [_uuid()]}}}}}
+ self.syncmanager.sync_secgrps(sg_dict)
+
+ def test_sg_rule_sync(self):
+ with contextlib.nested(self.security_group(),
+ self.security_group()) as (sg1, sg2):
+ sg1_rule_id = (
+ sg1['security_group']['security_group_rules'][0]['id'])
+ sg2_rule_id = (
+ sg2['security_group']['security_group_rules'][0]['id'])
+
+ sg_dict = {'security': {'secgrouprule': {'l2domain': {
+ 'add': [sg1_rule_id]}, 'domain': {'add': [sg2_rule_id]}}}}
+ self.syncmanager.sync_secgrp_rules(sg_dict)
+
+ def test_deleted_sg_grp_rule_sync(self):
+ sg_dict = {'security': {'secgrouprule':
+ {'l2domain': {'add': [_uuid()]},
+ 'domain': {'add': [_uuid()]}}}}
+ self.syncmanager.sync_secgrp_rules(sg_dict)
\ No newline at end of file