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) |