Isolated security groups with conf toggle
Allow isolated networks security groups using the QUARK.environment_capabilities configuration value. JIRA:NCP-1465 JIRA:NCP-1681
This commit is contained in:
		
							
								
								
									
										10
									
								
								quark/cache/security_groups_client.py
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								quark/cache/security_groups_client.py
									
									
									
									
										vendored
									
									
								
							@@ -16,13 +16,17 @@
 | 
			
		||||
import json
 | 
			
		||||
 | 
			
		||||
import netaddr
 | 
			
		||||
from oslo_config import cfg
 | 
			
		||||
from oslo_log import log as logging
 | 
			
		||||
 | 
			
		||||
from quark.cache import redis_base
 | 
			
		||||
from quark.environment import Capabilities
 | 
			
		||||
from quark import exceptions as q_exc
 | 
			
		||||
from quark import protocols
 | 
			
		||||
from quark import utils
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CONF = cfg.CONF
 | 
			
		||||
LOG = logging.getLogger(__name__)
 | 
			
		||||
SECURITY_GROUP_RULE_KEY = "rules"
 | 
			
		||||
SECURITY_GROUP_HASH_ATTR = "security group rules"
 | 
			
		||||
@@ -61,7 +65,11 @@ class SecurityGroupsClient(redis_base.ClientBase):
 | 
			
		||||
                if direction == "ingress":
 | 
			
		||||
                    source = self._convert_remote_network(prefix)
 | 
			
		||||
                else:
 | 
			
		||||
                    destination = self._convert_remote_network(prefix)
 | 
			
		||||
                    if (Capabilities.EGRESS not in
 | 
			
		||||
                            CONF.QUARK.environment_capabilities):
 | 
			
		||||
                        raise q_exc.EgressSecurityGroupRulesNotEnabled()
 | 
			
		||||
                    else:
 | 
			
		||||
                        destination = self._convert_remote_network(prefix)
 | 
			
		||||
 | 
			
		||||
            optional_fields = {}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,8 @@ from oslo_config import cfg
 | 
			
		||||
from oslo_log import log as logging
 | 
			
		||||
 | 
			
		||||
from quark.drivers import base
 | 
			
		||||
from quark.drivers import security_groups as sg_driver
 | 
			
		||||
from quark.environment import Capabilities
 | 
			
		||||
from quark import exceptions
 | 
			
		||||
from quark import utils
 | 
			
		||||
 | 
			
		||||
@@ -100,6 +102,9 @@ class NVPDriver(base.BaseDriver):
 | 
			
		||||
        self.limits = {'max_ports_per_switch': 0,
 | 
			
		||||
                       'max_rules_per_group': 0,
 | 
			
		||||
                       'max_rules_per_port': 0}
 | 
			
		||||
        self.sg_driver = None
 | 
			
		||||
        if Capabilities.SECURITY_GROUPS in CONF.QUARK.environment_capabilities:
 | 
			
		||||
            self.sg_driver = sg_driver.SecurityGroupDriver()
 | 
			
		||||
        super(NVPDriver, self).__init__()
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
@@ -268,9 +273,8 @@ class NVPDriver(base.BaseDriver):
 | 
			
		||||
        return {'logical_switches': [self._collect_lswitch_info(s, get_status)
 | 
			
		||||
                for s in switches]}
 | 
			
		||||
 | 
			
		||||
    def create_port(self, context, network_id, port_id,
 | 
			
		||||
                    status=True, security_groups=None,
 | 
			
		||||
                    device_id="", **kwargs):
 | 
			
		||||
    def create_port(self, context, network_id, port_id, status=True,
 | 
			
		||||
                    security_groups=None, device_id="", **kwargs):
 | 
			
		||||
        security_groups = security_groups or []
 | 
			
		||||
        tenant_id = context.tenant_id
 | 
			
		||||
        lswitch = self._create_or_choose_lswitch(context, network_id)
 | 
			
		||||
@@ -280,9 +284,10 @@ class NVPDriver(base.BaseDriver):
 | 
			
		||||
            with self.get_connection() as connection:
 | 
			
		||||
                port = connection.lswitch_port(lswitch)
 | 
			
		||||
                port.admin_status_enabled(status)
 | 
			
		||||
                nvp_group_ids = self._get_security_groups_for_port(
 | 
			
		||||
                    context, security_groups)
 | 
			
		||||
                port.security_profiles(nvp_group_ids)
 | 
			
		||||
                if not self.sg_driver:
 | 
			
		||||
                    nvp_group_ids = self._get_security_groups_for_port(
 | 
			
		||||
                        context, security_groups)
 | 
			
		||||
                    port.security_profiles(nvp_group_ids)
 | 
			
		||||
                tags = [dict(tag=network_id, scope="neutron_net_id"),
 | 
			
		||||
                        dict(tag=port_id, scope="neutron_port_id"),
 | 
			
		||||
                        dict(tag=tenant_id, scope="os_tid"),
 | 
			
		||||
@@ -291,8 +296,8 @@ class NVPDriver(base.BaseDriver):
 | 
			
		||||
                port.tags(tags)
 | 
			
		||||
                res = port.create()
 | 
			
		||||
                try:
 | 
			
		||||
                    """Catching odd NVP returns here will make it safe to assume that
 | 
			
		||||
                    NVP returned something correct."""
 | 
			
		||||
                    """Catching odd NVP returns here will make it safe to
 | 
			
		||||
                    assume that NVP returned something correct."""
 | 
			
		||||
                    res["lswitch"] = lswitch
 | 
			
		||||
                except TypeError:
 | 
			
		||||
                    LOG.exception("Unexpected return from NVP: %s" % res)
 | 
			
		||||
@@ -304,16 +309,24 @@ class NVPDriver(base.BaseDriver):
 | 
			
		||||
        return _create_lswitch_port()
 | 
			
		||||
 | 
			
		||||
    @utils.retry_loop(CONF.NVP.operation_retries)
 | 
			
		||||
    def update_port(self, context, port_id, status=True,
 | 
			
		||||
                    security_groups=None, **kwargs):
 | 
			
		||||
        security_groups = security_groups or []
 | 
			
		||||
    def update_port(self, context, port_id, mac_address=None, device_id=None,
 | 
			
		||||
                    status=True, security_groups=None, **kwargs):
 | 
			
		||||
        if not self.sg_driver:
 | 
			
		||||
            security_groups = security_groups or []
 | 
			
		||||
        else:
 | 
			
		||||
            kwargs.update({'security_groups': security_groups})
 | 
			
		||||
        with self.get_connection() as connection:
 | 
			
		||||
            if self.sg_driver:
 | 
			
		||||
                kwargs.update({'mac_addres': mac_address,
 | 
			
		||||
                               'device_id': device_id})
 | 
			
		||||
                self.sg_driver.update_port(**kwargs)
 | 
			
		||||
            lswitch_id = self._lswitch_from_port(context, port_id)
 | 
			
		||||
            port = connection.lswitch_port(lswitch_id, port_id)
 | 
			
		||||
            nvp_group_ids = self._get_security_groups_for_port(context,
 | 
			
		||||
                                                               security_groups)
 | 
			
		||||
            if nvp_group_ids:
 | 
			
		||||
                port.security_profiles(nvp_group_ids)
 | 
			
		||||
            if not self.sg_driver:
 | 
			
		||||
                nvp_group_ids = self._get_security_groups_for_port(
 | 
			
		||||
                    context, security_groups)
 | 
			
		||||
                if nvp_group_ids:
 | 
			
		||||
                    port.security_profiles(nvp_group_ids)
 | 
			
		||||
            port.admin_status_enabled(status)
 | 
			
		||||
            return port.update()
 | 
			
		||||
 | 
			
		||||
@@ -327,6 +340,8 @@ class NVPDriver(base.BaseDriver):
 | 
			
		||||
                LOG.debug("Deleting port %s from lswitch %s"
 | 
			
		||||
                          % (port_id, lswitch_uuid))
 | 
			
		||||
                connection.lswitch_port(lswitch_uuid, port_id).delete()
 | 
			
		||||
                if self.sg_driver:
 | 
			
		||||
                    self.sg_driver.delete_port(**kwargs)
 | 
			
		||||
            except aiclib.core.AICException as ae:
 | 
			
		||||
                if ae.code == 404:
 | 
			
		||||
                    LOG.info("LSwitchPort/Port %s not found in NVP."
 | 
			
		||||
 
 | 
			
		||||
@@ -91,9 +91,11 @@ class OptimizedNVPDriver(NVPDriver):
 | 
			
		||||
    def update_port(self, context, port_id, status=True,
 | 
			
		||||
                    security_groups=None, **kwargs):
 | 
			
		||||
        security_groups = security_groups or []
 | 
			
		||||
        mac_address = kwargs.get('mac_address')
 | 
			
		||||
        device_id = kwargs.get('device_id')
 | 
			
		||||
        nvp_port = super(OptimizedNVPDriver, self).update_port(
 | 
			
		||||
            context, port_id, status=status,
 | 
			
		||||
            security_groups=security_groups)
 | 
			
		||||
            context, port_id, mac_address=mac_address, device_id=device_id,
 | 
			
		||||
            status=status, security_groups=security_groups)
 | 
			
		||||
        port = self._lport_select_by_id(context, port_id)
 | 
			
		||||
        port.update(nvp_port)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@ CONF = cfg.CONF
 | 
			
		||||
 | 
			
		||||
class Capabilities(object):
 | 
			
		||||
    SECURITY_GROUPS = "security_groups"
 | 
			
		||||
    EGRESS = "egress"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
quark_opts = [
 | 
			
		||||
 
 | 
			
		||||
@@ -116,9 +116,9 @@ class SecurityGroupsNotImplemented(exceptions.InvalidInput):
 | 
			
		||||
                "create")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TenantNetworkSecurityGroupsNotImplemented(exceptions.InvalidInput):
 | 
			
		||||
    message = _("Security Groups are not currently implemented for "
 | 
			
		||||
                "tenant networks")
 | 
			
		||||
class EgressSecurityGroupRulesNotEnabled(exceptions.InvalidInput):
 | 
			
		||||
    message = _("Egress security group rules are not currently allowed "
 | 
			
		||||
                "by environment_capabilities configuration.")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SecurityGroupsRequireDevice(exceptions.InvalidInput):
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@ from oslo_utils import uuidutils
 | 
			
		||||
 | 
			
		||||
from quark.db import api as db_api
 | 
			
		||||
from quark.drivers import registry
 | 
			
		||||
from quark.environment import Capabilities
 | 
			
		||||
from quark import exceptions as q_exc
 | 
			
		||||
from quark import ipam
 | 
			
		||||
from quark import network_strategy
 | 
			
		||||
@@ -145,8 +146,8 @@ def create_port(context, port):
 | 
			
		||||
 | 
			
		||||
    net_driver = registry.DRIVER_REGISTRY.get_driver(net["network_plugin"])
 | 
			
		||||
 | 
			
		||||
    # TODO(anyone): security groups are not currently supported on port create,
 | 
			
		||||
    #               nor on isolated networks today. Please see RM8615
 | 
			
		||||
    # TODO(anyone): security groups are not currently supported on port create.
 | 
			
		||||
    #               Please see JIRA:NCP-801
 | 
			
		||||
    security_groups = utils.pop_param(port_attrs, "security_groups")
 | 
			
		||||
    if security_groups is not None:
 | 
			
		||||
        raise q_exc.SecurityGroupsNotImplemented()
 | 
			
		||||
@@ -294,12 +295,11 @@ def update_port(context, id, port):
 | 
			
		||||
        quota.QUOTAS.limit_check(context, context.tenant_id,
 | 
			
		||||
                                 fixed_ips_per_port=len(fixed_ips))
 | 
			
		||||
 | 
			
		||||
    # TODO(anyone): security groups are not currently supported on port create,
 | 
			
		||||
    #               nor on isolated networks today. Please see RM8615
 | 
			
		||||
    new_security_groups = utils.pop_param(port_dict, "security_groups")
 | 
			
		||||
    if new_security_groups is not None:
 | 
			
		||||
        if not STRATEGY.is_parent_network(port_db["network_id"]):
 | 
			
		||||
            raise q_exc.TenantNetworkSecurityGroupsNotImplemented()
 | 
			
		||||
    if Capabilities.SECURITY_GROUPS not in CONF.QUARK.environment_capabilities:
 | 
			
		||||
        if new_security_groups is not None:
 | 
			
		||||
            if not STRATEGY.is_parent_network(port_db["network_id"]):
 | 
			
		||||
                raise q_exc.TenantNetworkSecurityGroupsNotImplemented()
 | 
			
		||||
 | 
			
		||||
    if new_security_groups is not None and not port_db["device_id"]:
 | 
			
		||||
        raise q_exc.SecurityGroupsRequireDevice()
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@ import redis
 | 
			
		||||
from quark.agent.xapi import VIF
 | 
			
		||||
from quark.cache import security_groups_client as sg_client
 | 
			
		||||
from quark.db import models
 | 
			
		||||
from quark.environment import Capabilities
 | 
			
		||||
from quark import exceptions as q_exc
 | 
			
		||||
from quark.tests import test_base
 | 
			
		||||
 | 
			
		||||
@@ -33,6 +34,13 @@ class TestRedisSecurityGroupsClient(test_base.TestBase):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        super(TestRedisSecurityGroupsClient, self).setUp()
 | 
			
		||||
        # Forces the connection pool to be recreated on every test
 | 
			
		||||
        sg_client.SecurityGroupsClient.connection_pool = None
 | 
			
		||||
        temp_envcaps = [Capabilities.SECURITY_GROUPS, Capabilities.EGRESS]
 | 
			
		||||
        CONF.set_override('environment_capabilities', temp_envcaps, 'QUARK')
 | 
			
		||||
 | 
			
		||||
    def tearDown(self):
 | 
			
		||||
        CONF.clear_override('environment_capabilities', 'QUARK')
 | 
			
		||||
 | 
			
		||||
    @mock.patch("uuid.uuid4")
 | 
			
		||||
    @mock.patch("quark.cache.redis_base.TwiceRedis")
 | 
			
		||||
 
 | 
			
		||||
@@ -769,17 +769,6 @@ class TestQuarkUpdatePortSecurityGroups(test_quark_plugin.TestQuarkPlugin):
 | 
			
		||||
            yield (port_find, port_update, alloc_ip, dealloc_ip, sg_find,
 | 
			
		||||
                   driver_port_update)
 | 
			
		||||
 | 
			
		||||
    def test_update_port_security_groups_on_tenant_net_raises(self):
 | 
			
		||||
        with self._stubs(
 | 
			
		||||
            port=dict(id=1, device_id="device")
 | 
			
		||||
        ) as (port_find, port_update, alloc_ip, dealloc_ip, sg_find,
 | 
			
		||||
              driver_port_update):
 | 
			
		||||
            new_port = dict(port=dict(name="ourport",
 | 
			
		||||
                                      security_groups=[1]))
 | 
			
		||||
            with self.assertRaises(
 | 
			
		||||
                    q_exc.TenantNetworkSecurityGroupsNotImplemented):
 | 
			
		||||
                self.plugin.update_port(self.context, 1, new_port)
 | 
			
		||||
 | 
			
		||||
    def test_update_port_security_groups(self):
 | 
			
		||||
        with self._stubs(
 | 
			
		||||
            port=dict(id=1, device_id="device"), parent_net=True
 | 
			
		||||
 
 | 
			
		||||
@@ -29,10 +29,10 @@ from quark.tests import test_base
 | 
			
		||||
class TestNVPDriver(test_base.TestBase):
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        super(TestNVPDriver, self).setUp()
 | 
			
		||||
 | 
			
		||||
        cfg.CONF.set_override('environment_capabilities', [], 'QUARK')
 | 
			
		||||
        if not hasattr(self, 'driver'):
 | 
			
		||||
            self.driver = quark.drivers.nvp_driver.NVPDriver()
 | 
			
		||||
 | 
			
		||||
        cfg.CONF.clear_override('environment_capabilities', 'QUARK')
 | 
			
		||||
        cfg.CONF.set_override('max_rules_per_group', 3, 'NVP')
 | 
			
		||||
        cfg.CONF.set_override('max_rules_per_port', 1, 'NVP')
 | 
			
		||||
        self.driver.max_ports_per_switch = 0
 | 
			
		||||
@@ -491,6 +491,7 @@ class TestNVPDriverCreatePort(TestNVPDriver):
 | 
			
		||||
            self.assertTrue(False in status_args)
 | 
			
		||||
 | 
			
		||||
    def test_create_port_with_security_groups(self):
 | 
			
		||||
        cfg.CONF.set_override('environment_capabilities', [], 'QUARK')
 | 
			
		||||
        with self._stubs() as connection:
 | 
			
		||||
            connection.securityprofile = self._create_security_profile()
 | 
			
		||||
            self.driver.create_port(self.context, self.net_id,
 | 
			
		||||
@@ -499,8 +500,10 @@ class TestNVPDriverCreatePort(TestNVPDriver):
 | 
			
		||||
            connection.lswitch_port().assert_has_calls([
 | 
			
		||||
                mock.call.security_profiles([self.profile_id]),
 | 
			
		||||
            ], any_order=True)
 | 
			
		||||
        cfg.CONF.clear_override('environment_capabilities', 'QUARK')
 | 
			
		||||
 | 
			
		||||
    def test_create_port_with_security_groups_max_rules(self):
 | 
			
		||||
        cfg.CONF.set_override('environment_capabilities', [], 'QUARK')
 | 
			
		||||
        with self._stubs() as connection:
 | 
			
		||||
            connection.securityprofile = self._create_security_profile()
 | 
			
		||||
            connection.securityprofile().read().update(
 | 
			
		||||
@@ -512,6 +515,7 @@ class TestNVPDriverCreatePort(TestNVPDriver):
 | 
			
		||||
                self.driver.create_port(
 | 
			
		||||
                    self.context, self.net_id, self.port_id,
 | 
			
		||||
                    security_groups=[1])
 | 
			
		||||
        cfg.CONF.clear_override('environment_capabilities', 'QUARK')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestNVPDriverUpdatePort(TestNVPDriver):
 | 
			
		||||
@@ -527,6 +531,7 @@ class TestNVPDriverUpdatePort(TestNVPDriver):
 | 
			
		||||
            yield connection
 | 
			
		||||
 | 
			
		||||
    def test_update_port(self):
 | 
			
		||||
        cfg.CONF.set_override('environment_capabilities', [], 'QUARK')
 | 
			
		||||
        with self._stubs() as connection:
 | 
			
		||||
            self.driver.update_port(
 | 
			
		||||
                self.context, self.port_id,
 | 
			
		||||
@@ -534,8 +539,10 @@ class TestNVPDriverUpdatePort(TestNVPDriver):
 | 
			
		||||
            connection.lswitch_port().assert_has_calls([
 | 
			
		||||
                mock.call.security_profiles([self.profile_id]),
 | 
			
		||||
            ], any_order=True)
 | 
			
		||||
        cfg.CONF.clear_override('environment_capabilities', 'QUARK')
 | 
			
		||||
 | 
			
		||||
    def test_update_port_max_rules(self):
 | 
			
		||||
        cfg.CONF.set_override('environment_capabilities', [], 'QUARK')
 | 
			
		||||
        with self._stubs() as connection:
 | 
			
		||||
            connection.securityprofile().read().update(
 | 
			
		||||
                {'logical_port_ingress_rules': [{'ethertype': 'IPv4'},
 | 
			
		||||
@@ -546,6 +553,7 @@ class TestNVPDriverUpdatePort(TestNVPDriver):
 | 
			
		||||
                self.driver.update_port(
 | 
			
		||||
                    self.context, self.port_id,
 | 
			
		||||
                    security_groups=[1])
 | 
			
		||||
        cfg.CONF.clear_override('environment_capabilities', 'QUARK')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestNVPDriverLswitchesForNetwork(TestNVPDriver):
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user