# vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2013 VMware, 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 netaddr from oslo.config import cfg from neutron.common import exceptions as q_exc from neutron.db.firewall import firewall_db from neutron.db import l3_db from neutron.db.loadbalancer import loadbalancer_db from neutron.db import routedserviceinsertion_db as rsi_db from neutron.extensions import firewall as fw_ext from neutron.extensions import l3 from neutron.extensions import routedserviceinsertion as rsi from neutron.openstack.common import excutils from neutron.openstack.common import log as logging from neutron.plugins.common import constants as service_constants from neutron.plugins.nicira.common import config # noqa from neutron.plugins.nicira.common import exceptions as nvp_exc from neutron.plugins.nicira.common import utils from neutron.plugins.nicira.dbexts import servicerouter as sr_db from neutron.plugins.nicira.dbexts import vcns_db from neutron.plugins.nicira.dbexts import vcns_models from neutron.plugins.nicira.extensions import servicerouter as sr from neutron.plugins.nicira import NeutronPlugin from neutron.plugins.nicira.nsxlib import router as routerlib from neutron.plugins.nicira.nsxlib import switch as switchlib from neutron.plugins.nicira import NvpApiClient from neutron.plugins.nicira.vshield.common import ( constants as vcns_const) from neutron.plugins.nicira.vshield.common.constants import RouterStatus from neutron.plugins.nicira.vshield.common import exceptions from neutron.plugins.nicira.vshield.tasks.constants import TaskState from neutron.plugins.nicira.vshield.tasks.constants import TaskStatus from neutron.plugins.nicira.vshield import vcns_driver from sqlalchemy.orm import exc as sa_exc LOG = logging.getLogger(__name__) ROUTER_TYPE_BASIC = 1 ROUTER_TYPE_ADVANCED = 2 ROUTER_STATUS = [ service_constants.ACTIVE, service_constants.DOWN, service_constants.PENDING_CREATE, service_constants.PENDING_DELETE, service_constants.ERROR ] ROUTER_STATUS_LEVEL = { service_constants.ACTIVE: RouterStatus.ROUTER_STATUS_ACTIVE, service_constants.DOWN: RouterStatus.ROUTER_STATUS_DOWN, service_constants.PENDING_CREATE: ( RouterStatus.ROUTER_STATUS_PENDING_CREATE ), service_constants.PENDING_DELETE: ( RouterStatus.ROUTER_STATUS_PENDING_DELETE ), service_constants.ERROR: RouterStatus.ROUTER_STATUS_ERROR } class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin, NeutronPlugin.NvpPluginV2, rsi_db.RoutedServiceInsertionDbMixin, firewall_db.Firewall_db_mixin, loadbalancer_db.LoadBalancerPluginDb ): supported_extension_aliases = ( NeutronPlugin.NvpPluginV2.supported_extension_aliases + [ "service-router", "routed-service-insertion", "fwaas", "lbaas" ]) def __init__(self): super(NvpAdvancedPlugin, self).__init__() self._super_create_ext_gw_port = ( self._port_drivers['create'][l3_db.DEVICE_OWNER_ROUTER_GW]) self._super_delete_ext_gw_port = ( self._port_drivers['delete'][l3_db.DEVICE_OWNER_ROUTER_GW]) self._port_drivers['create'][l3_db.DEVICE_OWNER_ROUTER_GW] = ( self._vcns_create_ext_gw_port) self._port_drivers['delete'][l3_db.DEVICE_OWNER_ROUTER_GW] = ( self._vcns_delete_ext_gw_port) # cache router type based on router id self._router_type = {} self.callbacks = VcnsCallbacks(self) # load the vCNS driver self._load_vcns_drivers() # switchlib's create_lswitch needs to be replaced in order to proxy # logical switch create requests to vcns self._set_create_lswitch_proxy() def _set_create_lswitch_proxy(self): NeutronPlugin.switchlib.create_lswitch = self._proxy_create_lswitch def _proxy_create_lswitch(self, *args, **kwargs): name, tz_config, tags = ( _process_base_create_lswitch_args(*args, **kwargs) ) return self.vcns_driver.create_lswitch( name, tz_config, tags=tags, port_isolation=None, replication_mode=None) def _load_vcns_drivers(self): self.vcns_driver = vcns_driver.VcnsDriver(self.callbacks) def _set_router_type(self, router_id, router_type): self._router_type[router_id] = router_type def _get_router_type(self, context=None, router_id=None, router=None): if not router: if router_id in self._router_type: return self._router_type[router_id] router = self._get_router(context, router_id) LOG.debug(_("EDGE: router = %s"), router) if router['nsx_attributes']['service_router']: router_type = ROUTER_TYPE_ADVANCED else: router_type = ROUTER_TYPE_BASIC self._set_router_type(router['id'], router_type) return router_type def _find_router_type(self, router): is_service_router = router.get(sr.SERVICE_ROUTER, False) if is_service_router: return ROUTER_TYPE_ADVANCED else: return ROUTER_TYPE_BASIC def _is_advanced_service_router(self, context=None, router_id=None, router=None): if router: router_type = self._get_router_type(router=router) else: router_type = self._get_router_type(context, router_id) return (router_type == ROUTER_TYPE_ADVANCED) def _vcns_create_ext_gw_port(self, context, port_data): router_id = port_data['device_id'] if not self._is_advanced_service_router(context, router_id): self._super_create_ext_gw_port(context, port_data) return # NOP for Edge because currently the port will be create internally # by VSM LOG.debug(_("EDGE: _vcns_create_ext_gw_port")) def _vcns_delete_ext_gw_port(self, context, port_data): router_id = port_data['device_id'] if not self._is_advanced_service_router(context, router_id): self._super_delete_ext_gw_port(context, port_data) return # NOP for Edge LOG.debug(_("EDGE: _vcns_delete_ext_gw_port")) def _get_external_attachment_info(self, context, router): gw_port = router.gw_port ipaddress = None netmask = None nexthop = None if gw_port: # gw_port may have multiple IPs, only configure the first one if gw_port.get('fixed_ips'): ipaddress = gw_port['fixed_ips'][0]['ip_address'] network_id = gw_port.get('network_id') if network_id: ext_net = self._get_network(context, network_id) if not ext_net.external: msg = (_("Network '%s' is not a valid external " "network") % network_id) raise q_exc.BadRequest(resource='router', msg=msg) if ext_net.subnets: ext_subnet = ext_net.subnets[0] netmask = str(netaddr.IPNetwork(ext_subnet.cidr).netmask) nexthop = ext_subnet.gateway_ip return (ipaddress, netmask, nexthop) def _get_external_gateway_address(self, context, router): ipaddress, netmask, nexthop = self._get_external_attachment_info( context, router) return nexthop def _vcns_update_static_routes(self, context, **kwargs): router = kwargs.get('router') if router is None: router = self._get_router(context, kwargs['router_id']) edge_id = kwargs.get('edge_id') if edge_id is None: binding = vcns_db.get_vcns_router_binding(context.session, router['id']) edge_id = binding['edge_id'] skippable = True if 'nexthop' in kwargs: nexthop = kwargs['nexthop'] # The default gateway and vnic config has dependencies, if we # explicitly specify nexthop to change, tell the driver not to # skip this route update skippable = False else: nexthop = self._get_external_gateway_address(context, router) if 'subnets' in kwargs: subnets = kwargs['subnets'] else: subnets = self._find_router_subnets_cidrs(context.elevated(), router['id']) routes = [] for subnet in subnets: routes.append({ 'cidr': subnet, 'nexthop': vcns_const.INTEGRATION_LR_IPADDRESS.split('/')[0] }) self.vcns_driver.update_routes(router['id'], edge_id, nexthop, routes, skippable) def _get_nat_rules(self, context, router): fip_qry = context.session.query(l3_db.FloatingIP) fip_db = fip_qry.filter_by(router_id=router['id']).all() dnat = [] snat = [] for fip in fip_db: if fip.fixed_port_id: dnat.append({ 'dst': fip.floating_ip_address, 'translated': fip.fixed_ip_address }) gw_port = router.gw_port if gw_port and router.enable_snat: if gw_port.get('fixed_ips'): snat_ip = gw_port['fixed_ips'][0]['ip_address'] subnets = self._find_router_subnets_cidrs(context.elevated(), router['id']) for subnet in subnets: snat.append({ 'src': subnet, 'translated': snat_ip }) return (snat, dnat) def _update_nat_rules(self, context, router): snat, dnat = self._get_nat_rules(context, router) binding = vcns_db.get_vcns_router_binding(context.session, router['id']) self.vcns_driver.update_nat_rules(router['id'], binding['edge_id'], snat, dnat) def _update_interface(self, context, router, sync=False): addr, mask, nexthop = self._get_external_attachment_info( context, router) secondary = [] fip_qry = context.session.query(l3_db.FloatingIP) fip_db = fip_qry.filter_by(router_id=router['id']).all() for fip in fip_db: if fip.fixed_port_id: secondary.append(fip.floating_ip_address) #Add all vip addresses bound on the router vip_addrs = self._get_all_vip_addrs_by_router_id(context, router['id']) secondary.extend(vip_addrs) binding = vcns_db.get_vcns_router_binding(context.session, router['id']) task = self.vcns_driver.update_interface( router['id'], binding['edge_id'], vcns_const.EXTERNAL_VNIC_INDEX, self.vcns_driver.external_network, addr, mask, secondary=secondary) if sync: task.wait(TaskState.RESULT) def _update_router_gw_info(self, context, router_id, info): if not self._is_advanced_service_router(context, router_id): super(NvpAdvancedPlugin, self)._update_router_gw_info( context, router_id, info) return # get original gw_port config router = self._get_router(context, router_id) org_ext_net_id = router.gw_port_id and router.gw_port.network_id org_enable_snat = router.enable_snat orgaddr, orgmask, orgnexthop = self._get_external_attachment_info( context, router) super(NeutronPlugin.NvpPluginV2, self)._update_router_gw_info( context, router_id, info, router=router) new_ext_net_id = router.gw_port_id and router.gw_port.network_id new_enable_snat = router.enable_snat newaddr, newmask, newnexthop = self._get_external_attachment_info( context, router) binding = vcns_db.get_vcns_router_binding(context.session, router_id) if new_ext_net_id != org_ext_net_id and orgnexthop: # network changed, need to remove default gateway before vnic # can be configured LOG.debug(_("VCNS: delete default gateway %s"), orgnexthop) self._vcns_update_static_routes(context, router=router, edge_id=binding['edge_id'], nexthop=None) if orgaddr != newaddr or orgmask != newmask: self.vcns_driver.update_interface( router_id, binding['edge_id'], vcns_const.EXTERNAL_VNIC_INDEX, self.vcns_driver.external_network, newaddr, newmask) if orgnexthop != newnexthop: self._vcns_update_static_routes(context, router=router, edge_id=binding['edge_id'], nexthop=newnexthop) if (new_ext_net_id == org_ext_net_id and org_enable_snat == new_enable_snat): return self._update_nat_rules(context, router) def _add_subnet_snat_rule(self, context, router, subnet): # NOP for service router if not self._is_advanced_service_router(router=router): super(NvpAdvancedPlugin, self)._add_subnet_snat_rule( context, router, subnet) def _delete_subnet_snat_rule(self, context, router, subnet): # NOP for service router if not self._is_advanced_service_router(router=router): super(NvpAdvancedPlugin, self)._delete_subnet_snat_rule( context, router, subnet) def _remove_floatingip_address(self, context, fip_db): # NOP for service router router_id = fip_db.router_id if not self._is_advanced_service_router(context, router_id): super(NvpAdvancedPlugin, self)._remove_floatingip_address( context, fip_db) def _create_advanced_service_router(self, context, neutron_router_id, name, lrouter, lswitch): # store binding binding = vcns_db.add_vcns_router_binding( context.session, neutron_router_id, None, lswitch['uuid'], service_constants.PENDING_CREATE) # deploy edge jobdata = { 'neutron_router_id': neutron_router_id, 'lrouter': lrouter, 'lswitch': lswitch, 'context': context } # deploy and wait until the deploy requeste has been requested # so we will have edge_id ready. The wait here should be fine # as we're not in a database transaction now self.vcns_driver.deploy_edge( lrouter['uuid'], name, lswitch['uuid'], jobdata=jobdata, wait_for_exec=True) return binding def _create_integration_lswitch(self, tenant_id, name): # use defautl transport zone transport_zone_config = [{ "zone_uuid": self.cluster.default_tz_uuid, "transport_type": cfg.CONF.NSX.default_transport_type }] return self.vcns_driver.create_lswitch(name, transport_zone_config) def _add_router_integration_interface(self, tenant_id, name, lrouter, lswitch): # create logic switch port try: ls_port = switchlib.create_lport( self.cluster, lswitch['uuid'], tenant_id, '', '', lrouter['uuid'], True) except NvpApiClient.NvpApiException: msg = (_("An exception occurred while creating a port " "on lswitch %s") % lswitch['uuid']) LOG.exception(msg) raise q_exc.NeutronException(message=msg) # create logic router port try: neutron_port_id = '' pname = name[:36] + '-lp' admin_status_enabled = True lr_port = routerlib.create_router_lport( self.cluster, lrouter['uuid'], tenant_id, neutron_port_id, pname, admin_status_enabled, [vcns_const.INTEGRATION_LR_IPADDRESS]) except NvpApiClient.NvpApiException: msg = (_("Unable to create port on NVP logical router %s") % name) LOG.exception(msg) switchlib.delete_port( self.cluster, lswitch['uuid'], ls_port['uuid']) raise q_exc.NeutronException(message=msg) # attach logic router port to switch port try: self._update_router_port_attachment( self.cluster, None, lrouter['uuid'], {}, lr_port['uuid'], 'PatchAttachment', ls_port['uuid'], None) except NvpApiClient.NvpApiException as e: # lr_port should have been deleted switchlib.delete_port( self.cluster, lswitch['uuid'], ls_port['uuid']) raise e def _create_lrouter(self, context, router, nexthop): lrouter = super(NvpAdvancedPlugin, self)._create_lrouter( context, router, vcns_const.INTEGRATION_EDGE_IPADDRESS) router_type = self._find_router_type(router) self._set_router_type(lrouter['uuid'], router_type) if router_type == ROUTER_TYPE_BASIC: return lrouter tenant_id = self._get_tenant_id_for_create(context, router) name = router['name'] try: lsname = name[:36] + '-ls' lswitch = self._create_integration_lswitch( tenant_id, lsname) except Exception: msg = _("Unable to create integration logic switch " "for router %s") % name LOG.exception(msg) routerlib.delete_lrouter(self.cluster, lrouter['uuid']) raise q_exc.NeutronException(message=msg) try: self._add_router_integration_interface(tenant_id, name, lrouter, lswitch) except Exception: msg = _("Unable to add router interface to integration lswitch " "for router %s") % name LOG.exception(msg) routerlib.delete_lrouter(self.cluster, lrouter['uuid']) raise q_exc.NeutronException(message=msg) try: self._create_advanced_service_router( context, router['id'], name, lrouter, lswitch) except Exception: msg = (_("Unable to create advance service router for %s") % name) LOG.exception(msg) self.vcns_driver.delete_lswitch(lswitch('uuid')) routerlib.delete_lrouter(self.cluster, lrouter['uuid']) raise q_exc.NeutronException(message=msg) lrouter['status'] = service_constants.PENDING_CREATE return lrouter def _delete_lrouter(self, context, router_id, nsx_router_id): binding = vcns_db.get_vcns_router_binding(context.session, router_id) if not binding: super(NvpAdvancedPlugin, self)._delete_lrouter( context, router_id, nsx_router_id) else: vcns_db.update_vcns_router_binding( context.session, router_id, status=service_constants.PENDING_DELETE) lswitch_id = binding['lswitch_id'] edge_id = binding['edge_id'] # delete lswitch try: self.vcns_driver.delete_lswitch(lswitch_id) except exceptions.ResourceNotFound: LOG.warning(_("Did not found lswitch %s in NVP"), lswitch_id) # delete edge jobdata = { 'context': context } self.vcns_driver.delete_edge(router_id, edge_id, jobdata=jobdata) # delete NSX logical router routerlib.delete_lrouter(self.cluster, nsx_router_id) if id in self._router_type: del self._router_type[router_id] def _update_lrouter(self, context, router_id, name, nexthop, routes=None): if not self._is_advanced_service_router(context, router_id): return super(NvpAdvancedPlugin, self)._update_lrouter( context, router_id, name, nexthop, routes=routes) previous_routes = super(NvpAdvancedPlugin, self)._update_lrouter( context, router_id, name, vcns_const.INTEGRATION_EDGE_IPADDRESS, routes=routes) # TODO(fank): Theoretically users can specify extra routes for # physical network, and routes for phyiscal network needs to be # configured on Edge. This can be done by checking if nexthop is in # external network. But for now we only handle routes for logic # space and leave it for future enhancement. # Let _update_router_gw_info handle nexthop change #self._vcns_update_static_routes(context, router_id=router_id) return previous_routes def _retrieve_and_delete_nat_rules(self, context, floating_ip_address, internal_ip, router_id, min_num_rules_expected=0): # NOP for advanced service router if not self._is_advanced_service_router(context, router_id): super(NvpAdvancedPlugin, self)._retrieve_and_delete_nat_rules( context, floating_ip_address, internal_ip, router_id, min_num_rules_expected=min_num_rules_expected) def _update_fip_assoc(self, context, fip, floatingip_db, external_port): # Update DB model only for advanced service router router_id = self._get_fip_assoc_data(context, fip, floatingip_db)[2] if (router_id and not self._is_advanced_service_router(context, router_id)): super(NvpAdvancedPlugin, self)._update_fip_assoc( context, fip, floatingip_db, external_port) else: super(NeutronPlugin.NvpPluginV2, self)._update_fip_assoc( context, fip, floatingip_db, external_port) def _get_nvp_lrouter_status(self, id): try: lrouter = routerlib.get_lrouter(self.cluster, id) lr_status = lrouter["_relations"]["LogicalRouterStatus"] if lr_status["fabric_status"]: nvp_status = RouterStatus.ROUTER_STATUS_ACTIVE else: nvp_status = RouterStatus.ROUTER_STATUS_DOWN except q_exc.NotFound: nvp_status = RouterStatus.ROUTER_STATUS_ERROR return nvp_status def _get_vse_status(self, context, id): binding = vcns_db.get_vcns_router_binding(context.session, id) edge_status_level = self.vcns_driver.get_edge_status( binding['edge_id']) edge_db_status_level = ROUTER_STATUS_LEVEL[binding.status] if edge_status_level > edge_db_status_level: return edge_status_level else: return edge_db_status_level def _get_all_nvp_lrouters_statuses(self, tenant_id, fields): # get nvp lrouters status nvp_lrouters = routerlib.get_lrouters(self.cluster, tenant_id, fields) nvp_status = {} for nvp_lrouter in nvp_lrouters: if (nvp_lrouter["_relations"]["LogicalRouterStatus"] ["fabric_status"]): nvp_status[nvp_lrouter['uuid']] = ( RouterStatus.ROUTER_STATUS_ACTIVE ) else: nvp_status[nvp_lrouter['uuid']] = ( RouterStatus.ROUTER_STATUS_DOWN ) return nvp_status def _get_all_vse_statuses(self, context): bindings = self._model_query( context, vcns_models.VcnsRouterBinding) vse_db_status_level = {} edge_id_to_router_id = {} router_ids = [] for binding in bindings: if not binding['edge_id']: continue router_id = binding['router_id'] router_ids.append(router_id) edge_id_to_router_id[binding['edge_id']] = router_id vse_db_status_level[router_id] = ( ROUTER_STATUS_LEVEL[binding['status']]) if not vse_db_status_level: # no advanced service router, no need to query return {} vse_status_level = {} edges_status_level = self.vcns_driver.get_edges_statuses() for edge_id, status_level in edges_status_level.iteritems(): if edge_id in edge_id_to_router_id: router_id = edge_id_to_router_id[edge_id] db_status_level = vse_db_status_level[router_id] if status_level > db_status_level: vse_status_level[router_id] = status_level else: vse_status_level[router_id] = db_status_level return vse_status_level def get_router(self, context, id, fields=None): if fields and 'status' not in fields: return super(NvpAdvancedPlugin, self).get_router( context, id, fields=fields) router = super(NvpAdvancedPlugin, self).get_router(context, id) router_type = self._find_router_type(router) if router_type == ROUTER_TYPE_ADVANCED: vse_status_level = self._get_vse_status(context, id) if vse_status_level > ROUTER_STATUS_LEVEL[router['status']]: router['status'] = ROUTER_STATUS[vse_status_level] return self._fields(router, fields) def get_routers(self, context, filters=None, fields=None, **kwargs): routers = super(NvpAdvancedPlugin, self).get_routers( context, filters=filters, **kwargs) if fields and 'status' not in fields: # no status checking, just return regular get_routers return [self._fields(router, fields) for router in routers] for router in routers: router_type = self._find_router_type(router) if router_type == ROUTER_TYPE_ADVANCED: break else: # no advanced service router, return here return [self._fields(router, fields) for router in routers] vse_status_all = self._get_all_vse_statuses(context) for router in routers: router_type = self._find_router_type(router) if router_type == ROUTER_TYPE_ADVANCED: vse_status_level = vse_status_all.get(router['id']) if vse_status_level is None: vse_status_level = RouterStatus.ROUTER_STATUS_ERROR if vse_status_level > ROUTER_STATUS_LEVEL[router['status']]: router['status'] = ROUTER_STATUS[vse_status_level] return [self._fields(router, fields) for router in routers] def add_router_interface(self, context, router_id, interface_info): info = super(NvpAdvancedPlugin, self).add_router_interface( context, router_id, interface_info) if self._is_advanced_service_router(context, router_id): router = self._get_router(context, router_id) if router.enable_snat: self._update_nat_rules(context, router) # TODO(fank): do rollback on error, or have a dedicated thread # do sync work (rollback, re-configure, or make router down) self._vcns_update_static_routes(context, router=router) return info def remove_router_interface(self, context, router_id, interface_info): info = super(NvpAdvancedPlugin, self).remove_router_interface( context, router_id, interface_info) if self._is_advanced_service_router(context, router_id): router = self._get_router(context, router_id) if router.enable_snat: self._update_nat_rules(context, router) # TODO(fank): do rollback on error, or have a dedicated thread # do sync work (rollback, re-configure, or make router down) self._vcns_update_static_routes(context, router=router) return info def create_floatingip(self, context, floatingip): fip = super(NvpAdvancedPlugin, self).create_floatingip( context, floatingip) router_id = fip.get('router_id') if router_id and self._is_advanced_service_router(context, router_id): router = self._get_router(context, router_id) # TODO(fank): do rollback on error, or have a dedicated thread # do sync work (rollback, re-configure, or make router down) self._update_nat_rules(context, router) self._update_interface(context, router) return fip def update_floatingip(self, context, id, floatingip): fip = super(NvpAdvancedPlugin, self).update_floatingip( context, id, floatingip) router_id = fip.get('router_id') if router_id and self._is_advanced_service_router(context, router_id): router = self._get_router(context, router_id) # TODO(fank): do rollback on error, or have a dedicated thread # do sync work (rollback, re-configure, or make router down) self._update_nat_rules(context, router) self._update_interface(context, router) return fip def delete_floatingip(self, context, id): fip_db = self._get_floatingip(context, id) router_id = None if fip_db.fixed_port_id: router_id = fip_db.router_id super(NvpAdvancedPlugin, self).delete_floatingip(context, id) if router_id and self._is_advanced_service_router(context, router_id): router = self._get_router(context, router_id) # TODO(fank): do rollback on error, or have a dedicated thread # do sync work (rollback, re-configure, or make router down) self._update_interface(context, router) self._update_nat_rules(context, router) def disassociate_floatingips(self, context, port_id): try: fip_qry = context.session.query(l3_db.FloatingIP) fip_db = fip_qry.filter_by(fixed_port_id=port_id).one() router_id = fip_db.router_id except sa_exc.NoResultFound: router_id = None super(NvpAdvancedPlugin, self).disassociate_floatingips(context, port_id) if router_id and self._is_advanced_service_router(context, router_id): router = self._get_router(context, router_id) # TODO(fank): do rollback on error, or have a dedicated thread # do sync work (rollback, re-configure, or make router down) self._update_interface(context, router) self._update_nat_rules(context, router) # # FWaaS plugin implementation # def _firewall_set_status( self, context, firewall_id, status, firewall=None): with context.session.begin(subtransactions=True): fw_db = self._get_firewall(context, firewall_id) if status == service_constants.PENDING_UPDATE and ( fw_db.status == service_constants.PENDING_DELETE): raise fw_ext.FirewallInPendingState( firewall_id=firewall_id, pending_state=status) else: fw_db.status = status if firewall: firewall['status'] = status def _ensure_firewall_update_allowed(self, context, firewall_id): fwall = self.get_firewall(context, firewall_id) if fwall['status'] in [service_constants.PENDING_CREATE, service_constants.PENDING_UPDATE, service_constants.PENDING_DELETE]: raise fw_ext.FirewallInPendingState(firewall_id=firewall_id, pending_state=fwall['status']) def _ensure_firewall_policy_update_allowed( self, context, firewall_policy_id): firewall_policy = self.get_firewall_policy(context, firewall_policy_id) for firewall_id in firewall_policy.get('firewall_list', []): self._ensure_firewall_update_allowed(context, firewall_id) def _ensure_update_or_delete_firewall_rule( self, context, firewall_rule_id): fw_rule = self.get_firewall_rule(context, firewall_rule_id) if fw_rule.get('firewall_policy_id'): self._ensure_firewall_policy_update_allowed( context, fw_rule['firewall_policy_id']) def _make_firewall_rule_list_by_policy_id(self, context, fw_policy_id): if not fw_policy_id: return [] firewall_policy_db = self._get_firewall_policy(context, fw_policy_id) return [ self._make_firewall_rule_dict(fw_rule_db) for fw_rule_db in firewall_policy_db['firewall_rules'] ] def _get_edge_id_by_vcns_edge_binding(self, context, router_id): #Get vcns_router_binding mapping between router and edge router_binding = vcns_db.get_vcns_router_binding( context.session, router_id) return router_binding.edge_id def _get_firewall_list_from_firewall_policy(self, context, policy_id): firewall_policy_db = self._get_firewall_policy(context, policy_id) return [ self._make_firewall_dict(fw_db) for fw_db in firewall_policy_db['firewalls'] ] def _get_firewall_list_from_firewall_rule(self, context, rule_id): rule = self._get_firewall_rule(context, rule_id) if not rule.firewall_policy_id: # The firewall rule is not associated with firewall policy yet return None return self._get_firewall_list_from_firewall_policy( context, rule.firewall_policy_id) def _vcns_update_firewall(self, context, fw, router_id=None, **kwargs): edge_id = kwargs.get('edge_id') if not edge_id: edge_id = self._get_edge_id_by_vcns_edge_binding( context, router_id) firewall_rule_list = kwargs.get('firewall_rule_list') if not firewall_rule_list: firewall_rule_list = self._make_firewall_rule_list_by_policy_id( context, fw['firewall_policy_id']) fw_with_rules = fw fw_with_rules['firewall_rule_list'] = firewall_rule_list try: self.vcns_driver.update_firewall(context, edge_id, fw_with_rules) except exceptions.VcnsApiException as e: self._firewall_set_status( context, fw['id'], service_constants.ERROR) msg = (_("Failed to create firewall on vShield Edge " "bound on router %s") % router_id) LOG.exception(msg) raise e except exceptions.BadRequest as e: self._firewall_set_status( context, fw['id'], service_constants.ERROR) LOG.exception(_("Bad Firewall request Input")) raise e def _vcns_delete_firewall(self, context, router_id=None, **kwargs): edge_id = kwargs.get('edge_id') if not edge_id: edge_id = self._get_edge_id_by_vcns_edge_binding( context, router_id) #TODO(linb):do rollback on error self.vcns_driver.delete_firewall(context, edge_id) def create_firewall(self, context, firewall): LOG.debug(_("create_firewall() called")) router_id = firewall['firewall'].get(vcns_const.ROUTER_ID) if not router_id: msg = _("router_id is not provided!") LOG.error(msg) raise q_exc.BadRequest(resource='router', msg=msg) if not self._is_advanced_service_router(context, router_id): msg = _("router_id:%s is not an advanced router!") % router_id LOG.error(msg) raise q_exc.BadRequest(resource='router', msg=msg) if self._get_resource_router_id_binding( context, firewall_db.Firewall, router_id=router_id): msg = _("A firewall is already associated with the router") LOG.error(msg) raise nvp_exc.NvpServiceOverQuota( overs='firewall', err_msg=msg) fw = super(NvpAdvancedPlugin, self).create_firewall(context, firewall) #Add router service insertion binding with firewall object res = { 'id': fw['id'], 'router_id': router_id } self._process_create_resource_router_id( context, res, firewall_db.Firewall) #Since there is only one firewall per edge, #here would be bulk configureation operation on firewall self._vcns_update_firewall(context, fw, router_id) self._firewall_set_status( context, fw['id'], service_constants.ACTIVE, fw) fw[rsi.ROUTER_ID] = router_id return fw def update_firewall(self, context, id, firewall): LOG.debug(_("update_firewall() called")) self._ensure_firewall_update_allowed(context, id) service_router_binding = self._get_resource_router_id_binding( context, firewall_db.Firewall, resource_id=id) rule_list_pre = self._make_firewall_rule_list_by_policy_id( context, self.get_firewall(context, id)['firewall_policy_id']) firewall['firewall']['status'] = service_constants.PENDING_UPDATE fw = super(NvpAdvancedPlugin, self).update_firewall( context, id, firewall) fw[rsi.ROUTER_ID] = service_router_binding['router_id'] rule_list_new = self._make_firewall_rule_list_by_policy_id( context, fw['firewall_policy_id']) if rule_list_pre == rule_list_new: self._firewall_set_status( context, fw['id'], service_constants.ACTIVE, fw) return fw else: self._vcns_update_firewall( context, fw, service_router_binding.router_id, firewall_rule_list=rule_list_new) self._firewall_set_status( context, fw['id'], service_constants.ACTIVE, fw) return fw def delete_firewall(self, context, id): LOG.debug(_("delete_firewall() called")) self._firewall_set_status( context, id, service_constants.PENDING_DELETE) service_router_binding = self._get_resource_router_id_binding( context, firewall_db.Firewall, resource_id=id) self._vcns_delete_firewall(context, service_router_binding.router_id) super(NvpAdvancedPlugin, self).delete_firewall(context, id) self._delete_resource_router_id_binding( context, id, firewall_db.Firewall) def get_firewall(self, context, id, fields=None): fw = super(NvpAdvancedPlugin, self).get_firewall( context, id, fields) if fields and rsi.ROUTER_ID not in fields: return fw service_router_binding = self._get_resource_router_id_binding( context, firewall_db.Firewall, resource_id=fw['id']) fw[rsi.ROUTER_ID] = service_router_binding['router_id'] return fw def get_firewalls(self, context, filters=None, fields=None): fws = super(NvpAdvancedPlugin, self).get_firewalls( context, filters, fields) if fields and rsi.ROUTER_ID not in fields: return fws service_router_bindings = self._get_resource_router_id_bindings( context, firewall_db.Firewall, resource_ids=[fw['id'] for fw in fws]) mapping = dict([(binding['resource_id'], binding['router_id']) for binding in service_router_bindings]) for fw in fws: fw[rsi.ROUTER_ID] = mapping[fw['id']] return fws def update_firewall_rule(self, context, id, firewall_rule): LOG.debug(_("update_firewall_rule() called")) self._ensure_update_or_delete_firewall_rule(context, id) fwr_pre = self.get_firewall_rule(context, id) fwr = super(NvpAdvancedPlugin, self).update_firewall_rule( context, id, firewall_rule) if fwr_pre == fwr: return fwr # check if this rule is associated with firewall fw_list = self._get_firewall_list_from_firewall_rule(context, id) if not fw_list: return fwr for fw in fw_list: # get router service insertion binding with firewall id service_router_binding = self._get_resource_router_id_binding( context, firewall_db.Firewall, resource_id=fw['id']) edge_id = self._get_edge_id_by_vcns_edge_binding( context, service_router_binding.router_id) #TODO(linb): do rollback on error self.vcns_driver.update_firewall_rule(context, id, edge_id, fwr) return fwr def update_firewall_policy(self, context, id, firewall_policy): LOG.debug(_("update_firewall_policy() called")) self._ensure_firewall_policy_update_allowed(context, id) firewall_rules_pre = self._make_firewall_rule_list_by_policy_id( context, id) fwp = super(NvpAdvancedPlugin, self).update_firewall_policy( context, id, firewall_policy) firewall_rules = self._make_firewall_rule_list_by_policy_id( context, id) if firewall_rules_pre == firewall_rules: return fwp # check if this policy is associated with firewall fw_list = self._get_firewall_list_from_firewall_policy(context, id) if not fw_list: return fwp for fw in fw_list: # Get the router_service insertion binding with firewall id # TODO(fank): optimized by using _get_resource_router_id_bindings service_router_binding = self._get_resource_router_id_binding( context, firewall_db.Firewall, resource_id=fw['id']) self._vcns_update_firewall( context, fw, service_router_binding.router_id, firewall_rule_list=firewall_rules) return fwp def insert_rule(self, context, id, rule_info): LOG.debug(_("insert_rule() called")) self._ensure_firewall_policy_update_allowed(context, id) fwp = super(NvpAdvancedPlugin, self).insert_rule( context, id, rule_info) fwr = super(NvpAdvancedPlugin, self).get_firewall_rule( context, rule_info['firewall_rule_id']) # check if this policy is associated with firewall fw_list = self._get_firewall_list_from_firewall_policy(context, id) if not fw_list: return fwp for fw in fw_list: # TODO(fank): optimized by using _get_resource_router_id_bindings service_router_binding = self._get_resource_router_id_binding( context, firewall_db.Firewall, resource_id=fw['id']) edge_id = self._get_edge_id_by_vcns_edge_binding( context, service_router_binding.router_id) if rule_info.get('insert_before') or rule_info.get('insert_after'): #if insert_before or insert_after is set, we would call #VCNS insert_rule API #TODO(linb): do rollback on error self.vcns_driver.insert_rule(context, rule_info, edge_id, fwr) else: #Else we would call bulk configuration on the firewall self._vcns_update_firewall(context, fw, edge_id=edge_id) return fwp def remove_rule(self, context, id, rule_info): LOG.debug(_("remove_rule() called")) self._ensure_firewall_policy_update_allowed(context, id) fwp = super(NvpAdvancedPlugin, self).remove_rule( context, id, rule_info) fwr = super(NvpAdvancedPlugin, self).get_firewall_rule( context, rule_info['firewall_rule_id']) # check if this policy is associated with firewall fw_list = self._get_firewall_list_from_firewall_policy(context, id) if not fw_list: return fwp for fw in fw_list: # TODO(fank): optimized by using _get_resource_router_id_bindings service_router_binding = self._get_resource_router_id_binding( context, firewall_db.Firewall, resource_id=fw['id']) edge_id = self._get_edge_id_by_vcns_edge_binding( context, service_router_binding.router_id) #TODO(linb): do rollback on error self.vcns_driver.delete_firewall_rule( context, fwr['id'], edge_id) return fwp # # LBAAS service plugin implementation # def _get_edge_id_by_vip_id(self, context, vip_id): try: service_router_binding = self._get_resource_router_id_binding( context, loadbalancer_db.Vip, resource_id=vip_id) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_("Failed to find the edge with " "vip_id: %s"), vip_id) return self._get_edge_id_by_vcns_edge_binding( context, service_router_binding.router_id) def _get_all_vip_addrs_by_router_id( self, context, router_id): vip_bindings = self._get_resource_router_id_bindings( context, loadbalancer_db.Vip, router_ids=[router_id]) vip_addrs = [] for vip_binding in vip_bindings: vip = self.get_vip(context, vip_binding.resource_id) vip_addrs.append(vip.get('address')) return vip_addrs def _add_router_service_insertion_binding(self, context, resource_id, router_id, model): res = { 'id': resource_id, 'router_id': router_id } self._process_create_resource_router_id(context, res, model) def _resource_set_status(self, context, model, id, status, obj=None, pool_id=None): with context.session.begin(subtransactions=True): try: qry = context.session.query(model) if issubclass(model, loadbalancer_db.PoolMonitorAssociation): res = qry.filter_by(monitor_id=id, pool_id=pool_id).one() else: res = qry.filter_by(id=id).one() if status == service_constants.PENDING_UPDATE and ( res.get('status') == service_constants.PENDING_DELETE): msg = (_("Operation can't be performed, Since resource " "%(model)s : %(id)s is in DELETEing status!") % {'model': model, 'id': id}) LOG.error(msg) raise nvp_exc.NvpServicePluginException(err_msg=msg) else: res.status = status except sa_exc.NoResultFound: msg = (_("Resource %(model)s : %(id)s not found!") % {'model': model, 'id': id}) LOG.exception(msg) raise nvp_exc.NvpServicePluginException(err_msg=msg) if obj: obj['status'] = status def _vcns_create_pool_and_monitors(self, context, pool_id, **kwargs): pool = self.get_pool(context, pool_id) edge_id = kwargs.get('edge_id') if not edge_id: edge_id = self._get_edge_id_by_vip_id( context, pool['vip_id']) #Check wheter the pool is already created on the router #in case of future's M:N relation between Pool and Vip #Check associated HealthMonitors and then create them for monitor_id in pool.get('health_monitors'): hm = self.get_health_monitor(context, monitor_id) try: self.vcns_driver.create_health_monitor( context, edge_id, hm) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_("Failed to create healthmonitor " "associated with pool id: %s!") % pool_id) for monitor_ide in pool.get('health_monitors'): if monitor_ide == monitor_id: break self.vcns_driver.delete_health_monitor( context, monitor_ide, edge_id) #Create the pool on the edge members = [ super(NvpAdvancedPlugin, self).get_member( context, member_id) for member_id in pool.get('members') ] try: self.vcns_driver.create_pool(context, edge_id, pool, members) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_("Failed to create pool on vshield edge")) self.vcns_driver.delete_pool( context, pool_id, edge_id) for monitor_id in pool.get('health_monitors'): self.vcns_driver.delete_health_monitor( context, monitor_id, edge_id) def _vcns_update_pool(self, context, pool, **kwargs): edge_id = self._get_edge_id_by_vip_id(context, pool['vip_id']) members = kwargs.get('members') if not members: members = [ super(NvpAdvancedPlugin, self).get_member( context, member_id) for member_id in pool.get('members') ] self.vcns_driver.update_pool(context, edge_id, pool, members) def create_vip(self, context, vip): LOG.debug(_("create_vip() called")) router_id = vip['vip'].get(vcns_const.ROUTER_ID) if not router_id: msg = _("router_id is not provided!") LOG.error(msg) raise q_exc.BadRequest(resource='router', msg=msg) if not self._is_advanced_service_router(context, router_id): msg = _("router_id: %s is not an advanced router!") % router_id LOG.error(msg) raise nvp_exc.NvpServicePluginException(err_msg=msg) #Check whether the vip port is an external port subnet_id = vip['vip']['subnet_id'] network_id = self.get_subnet(context, subnet_id)['network_id'] ext_net = self._get_network(context, network_id) if not ext_net.external: msg = (_("Network '%s' is not a valid external " "network") % network_id) raise nvp_exc.NvpServicePluginException(err_msg=msg) v = super(NvpAdvancedPlugin, self).create_vip(context, vip) #Get edge_id for the resource router_binding = vcns_db.get_vcns_router_binding( context.session, router_id) edge_id = router_binding.edge_id #Add vip_router binding self._add_router_service_insertion_binding(context, v['id'], router_id, loadbalancer_db.Vip) #Create the vip port on vShield Edge router = self._get_router(context, router_id) self._update_interface(context, router, sync=True) #Create the vip and associated pool/monitor on the corresponding edge try: self._vcns_create_pool_and_monitors( context, v['pool_id'], edge_id=edge_id) self.vcns_driver.create_vip(context, edge_id, v) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_("Failed to create vip!")) self._delete_resource_router_id_binding( context, v['id'], loadbalancer_db.Vip) super(NvpAdvancedPlugin, self).delete_vip(context, v['id']) self._resource_set_status(context, loadbalancer_db.Vip, v['id'], service_constants.ACTIVE, v) v[rsi.ROUTER_ID] = router_id return v def update_vip(self, context, id, vip): edge_id = self._get_edge_id_by_vip_id(context, id) old_vip = self.get_vip(context, id) vip['vip']['status'] = service_constants.PENDING_UPDATE v = super(NvpAdvancedPlugin, self).update_vip(context, id, vip) v[rsi.ROUTER_ID] = self._get_resource_router_id_binding( context, loadbalancer_db.Vip, resource_id=id)['router_id'] if old_vip['pool_id'] != v['pool_id']: self.vcns_driver.delete_vip(context, id) #Delete old pool/monitor on the edge #TODO(linb): Factor out procedure for removing pool and health #separate method old_pool = self.get_pool(context, old_vip['pool_id']) self.vcns_driver.delete_pool( context, old_vip['pool_id'], edge_id) for monitor_id in old_pool.get('health_monitors'): self.vcns_driver.delete_health_monitor( context, monitor_id, edge_id) #Create new pool/monitor object on the edge #TODO(linb): add exception handle if error self._vcns_create_pool_and_monitors( context, v['pool_id'], edge_id=edge_id) self.vcns_driver.create_vip(context, edge_id, v) return v try: self.vcns_driver.update_vip(context, v) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_("Failed to update vip with id: %s!"), id) self._resource_set_status(context, loadbalancer_db.Vip, id, service_constants.ERROR, v) self._resource_set_status(context, loadbalancer_db.Vip, v['id'], service_constants.ACTIVE, v) return v def delete_vip(self, context, id): v = self.get_vip(context, id) self._resource_set_status( context, loadbalancer_db.Vip, id, service_constants.PENDING_DELETE) try: self.vcns_driver.delete_vip(context, id) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_("Failed to delete vip with id: %s!"), id) self._resource_set_status(context, loadbalancer_db.Vip, id, service_constants.ERROR) edge_id = self._get_edge_id_by_vip_id(context, id) #Check associated HealthMonitors and then delete them pool = self.get_pool(context, v['pool_id']) self.vcns_driver.delete_pool(context, v['pool_id'], edge_id) for monitor_id in pool.get('health_monitors'): #TODO(linb): do exception handle if error self.vcns_driver.delete_health_monitor( context, monitor_id, edge_id) router_binding = self._get_resource_router_id_binding( context, loadbalancer_db.Vip, resource_id=id) router = self._get_router(context, router_binding.router_id) self._delete_resource_router_id_binding( context, id, loadbalancer_db.Vip) super(NvpAdvancedPlugin, self).delete_vip(context, id) self._update_interface(context, router, sync=True) def get_vip(self, context, id, fields=None): vip = super(NvpAdvancedPlugin, self).get_vip(context, id, fields) if fields and rsi.ROUTER_ID not in fields: return vip service_router_binding = self._get_resource_router_id_binding( context, loadbalancer_db.Vip, resource_id=vip['id']) vip[rsi.ROUTER_ID] = service_router_binding['router_id'] return vip def get_vips(self, context, filters=None, fields=None): vips = super(NvpAdvancedPlugin, self).get_vips( context, filters, fields) if fields and rsi.ROUTER_ID not in fields: return vips service_router_bindings = self._get_resource_router_id_bindings( context, loadbalancer_db.Vip, resource_ids=[vip['id'] for vip in vips]) mapping = dict([(binding['resource_id'], binding['router_id']) for binding in service_router_bindings]) for vip in vips: vip[rsi.ROUTER_ID] = mapping[vip['id']] return vips def update_pool(self, context, id, pool): pool['pool']['status'] = service_constants.PENDING_UPDATE p = super(NvpAdvancedPlugin, self).update_pool(context, id, pool) #Check whether the pool is already associated with the vip if not p.get('vip_id'): self._resource_set_status(context, loadbalancer_db.Pool, p['id'], service_constants.ACTIVE, p) return p try: self._vcns_update_pool(context, p) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_("Failed to update pool with id: %s!"), id) self._resource_set_status(context, loadbalancer_db.Pool, p['id'], service_constants.ERROR, p) self._resource_set_status(context, loadbalancer_db.Pool, p['id'], service_constants.ACTIVE, p) return p def create_member(self, context, member): m = super(NvpAdvancedPlugin, self).create_member(context, member) pool_id = m.get('pool_id') pool = self.get_pool(context, pool_id) if not pool.get('vip_id'): self._resource_set_status(context, loadbalancer_db.Member, m['id'], service_constants.ACTIVE, m) return m self._resource_set_status(context, loadbalancer_db.Pool, pool_id, service_constants.PENDING_UPDATE) try: self._vcns_update_pool(context, pool) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_("Failed to update pool with the member")) super(NvpAdvancedPlugin, self).delete_member(context, m['id']) self._resource_set_status(context, loadbalancer_db.Pool, pool_id, service_constants.ACTIVE) self._resource_set_status(context, loadbalancer_db.Member, m['id'], service_constants.ACTIVE, m) return m def update_member(self, context, id, member): member['member']['status'] = service_constants.PENDING_UPDATE old_member = self.get_member(context, id) m = super(NvpAdvancedPlugin, self).update_member( context, id, member) if m['pool_id'] != old_member['pool_id']: old_pool_id = old_member['pool_id'] old_pool = self.get_pool(context, old_pool_id) if old_pool.get('vip_id'): self._resource_set_status( context, loadbalancer_db.Pool, old_pool_id, service_constants.PENDING_UPDATE) try: self._vcns_update_pool(context, old_pool) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_("Failed to update old pool " "with the member")) super(NvpAdvancedPlugin, self).delete_member( context, m['id']) self._resource_set_status( context, loadbalancer_db.Pool, old_pool_id, service_constants.ACTIVE) pool_id = m['pool_id'] pool = self.get_pool(context, pool_id) if not pool.get('vip_id'): self._resource_set_status(context, loadbalancer_db.Member, m['id'], service_constants.ACTIVE, m) return m self._resource_set_status(context, loadbalancer_db.Pool, pool_id, service_constants.PENDING_UPDATE) try: self._vcns_update_pool(context, pool) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_("Failed to update pool with the member")) super(NvpAdvancedPlugin, self).delete_member( context, m['id']) self._resource_set_status(context, loadbalancer_db.Pool, pool_id, service_constants.ACTIVE) self._resource_set_status(context, loadbalancer_db.Member, m['id'], service_constants.ACTIVE, m) return m def delete_member(self, context, id): m = self.get_member(context, id) super(NvpAdvancedPlugin, self).delete_member(context, id) pool_id = m['pool_id'] pool = self.get_pool(context, pool_id) if not pool.get('vip_id'): return self._resource_set_status(context, loadbalancer_db.Pool, pool_id, service_constants.PENDING_UPDATE) try: self._vcns_update_pool(context, pool) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_("Failed to update pool with the member")) self._resource_set_status(context, loadbalancer_db.Pool, pool_id, service_constants.ACTIVE) def update_health_monitor(self, context, id, health_monitor): old_hm = super(NvpAdvancedPlugin, self).get_health_monitor( context, id) hm = super(NvpAdvancedPlugin, self).update_health_monitor( context, id, health_monitor) for hm_pool in hm.get('pools'): pool_id = hm_pool['pool_id'] pool = self.get_pool(context, pool_id) if pool.get('vip_id'): edge_id = self._get_edge_id_by_vip_id( context, pool['vip_id']) try: self.vcns_driver.update_health_monitor( context, edge_id, old_hm, hm) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_("Failed to update monitor " "with id: %s!"), id) return hm def delete_health_monitor(self, context, id): with context.session.begin(subtransactions=True): qry = context.session.query( loadbalancer_db.PoolMonitorAssociation ).filter_by(monitor_id=id) for assoc in qry: pool_id = assoc['pool_id'] super(NvpAdvancedPlugin, self).delete_pool_health_monitor(context, id, pool_id) pool = self.get_pool(context, pool_id) if not pool.get('vip_id'): continue edge_id = self._get_edge_id_by_vip_id( context, pool['vip_id']) self._resource_set_status( context, loadbalancer_db.Pool, pool_id, service_constants.PENDING_UPDATE) try: self._vcns_update_pool(context, pool) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_("Failed to update pool with monitor!")) self._resource_set_status( context, loadbalancer_db.Pool, pool_id, service_constants.ACTIVE) try: self.vcns_driver.delete_health_monitor( context, id, edge_id) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_("Failed to delete monitor " "with id: %s!"), id) super(NvpAdvancedPlugin, self).delete_health_monitor(context, id) self._delete_resource_router_id_binding( context, id, loadbalancer_db.HealthMonitor) super(NvpAdvancedPlugin, self).delete_health_monitor(context, id) self._delete_resource_router_id_binding( context, id, loadbalancer_db.HealthMonitor) def create_pool_health_monitor(self, context, health_monitor, pool_id): monitor_id = health_monitor['health_monitor']['id'] pool = self.get_pool(context, pool_id) monitors = pool.get('health_monitors') if len(monitors) > 0: msg = _("Vcns right now can only support " "one monitor per pool") LOG.error(msg) raise nvp_exc.NvpServicePluginException(err_msg=msg) #Check whether the pool is already associated with the vip if not pool.get('vip_id'): res = super(NvpAdvancedPlugin, self).create_pool_health_monitor(context, health_monitor, pool_id) return res #Get the edge_id edge_id = self._get_edge_id_by_vip_id(context, pool['vip_id']) res = super(NvpAdvancedPlugin, self).create_pool_health_monitor(context, health_monitor, pool_id) monitor = self.get_health_monitor(context, monitor_id) #TODO(linb)Add Exception handle if error self.vcns_driver.create_health_monitor(context, edge_id, monitor) #Get updated pool pool['health_monitors'].append(monitor['id']) self._resource_set_status( context, loadbalancer_db.Pool, pool_id, service_constants.PENDING_UPDATE) try: self._vcns_update_pool(context, pool) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_("Failed to associate monitor with pool!")) self._resource_set_status( context, loadbalancer_db.Pool, pool_id, service_constants.ERROR) super(NvpAdvancedPlugin, self).delete_pool_health_monitor( context, monitor_id, pool_id) self._resource_set_status( context, loadbalancer_db.Pool, pool_id, service_constants.ACTIVE) self._resource_set_status( context, loadbalancer_db.PoolMonitorAssociation, monitor_id, service_constants.ACTIVE, res, pool_id=pool_id) return res def delete_pool_health_monitor(self, context, id, pool_id): super(NvpAdvancedPlugin, self).delete_pool_health_monitor( context, id, pool_id) pool = self.get_pool(context, pool_id) #Check whether the pool is already associated with the vip if pool.get('vip_id'): #Delete the monitor on vshield edge edge_id = self._get_edge_id_by_vip_id(context, pool['vip_id']) self._resource_set_status( context, loadbalancer_db.Pool, pool_id, service_constants.PENDING_UPDATE) try: self._vcns_update_pool(context, pool) except Exception: with excutils.save_and_reraise_exception(): LOG.exception( _("Failed to update pool with pool_monitor!")) self._resource_set_status( context, loadbalancer_db.Pool, pool_id, service_constants.ERROR) #TODO(linb): Add exception handle if error self.vcns_driver.delete_health_monitor(context, id, edge_id) self._resource_set_status( context, loadbalancer_db.Pool, pool_id, service_constants.ACTIVE) class VcnsCallbacks(object): """Edge callback implementation Callback functions for asynchronous tasks. """ def __init__(self, plugin): self.plugin = plugin def edge_deploy_started(self, task): """callback when deployment task started.""" jobdata = task.userdata['jobdata'] context = jobdata['context'] edge_id = task.userdata.get('edge_id') neutron_router_id = jobdata['neutron_router_id'] name = task.userdata['router_name'] if edge_id: LOG.debug(_("Start deploying %(edge_id)s for router %(name)s"), { 'edge_id': edge_id, 'name': name}) vcns_db.update_vcns_router_binding( context.session, neutron_router_id, edge_id=edge_id) else: LOG.debug(_("Failed to deploy Edge for router %s"), name) vcns_db.update_vcns_router_binding( context.session, neutron_router_id, status=service_constants.ERROR) def edge_deploy_result(self, task): """callback when deployment task finished.""" jobdata = task.userdata['jobdata'] lrouter = jobdata['lrouter'] context = jobdata['context'] name = task.userdata['router_name'] neutron_router_id = jobdata['neutron_router_id'] router_db = None try: router_db = self.plugin._get_router( context, neutron_router_id) except l3.RouterNotFound: # Router might have been deleted before deploy finished LOG.exception(_("Router %s not found"), lrouter['uuid']) if task.status == TaskStatus.COMPLETED: LOG.debug(_("Successfully deployed %(edge_id)s for " "router %(name)s"), { 'edge_id': task.userdata['edge_id'], 'name': name}) if (router_db and router_db['status'] == service_constants.PENDING_CREATE): router_db['status'] = service_constants.ACTIVE binding = vcns_db.get_vcns_router_binding( context.session, neutron_router_id) # only update status to active if its status is pending create if binding['status'] == service_constants.PENDING_CREATE: vcns_db.update_vcns_router_binding( context.session, neutron_router_id, status=service_constants.ACTIVE) else: LOG.debug(_("Failed to deploy Edge for router %s"), name) if router_db: router_db['status'] = service_constants.ERROR vcns_db.update_vcns_router_binding( context.session, neutron_router_id, status=service_constants.ERROR) def edge_delete_result(self, task): jobdata = task.userdata['jobdata'] router_id = task.userdata['router_id'] context = jobdata['context'] if task.status == TaskStatus.COMPLETED: vcns_db.delete_vcns_router_binding(context.session, router_id) def interface_update_result(self, task): LOG.debug(_("interface_update_result %d"), task.status) def snat_create_result(self, task): LOG.debug(_("snat_create_result %d"), task.status) def snat_delete_result(self, task): LOG.debug(_("snat_delete_result %d"), task.status) def dnat_create_result(self, task): LOG.debug(_("dnat_create_result %d"), task.status) def dnat_delete_result(self, task): LOG.debug(_("dnat_delete_result %d"), task.status) def routes_update_result(self, task): LOG.debug(_("routes_update_result %d"), task.status) def nat_update_result(self, task): LOG.debug(_("nat_update_result %d"), task.status) def _process_base_create_lswitch_args(*args, **kwargs): tags = utils.get_tags() tags.append({"tag": args[1], "scope": "quantum_net_id"}) if args[2]: tags.append({"tag": args[2], "scope": "os_tid"}) switch_name = args[3] tz_config = args[4] if kwargs.get("shared", False) or len(args) >= 6: tags.append({"tag": "true", "scope": "shared"}) if kwargs.get("tags"): tags.extend(kwargs["tags"]) return switch_name, tz_config, tags