components/openstack/neutron/files/evs/plugin.py
changeset 5405 66fd59fecd68
parent 4975 6445e44cfccd
child 5701 1409c5c63ef9
equal deleted inserted replaced
5404:55e409ba4e72 5405:66fd59fecd68
     1 # vim: tabstop=4 shiftwidth=4 softtabstop=4
     1 # vim: tabstop=4 shiftwidth=4 softtabstop=4
     2 
     2 
     3 # Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
     3 # Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
     4 #
     4 #
     5 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
     5 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
     6 #    not use this file except in compliance with the License. You may obtain
     6 #    not use this file except in compliance with the License. You may obtain
     7 #    a copy of the License at
     7 #    a copy of the License at
     8 #
     8 #
    14 #    License for the specific language governing permissions and limitations
    14 #    License for the specific language governing permissions and limitations
    15 #    under the License.
    15 #    under the License.
    16 #
    16 #
    17 # @author: Girish Moodalbail, Oracle, Inc.
    17 # @author: Girish Moodalbail, Oracle, Inc.
    18 
    18 
    19 import time
       
    20 
       
    21 import rad.client as radcli
    19 import rad.client as radcli
    22 import rad.connect as radcon
    20 import rad.connect as radcon
    23 import rad.bindings.com.oracle.solaris.rad.evscntl_1 as evsbind
    21 import rad.bindings.com.oracle.solaris.rad.evscntl_1 as evsbind
    24 
    22 
    25 from oslo.config import cfg
    23 from oslo_concurrency import lockutils
    26 from oslo.db import exception as os_db_exc
    24 from oslo_config import cfg
    27 from sqlalchemy import exc as sqla_exc
    25 from oslo_db import api as oslo_db_api
       
    26 from oslo_log import log as logging
       
    27 from oslo_utils import importutils
    28 
    28 
    29 from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
    29 from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
    30 from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
    30 from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
    31 from neutron.api.rpc.handlers import dhcp_rpc
    31 from neutron.api.rpc.handlers import dhcp_rpc
    32 from neutron.api.rpc.handlers import l3_rpc
    32 from neutron.api.rpc.handlers import l3_rpc
    38 from neutron.db import agents_db
    38 from neutron.db import agents_db
    39 from neutron.db import agentschedulers_db
    39 from neutron.db import agentschedulers_db
    40 from neutron.db import api as db
    40 from neutron.db import api as db
    41 from neutron.db import db_base_plugin_v2
    41 from neutron.db import db_base_plugin_v2
    42 from neutron.db import external_net_db
    42 from neutron.db import external_net_db
       
    43 from neutron.db import l3_agentschedulers_db
       
    44 from neutron.db import l3_attrs_db
    43 from neutron.db import l3_gwmode_db
    45 from neutron.db import l3_gwmode_db
    44 from neutron.db import model_base
    46 from neutron.db import model_base
    45 from neutron.db import models_v2
    47 from neutron.db import models_v2
       
    48 from neutron.db import portbindings_db
    46 from neutron.db import quota_db
    49 from neutron.db import quota_db
       
    50 from neutron.db import securitygroups_db
    47 from neutron.extensions import external_net
    51 from neutron.extensions import external_net
    48 from neutron.extensions import providernet
    52 from neutron.extensions import providernet
    49 from neutron.openstack.common import importutils
       
    50 from neutron.openstack.common import lockutils
       
    51 from neutron.openstack.common import log as logging
       
    52 from neutron.plugins.common import constants as svc_constants
    53 from neutron.plugins.common import constants as svc_constants
       
    54 from neutron.plugins.ml2 import models
    53 
    55 
    54 LOG = logging.getLogger(__name__)
    56 LOG = logging.getLogger(__name__)
    55 MAX_RETRIES = 10
    57 # Only import the vpn server code if it exists.
    56 RETRY_INTERVAL = 2
    58 try:
       
    59     sp = cfg.CONF.service_plugins
       
    60     vpns = 'vpnaas'
       
    61     if vpns in sp:
       
    62         try:
       
    63             from neutron_vpnaas.db.vpn import vpn_db
       
    64             LOG.debug("Loading VPNaaS service driver.")
       
    65         except ImportError:
       
    66             pass
       
    67     else:
       
    68         LOG.debug("vpnaas service_plugin not configured")
       
    69 except:
       
    70     pass
    57 
    71 
    58 evs_controller_opts = [
    72 evs_controller_opts = [
    59     cfg.StrOpt('evs_controller', default='ssh://evsuser@localhost',
    73     cfg.StrOpt('evs_controller', default='ssh://evsuser@localhost',
    60                help=_("An URI that specifies an EVS controller"))
    74                help=_("An URI that specifies an EVS controller"))
    61 ]
    75 ]
    82 
    96 
    83 
    97 
    84 class EVSNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
    98 class EVSNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
    85                          agentschedulers_db.DhcpAgentSchedulerDbMixin,
    99                          agentschedulers_db.DhcpAgentSchedulerDbMixin,
    86                          external_net_db.External_net_db_mixin,
   100                          external_net_db.External_net_db_mixin,
       
   101                          l3_agentschedulers_db.L3AgentSchedulerDbMixin,
    87                          l3_gwmode_db.L3_NAT_db_mixin):
   102                          l3_gwmode_db.L3_NAT_db_mixin):
    88     """Implements v2 Neutron Plug-in API specification.
   103     """Implements v2 Neutron Plug-in API specification.
    89 
   104 
    90     All the neutron API calls to create/delete/retrieve Network/Subnet/Port
   105     All the neutron API calls to create/delete/retrieve Network/Subnet/Port
    91     are forwarded to EVS controller through Solaris RAD. The RAD connection
   106     are forwarded to EVS controller through Solaris RAD. The RAD connection
   146     |---------------------+------------------+------------------------------|
   161     |---------------------+------------------+------------------------------|
   147     """
   162     """
   148 
   163 
   149     _supported_extension_aliases = ["provider", "external-net", "router",
   164     _supported_extension_aliases = ["provider", "external-net", "router",
   150                                     "ext-gw-mode", "quotas", "agent",
   165                                     "ext-gw-mode", "quotas", "agent",
       
   166                                     "l3_agent_scheduler",
   151                                     "dhcp_agent_scheduler"]
   167                                     "dhcp_agent_scheduler"]
   152 
   168 
   153     def __init__(self):
   169     def __init__(self):
   154         engine = db.get_engine()
   170         engine = db.get_engine()
   155         model_base.BASEV2.metadata.create_all(engine)
   171         model_base.BASEV2.metadata.create_all(engine)
   156 
   172 
   157         self.network_scheduler = importutils.import_object(
   173         self.network_scheduler = importutils.import_object(
   158             cfg.CONF.network_scheduler_driver
   174             cfg.CONF.network_scheduler_driver
   159         )
   175         )
   160 
   176         self.router_scheduler = importutils.import_object(
       
   177             cfg.CONF.router_scheduler_driver
       
   178         )
   161         self._setup_rpc()
   179         self._setup_rpc()
   162         self._rad_connection = None
   180         self._rad_connection = None
   163 
   181 
   164     @property
   182     @property
   165     def rad_connection(self):
   183     def rad_connection(self):
   571             vport = evs.addVPort(propstr, vportname)
   589             vport = evs.addVPort(propstr, vportname)
   572         except radcli.ObjectError as oe:
   590         except radcli.ObjectError as oe:
   573             raise EVSControllerError(oe.get_payload().errmsg)
   591             raise EVSControllerError(oe.get_payload().errmsg)
   574         return vport
   592         return vport
   575 
   593 
   576     def _create_port_db(self, context, port):
   594     @oslo_db_api.wrap_db_retry(max_retries=db.MAX_RETRIES,
       
   595                                retry_on_request=True,
       
   596                                retry_on_deadlock=True)
       
   597     def create_port(self, context, port):
       
   598         """Creates a port(VPort) for a given network(EVS).
       
   599 
       
   600          A VPort represents the point of attachment between the VNIC and an
       
   601          EVS. It encapsulates various network configuration parameters such as
       
   602              -- SLAs (maxbw, cos, and priority)
       
   603              -- IP address and
       
   604              -- MAC address, et al
       
   605          This configuration is inherited by the VNIC when it connects to the
       
   606          VPort.
       
   607         """
       
   608         if port['port']['admin_state_up'] is False:
       
   609             raise EVSOpNotSupported(_("setting admin_state_up=False for a "
       
   610                                       "port not supported"))
       
   611 
   577         with context.session.begin(subtransactions=True):
   612         with context.session.begin(subtransactions=True):
   578             # for external gateway ports and floating ips, tenant_id
   613             # for external gateway ports and floating ips, tenant_id
   579             # is not set, but EVS does not like it.
   614             # is not set, but EVS does not like it.
   580             tenant_id = self._get_tenant_id_for_create(context, port['port'])
   615             tenant_id = self._get_tenant_id_for_create(context, port['port'])
   581             if not tenant_id:
   616             if not tenant_id:
   603                             db_port['fixed_ips'][0].get('ip_address'))
   638                             db_port['fixed_ips'][0].get('ip_address'))
   604             proplist.append('uuid=%s' % db_port['id'])
   639             proplist.append('uuid=%s' % db_port['id'])
   605 
   640 
   606             self._evs_controller_addVPort(tenantname, evs_id, vportname,
   641             self._evs_controller_addVPort(tenantname, evs_id, vportname,
   607                                           ",".join(proplist))
   642                                           ",".join(proplist))
   608 
       
   609         return db_port
   643         return db_port
   610 
       
   611     def create_port(self, context, port):
       
   612         """Creates a port(VPort) for a given network(EVS).
       
   613 
       
   614          A VPort represents the point of attachment between the VNIC and an
       
   615          EVS. It encapsulates various network configuration parameters such as
       
   616              -- SLAs (maxbw, cos, and priority)
       
   617              -- IP address and
       
   618              -- MAC address, et al
       
   619          This configuration is inherited by the VNIC when it connects to the
       
   620          VPort.
       
   621         """
       
   622         if port['port']['admin_state_up'] is False:
       
   623             raise EVSOpNotSupported(_("setting admin_state_up=False for a "
       
   624                                       "port not supported"))
       
   625 
       
   626         exc = None
       
   627         for attempt in xrange(1, MAX_RETRIES):
       
   628             try:
       
   629                 return self._create_port_db(context, port)
       
   630             except os_db_exc.DBDeadlock as exc:
       
   631                 LOG.debug(_("Found %s. Restarting the transaction. "
       
   632                             "Attempt: %s") % (exc, attempt))
       
   633                 time.sleep(RETRY_INTERVAL)
       
   634             except sqla_exc.OperationalError as exc:
       
   635                 if ('timeout' in exc.message.lower() or
       
   636                         'restart' in exc.message.lower()):
       
   637                     LOG.debug(_("Found %s. Restarting the transaction. "
       
   638                                 "Attempt: %s") % (exc, attempt))
       
   639                     time.sleep(RETRY_INTERVAL)
       
   640                     continue
       
   641                 raise
       
   642         else:
       
   643             assert exc is not None
       
   644             raise exc
       
   645 
   644 
   646     def update_port(self, context, id, port):
   645     def update_port(self, context, id, port):
   647         # EVS does not allow updating certain attributes, so check for it
   646         # EVS does not allow updating certain attributes, so check for it
   648         state = port['port'].get('admin_state_up')
   647         state = port['port'].get('admin_state_up')
   649         if state and state is False:
   648         if state and state is False:
   662             raise EVSOpNotSupported(_("updating port's fixed_ips "
   661             raise EVSOpNotSupported(_("updating port's fixed_ips "
   663                                       "is not supported"))
   662                                       "is not supported"))
   664         LOG.debug(_("Updating port %s with %s") % (id, port))
   663         LOG.debug(_("Updating port %s with %s") % (id, port))
   665         db_port = super(EVSNeutronPluginV2, self).update_port(context,
   664         db_port = super(EVSNeutronPluginV2, self).update_port(context,
   666                                                               id, port)
   665                                                               id, port)
   667 
       
   668         return db_port
   666         return db_port
   669 
   667 
   670     def get_port(self, context, id, fields=None):
   668     def get_port(self, context, id, fields=None):
   671         LOG.debug(_("Getting port: %s"), id)
   669         LOG.debug(_("Getting port: %s"), id)
   672         port = super(EVSNeutronPluginV2, self).get_port(context, id, None)
   670         port = super(EVSNeutronPluginV2, self).get_port(context, id, None)