]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Implements securitygroup extension for nuage plugin
authorDivya ChanneGowda <divya.hc@gmail.com>
Tue, 15 Jul 2014 21:33:30 +0000 (14:33 -0700)
committerDivya ChanneGowda <divya.hc@gmail.com>
Wed, 20 Aug 2014 04:23:29 +0000 (21:23 -0700)
In Nuage VSP, the scope of vport-tag(Neutron securitygroup equivalent) is either
per router or per subnet whereas securitygroup scope in Neutron is per tenant.
Because of this, the mapping between neutron and VSP resource always happens at
the port create or update time, such that port's router/subnet is known and
thus sg attachment point in VSP is known.
On port-update --security-group sg1, if this is the first port getting attached
to that security-group, corresponding vport-tag(for sg) and rules( for sg rules)
are created on VSP. Subsequent port-update for the same sg1 will just update the
port to vport-tag binding. When security-group and security-group-rules are
deleted on neutron, corresponding vport-tag and rules are deleted on the VSP.

Implements: blueprint securitygroup-ext-for-nuage-plugin

Change-Id: If6f7f16ad727ae9394008fb81b56c785c2404c8f

neutron/plugins/nuage/plugin.py
neutron/tests/unit/nuage/fake_nuageclient.py
neutron/tests/unit/nuage/test_nuage_plugin.py

index 164154cfd130c15d4e25007670ffdb2c6cd25426..f64e587f951a972e68090ded6d862d939b858c2a 100644 (file)
@@ -32,11 +32,14 @@ from neutron.db import external_net_db
 from neutron.db import extraroute_db
 from neutron.db import l3_db
 from neutron.db import quota_db  # noqa
+from neutron.db import securitygroups_db as sg_db
 from neutron.extensions import external_net
 from neutron.extensions import l3
 from neutron.extensions import portbindings
+from neutron.extensions import securitygroup as ext_sg
 from neutron.openstack.common import excutils
 from neutron.openstack.common import importutils
+from neutron.openstack.common import lockutils
 from neutron.plugins.nuage.common import config
 from neutron.plugins.nuage.common import constants
 from neutron.plugins.nuage.common import exceptions as nuage_exc
@@ -50,11 +53,13 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
                   external_net_db.External_net_db_mixin,
                   extraroute_db.ExtraRoute_db_mixin,
                   l3_db.L3_NAT_db_mixin,
-                  netpartition.NetPartitionPluginBase):
+                  netpartition.NetPartitionPluginBase,
+                  sg_db.SecurityGroupDbMixin):
     """Class that implements Nuage Networks' plugin functionality."""
     supported_extension_aliases = ["router", "binding", "external-net",
                                    "net-partition", "nuage-router",
-                                   "nuage-subnet", "quotas", "extraroute"]
+                                   "nuage-subnet", "quotas",
+                                   "extraroute", "security-group"]
 
     binding_view = "extension:port_binding:view"
 
@@ -122,18 +127,93 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
             'net_partition': net_partition,
             'ip': port['fixed_ips'][0]['ip_address'],
             'no_of_ports': len(ports),
-            'tenant': port['tenant_id']
+            'tenant': port['tenant_id'],
         }
 
-        self.nuageclient.create_vms(params)
+        nuage_vm = self.nuageclient.create_vms(params)
+        if nuage_vm:
+            if port['fixed_ips'][0]['ip_address'] != str(nuage_vm['ip']):
+                self._update_port_ip(context, port, nuage_vm['ip'])
 
+    def _get_router_by_subnet(self, context, subnet_id):
+        filters = {
+            'fixed_ips': {'subnet_id': [subnet_id]},
+            'device_owner': [os_constants.DEVICE_OWNER_ROUTER_INTF]
+        }
+        router_port = self.get_ports(context, filters=filters)
+        if not router_port:
+            msg = (_("Router for subnet %s not found ") % subnet_id)
+            raise n_exc.BadRequest(resource='port', msg=msg)
+        return router_port[0]['device_id']
+
+    def _process_port_create_security_group(self, context, port,
+                                            sec_group):
+        if not attributes.is_attr_set(sec_group):
+            port[ext_sg.SECURITYGROUPS] = []
+            return
+        port_id = port['id']
+        with context.session.begin(subtransactions=True):
+            for sg_id in sec_group:
+                super(NuagePlugin,
+                      self)._create_port_security_group_binding(context,
+                                                                port_id,
+                                                                sg_id)
+        try:
+            vptag_vport_list = []
+            for sg_id in sec_group:
+                params = {
+                    'neutron_port_id': port_id
+                }
+                nuage_port = self.nuageclient.get_nuage_port_by_id(params)
+                if nuage_port and nuage_port.get('nuage_vport_id'):
+                    nuage_vport_id = nuage_port['nuage_vport_id']
+                    sg = self._get_security_group(context, sg_id)
+                    sg_rules = self.get_security_group_rules(
+                                        context,
+                                        {'security_group_id': [sg_id]})
+                    sg_params = {
+                        'nuage_port': nuage_port,
+                        'sg': sg,
+                        'sg_rules': sg_rules
+                    }
+                    nuage_vptag_id = (
+                        self.nuageclient.process_port_create_security_group(
+                                                                    sg_params))
+                    vptag_vport = {
+                        'nuage_vporttag_id': nuage_vptag_id
+                    }
+                    vptag_vport_list.append(vptag_vport)
+
+            if vptag_vport_list:
+                params = {
+                    'vptag_vport_list': vptag_vport_list,
+                    'nuage_vport_id': nuage_vport_id
+                }
+                self.nuageclient.update_nuage_vport(params)
+        except Exception:
+            with excutils.save_and_reraise_exception():
+                for sg_id in sec_group:
+                    super(NuagePlugin,
+                          self)._delete_port_security_group_bindings(context,
+                                                                 port_id)
+        # Convert to list as a set might be passed here and
+        # this has to be serialized
+        port[ext_sg.SECURITYGROUPS] = (list(sec_group) if sec_group else [])
+
+    def _delete_port_security_group_bindings(self, context, port_id):
+        super(NuagePlugin,
+              self)._delete_port_security_group_bindings(context, port_id)
+        self.nuageclient.delete_port_security_group_bindings(port_id)
+
+    @lockutils.synchronized('create_port', 'nuage-port', external=True)
     def create_port(self, context, port):
         session = context.session
         with session.begin(subtransactions=True):
+            p = port['port']
+            self._ensure_default_security_group_on_port(context, port)
             port = super(NuagePlugin, self).create_port(context, port)
             device_owner = port.get('device_owner', None)
-            if (device_owner and
-                device_owner not in constants.AUTO_CREATE_PORT_OWNERS):
+            if device_owner not in constants.AUTO_CREATE_PORT_OWNERS:
                 if 'fixed_ips' not in port or len(port['fixed_ips']) == 0:
                     return self._extend_port_dict_binding(context, port)
                 subnet_id = port['fixed_ips'][0]['subnet_id']
@@ -154,17 +234,23 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
                                 super(NuagePlugin, self).delete_port(
                                     context,
                                     port['id'])
+                    if ext_sg.SECURITYGROUPS in p:
+                        self._process_port_create_security_group(
+                            context,
+                            port,
+                            p[ext_sg.SECURITYGROUPS])
         return self._extend_port_dict_binding(context, port)
 
     def update_port(self, context, id, port):
         p = port['port']
+        sg_groups = None
         if p.get('device_owner', '').startswith(
             constants.NOVA_PORT_OWNER_PREF):
             session = context.session
             with session.begin(subtransactions=True):
                 port = self._get_port(context, id)
                 port.update(p)
-                if 'fixed_ips' not in port or len(port['fixed_ips']) == 0:
+                if not port.get('fixed_ips'):
                     return self._make_port_dict(port)
                 subnet_id = port['fixed_ips'][0]['subnet_id']
 
@@ -178,24 +264,48 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
                     'neutron_port_id': id,
                 }
                 nuage_port = self.nuageclient.get_nuage_port_by_id(params)
-                if not nuage_port:
-                    msg = (_("Port %s not found on VSD") % id)
-                    raise n_exc.BadRequest(resource='port', msg=msg)
-                if not nuage_port['nuage_vport_id']:
+                if not nuage_port or not nuage_port.get('nuage_vport_id'):
                     self._create_update_port(context, port,
                                              subnet_mapping[
                                                  'net_partition_id'],
                                              subnet_mapping['nuage_subnet_id'])
                 updated_port = self._make_port_dict(port)
+                sg_port = self._extend_port_dict_security_group(
+                    updated_port,
+                    port
+                )
+                sg_groups = sg_port[ext_sg.SECURITYGROUPS]
         else:
             updated_port = super(NuagePlugin, self).update_port(context, id,
                                                                 port)
+            if not updated_port.get('fixed_ips'):
+                return updated_port
+            subnet_id = updated_port['fixed_ips'][0]['subnet_id']
+            subnet_mapping = nuagedb.get_subnet_l2dom_by_id(context.session,
+                                                            subnet_id)
+        if subnet_mapping:
+            if sg_groups:
+                self._delete_port_security_group_bindings(context,
+                                                          updated_port['id'])
+                self._process_port_create_security_group(context,
+                                                         updated_port,
+                                                         sg_groups)
+            elif ext_sg.SECURITYGROUPS in p:
+                self._delete_port_security_group_bindings(context,
+                                                          updated_port['id'])
+                self._process_port_create_security_group(
+                    context,
+                    updated_port,
+                    p[ext_sg.SECURITYGROUPS]
+                )
         return updated_port
 
+    @lockutils.synchronized('delete-port', 'nuage-del', external=True)
     def delete_port(self, context, id, l3_port_check=True):
         if l3_port_check:
             self.prevent_l3_port_deletion(context, id)
         port = self._get_port(context, id)
+        nuage_vif_id = None
         params = {
             'neutron_port_id': id,
         }
@@ -212,12 +322,19 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
                                                         sub_id)
         if not subnet_mapping:
             return super(NuagePlugin, self).delete_port(context, id)
+
+        # Need to call this explicitly to delete vport to vporttag binding
+        if ext_sg.SECURITYGROUPS in port:
+            self._delete_port_security_group_bindings(context, id)
+
         netpart_id = subnet_mapping['net_partition_id']
         net_partition = nuagedb.get_net_partition_by_id(context.session,
                                                         netpart_id)
 
-        # Need to call this explicitly to delete vport_vporttag_mapping
+        # Need to call this explicitly to delete vport
         if constants.NOVA_PORT_OWNER_PREF in port['device_owner']:
+            if nuage_port:
+                nuage_vif_id = nuage_port['nuage_vif_id']
             # This was a VM Port
             filters = {'device_id': [port['device_id']]}
             ports = self.get_ports(context, filters)
@@ -226,7 +343,7 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
                 'net_partition': net_partition,
                 'tenant': port['tenant_id'],
                 'mac': port['mac_address'],
-                'nuage_vif_id': nuage_port['nuage_vif_id'],
+                'nuage_vif_id': nuage_vif_id,
                 'id': port['device_id']
             }
             self.nuageclient.delete_vms(params)
@@ -264,6 +381,10 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
     def create_network(self, context, network):
         net = network['network']
         with context.session.begin(subtransactions=True):
+            self._ensure_default_security_group(
+                context,
+                network['network']['tenant_id']
+            )
             net = super(NuagePlugin, self).create_network(context,
                                                           network)
             self._process_l3_create(context, net, network['network'])
@@ -1010,4 +1131,50 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
                 if fip:
                     self.nuageclient.delete_nuage_floatingip(
                         fip['nuage_fip_id'])
-            super(NuagePlugin, self).delete_floatingip(context, id)
\ No newline at end of file
+            super(NuagePlugin, self).delete_floatingip(context, id)
+
+    def delete_security_group(self, context, id):
+        filters = {'security_group_id': [id]}
+        ports = self._get_port_security_group_bindings(context,
+                                                       filters)
+        if ports:
+            raise ext_sg.SecurityGroupInUse(id=id)
+        sg_rules = self.get_security_group_rules(context,
+                                                 {'security_group_id': [id]})
+
+        if sg_rules:
+            self.nuageclient.delete_nuage_sgrule(sg_rules)
+        self.nuageclient.delete_nuage_secgroup(id)
+
+        super(NuagePlugin, self).delete_security_group(context, id)
+
+    def create_security_group_rule(self, context, security_group_rule):
+        sg_rule = security_group_rule['security_group_rule']
+        self.nuageclient.validate_nuage_sg_rule_definition(sg_rule)
+        sg_id = sg_rule['security_group_id']
+
+        local_sg_rule = super(NuagePlugin,
+                              self).create_security_group_rule(
+                                        context, security_group_rule)
+
+        try:
+            nuage_vptag = self.nuageclient.get_sg_vptag_mapping(sg_id)
+            if nuage_vptag:
+                sg_params = {
+                    'sg_id': sg_id,
+                    'neutron_sg_rule': local_sg_rule,
+                    'vptag': nuage_vptag
+                }
+                self.nuageclient.create_nuage_sgrule(sg_params)
+        except Exception:
+            with excutils.save_and_reraise_exception():
+                super(NuagePlugin,
+                      self).delete_security_group_rule(context,
+                                                   local_sg_rule['id'])
+
+        return local_sg_rule
+
+    def delete_security_group_rule(self, context, id):
+        local_sg_rule = self.get_security_group_rule(context, id)
+        super(NuagePlugin, self).delete_security_group_rule(context, id)
+        self.nuageclient.delete_nuage_sgrule([local_sg_rule])
index dfad786084d118fb73e5820a1406125bc4f6c0a2..bbfecd487bd0c153577a7fef177fdf5fe6021ebe 100644 (file)
@@ -161,3 +161,27 @@ class FakeNuageClient(object):
 
     def get_usergroup(self, tenant, net_partition_id):
         return uuidutils.generate_uuid(), uuidutils.generate_uuid()
+
+    def get_sg_vptag_mapping(self, id):
+        pass
+
+    def validate_nuage_sg_rule_definition(self, params):
+        pass
+
+    def create_nuage_sgrule(self, params):
+        pass
+
+    def update_nuage_vport(self, params):
+        pass
+
+    def delete_nuage_sgrule(self, params):
+        pass
+
+    def delete_nuage_secgroup(self, params):
+        pass
+
+    def process_port_create_security_group(self, params):
+        pass
+
+    def delete_port_security_group_bindings(self, params):
+        pass
index 244ebbde2232b82766c1cdf922a1a6240fa48b3d..332494c4898e19aa6f443e27087b2ce40d785925 100644 (file)
@@ -29,6 +29,7 @@ from neutron.tests.unit import _test_extension_portbindings as test_bindings
 from neutron.tests.unit.nuage import fake_nuageclient
 from neutron.tests.unit import test_db_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
 
 API_EXT_PATH = os.path.dirname(extensions.__file__)
@@ -287,3 +288,8 @@ class TestNuageExtrarouteTestCase(NuagePluginV2TestCase,
 
     def test_network_update_external_failure(self):
         self._test_network_update_external_failure()
+
+
+class TestNuageSecurityGroupTestCase(NuagePluginV2TestCase,
+                                     test_sg.TestSecurityGroups):
+    pass