Merge "Central and local plugin (part3, security group)"
This commit is contained in:
commit
21a6f9c215
|
@ -62,7 +62,13 @@ client_opts = [
|
|||
cfg.StrOpt('admin_tenant_domain_name',
|
||||
default='Default',
|
||||
help='tenant domain name of admin account, needed when'
|
||||
' auto_refresh_endpoint set to True')
|
||||
' auto_refresh_endpoint set to True'),
|
||||
cfg.StrOpt('ew_bridge_cidr',
|
||||
default='100.0.0.0/9',
|
||||
help='cidr pool of the east-west bridge network'),
|
||||
cfg.StrOpt('ns_bridge_cidr',
|
||||
default='100.128.0.0/9',
|
||||
help='cidr pool of the north-south bridge network')
|
||||
]
|
||||
client_opt_group = cfg.OptGroup('client')
|
||||
cfg.CONF.register_group(client_opt_group)
|
||||
|
|
|
@ -79,6 +79,7 @@ PROFILE_REGION = 'region'
|
|||
JT_ROUTER = 'router'
|
||||
JT_ROUTER_SETUP = 'router_setup'
|
||||
JT_PORT_DELETE = 'port_delete'
|
||||
JT_SEG_RULE_SETUP = 'seg_rule_setup'
|
||||
|
||||
# network type
|
||||
NT_LOCAL = 'local'
|
||||
|
|
|
@ -94,3 +94,8 @@ class XJobAPI(object):
|
|||
self.client.prepare(exchange='openstack').cast(
|
||||
ctxt, 'delete_server_port',
|
||||
payload={constants.JT_PORT_DELETE: port_id})
|
||||
|
||||
def configure_security_group_rules(self, ctxt, project_id):
|
||||
self.client.prepare(exchange='openstack').cast(
|
||||
ctxt, 'configure_security_group_rules',
|
||||
payload={constants.JT_SEG_RULE_SETUP: project_id})
|
||||
|
|
|
@ -400,7 +400,11 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||
gateway_port_body)
|
||||
return super(TricirclePlugin, self).get_port(context, t_gateway_id)
|
||||
db_port = super(TricirclePlugin, self).create_port_db(context, port)
|
||||
return self._make_port_dict(db_port)
|
||||
self._ensure_default_security_group_on_port(context, port)
|
||||
sgids = self._get_security_groups_on_port(context, port)
|
||||
result = self._make_port_dict(db_port)
|
||||
self._process_port_create_security_group(context, result, sgids)
|
||||
return result
|
||||
|
||||
def update_port(self, context, port_id, port):
|
||||
# TODO(zhiyuan) handle bottom port update
|
||||
|
@ -419,6 +423,9 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||
t_constants.RT_SUBNET) for ip in res['fixed_ips']]
|
||||
entries.append((res['network_id'], t_constants.RT_NETWORK))
|
||||
entries.append((res['id'], t_constants.RT_PORT))
|
||||
if res['security_groups']:
|
||||
for sg_id in res['security_groups']:
|
||||
entries.append((sg_id, t_constants.RT_SG))
|
||||
|
||||
for resource_id, resource_type in entries:
|
||||
if db_api.get_bottom_id_by_top_id_pod_name(
|
||||
|
@ -441,6 +448,8 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||
admin_context, res['network_id'],
|
||||
interfaces[0]['device_id'], pod['pod_id'])
|
||||
|
||||
self.xjob_handler.configure_security_group_rules(t_ctx,
|
||||
res['tenant_id'])
|
||||
return res
|
||||
|
||||
def delete_port(self, context, port_id, l3_port_check=True):
|
||||
|
@ -916,10 +925,10 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||
def _get_bridge_subnet_pool_id(self, t_ctx, q_ctx, project_id, pod, is_ew):
|
||||
if is_ew:
|
||||
pool_name = t_constants.ew_bridge_subnet_pool_name
|
||||
pool_cidr = '100.0.0.0/9'
|
||||
pool_cidr = cfg.CONF.client.ew_bridge_cidr
|
||||
else:
|
||||
pool_name = t_constants.ns_bridge_subnet_pool_name
|
||||
pool_cidr = '100.128.0.0/9'
|
||||
pool_cidr = cfg.CONF.client.ns_bridge_cidr
|
||||
pool_ele = {'id': pool_name}
|
||||
body = {'subnetpool': {'tenant_id': project_id,
|
||||
'name': pool_name,
|
||||
|
|
|
@ -567,3 +567,18 @@ class NetworkHelper(object):
|
|||
return getattr(self.call_obj, 'get_%s' % _type)(q_ctx, _id)
|
||||
else:
|
||||
return getattr(self._get_client(), 'get_%ss' % _type)(t_ctx, _id)
|
||||
|
||||
@staticmethod
|
||||
def get_create_sg_rule_body(rule, sg_id, ip=None):
|
||||
ip = ip or rule['remote_ip_prefix']
|
||||
# if ip is passed, this is a extended rule for remote group
|
||||
return {'security_group_rule': {
|
||||
'tenant_id': rule['tenant_id'],
|
||||
'remote_group_id': None,
|
||||
'direction': rule['direction'],
|
||||
'remote_ip_prefix': ip,
|
||||
'protocol': rule.get('protocol'),
|
||||
'ethertype': rule['ethertype'],
|
||||
'port_range_max': rule.get('port_range_max'),
|
||||
'port_range_min': rule.get('port_range_min'),
|
||||
'security_group_id': sg_id}}
|
||||
|
|
|
@ -22,6 +22,7 @@ import neutron_lib.constants as q_constants
|
|||
import neutron_lib.exceptions as q_exceptions
|
||||
|
||||
from neutron.common import utils
|
||||
import neutron.extensions.securitygroup as ext_sg
|
||||
from neutron.plugins.ml2 import plugin
|
||||
|
||||
from tricircle.common import client # noqa
|
||||
|
@ -381,6 +382,8 @@ class TricirclePlugin(plugin.Ml2Plugin):
|
|||
for field in ('name', 'device_id'):
|
||||
if port_body.get(field):
|
||||
t_port[field] = port_body[field]
|
||||
|
||||
self._handle_security_group(t_ctx, context, t_port)
|
||||
b_port = self.core_plugin.create_port(context, {'port': t_port})
|
||||
return b_port
|
||||
|
||||
|
@ -408,6 +411,7 @@ class TricirclePlugin(plugin.Ml2Plugin):
|
|||
raise q_exceptions.PortNotFound(port_id=_id)
|
||||
self._ensure_network_subnet(context, t_port)
|
||||
self._adapt_port_body_for_call(t_port)
|
||||
self._handle_security_group(t_ctx, context, t_port)
|
||||
b_port = self.core_plugin.create_port(context, {'port': t_port})
|
||||
return self._fields(b_port, fields)
|
||||
|
||||
|
@ -446,6 +450,7 @@ class TricirclePlugin(plugin.Ml2Plugin):
|
|||
for port in t_ports:
|
||||
self._ensure_network_subnet(context, port)
|
||||
self._adapt_port_body_for_call(port)
|
||||
self._handle_security_group(t_ctx, context, port)
|
||||
b_port = self.core_plugin.create_port(context,
|
||||
{'port': port})
|
||||
b_ports.append(self._fields(b_port, fields))
|
||||
|
@ -455,3 +460,68 @@ class TricirclePlugin(plugin.Ml2Plugin):
|
|||
t_ctx = t_context.get_context_from_neutron_context(context)
|
||||
self.neutron_handle.handle_delete(t_ctx, t_constants.RT_PORT, _id)
|
||||
self.core_plugin.delete_port(context, _id, l3_port_check)
|
||||
|
||||
def _handle_security_group(self, t_ctx, q_ctx, port):
|
||||
if not port['security_groups']:
|
||||
raw_client = self.neutron_handle._get_client(t_ctx)
|
||||
params = {'name': 'default'}
|
||||
t_sgs = raw_client.list_security_groups(
|
||||
**params)['security_groups']
|
||||
if t_sgs:
|
||||
port['security_groups'] = [t_sgs[0]['id']]
|
||||
if port['security_groups'] is q_constants.ATTR_NOT_SPECIFIED:
|
||||
return
|
||||
for sg_id in port['security_groups']:
|
||||
self.get_security_group(q_ctx, sg_id)
|
||||
|
||||
def get_security_group(self, context, _id, fields=None, tenant_id=None):
|
||||
try:
|
||||
return self.core_plugin.get_security_group(
|
||||
context, _id, fields, tenant_id)
|
||||
except q_exceptions.NotFound:
|
||||
t_ctx = t_context.get_context_from_neutron_context(context)
|
||||
t_sg = self.neutron_handle.handle_get(t_ctx,
|
||||
'security_group', _id)
|
||||
if not t_sg:
|
||||
raise ext_sg.SecurityGroupNotFound(id=_id)
|
||||
self.core_plugin.create_security_group(context,
|
||||
{'security_group': t_sg})
|
||||
return self.core_plugin.get_security_group(
|
||||
context, _id, fields, tenant_id)
|
||||
|
||||
def get_security_groups(self, context, filters=None, fields=None,
|
||||
sorts=None, limit=None, marker=None,
|
||||
page_reverse=False, default_sg=False):
|
||||
# if id is not specified in the filter, we just return security group
|
||||
# data in local Neutron server, otherwise id is specified, we need to
|
||||
# retrieve network data from central Neutron server and create network
|
||||
# which doesn't exist in local Neutron server.
|
||||
if not filters or 'id' not in filters:
|
||||
return self.core_plugin.get_security_groups(
|
||||
context, filters, fields, sorts, limit, marker, page_reverse,
|
||||
default_sg)
|
||||
|
||||
b_sgs = self.core_plugin.get_security_groups(
|
||||
context, filters, fields, sorts, limit, marker, page_reverse,
|
||||
default_sg)
|
||||
if len(b_sgs) == len(filters['id']):
|
||||
return b_sgs
|
||||
|
||||
t_ctx = t_context.get_context_from_neutron_context(context)
|
||||
raw_client = self.neutron_handle._get_client(t_ctx)
|
||||
params = self._construct_params(filters, sorts, limit, marker,
|
||||
page_reverse)
|
||||
t_sgs = raw_client.list_security_groups(**params)['security_groups']
|
||||
|
||||
t_id_set = set([sg['id'] for sg in t_sgs])
|
||||
b_id_set = set([sg['id'] for sg in b_sgs])
|
||||
missing_id_set = t_id_set - b_id_set
|
||||
if missing_id_set:
|
||||
missing_sgs = [sg for sg in t_sgs if (
|
||||
sg['id'] in missing_id_set)]
|
||||
for sg in missing_sgs:
|
||||
b_sg = self.core_plugin.create_security_group(
|
||||
context, {'security_group': sg})
|
||||
b_sgs.append(self.core_plugin.get_security_group(
|
||||
context, b_sg['id'], fields))
|
||||
return b_sgs
|
||||
|
|
|
@ -33,14 +33,17 @@ import tricircle.network.local_plugin as plugin
|
|||
TOP_NETS = []
|
||||
TOP_SUBNETS = []
|
||||
TOP_PORTS = []
|
||||
TOP_SGS = []
|
||||
BOTTOM_NETS = []
|
||||
BOTTOM_SUBNETS = []
|
||||
BOTTOM_PORTS = []
|
||||
RES_LIST = [TOP_NETS, TOP_SUBNETS, TOP_PORTS,
|
||||
BOTTOM_NETS, BOTTOM_SUBNETS, BOTTOM_PORTS]
|
||||
BOTTOM_SGS = []
|
||||
RES_LIST = [TOP_NETS, TOP_SUBNETS, TOP_PORTS, TOP_SGS,
|
||||
BOTTOM_NETS, BOTTOM_SUBNETS, BOTTOM_PORTS, BOTTOM_SGS]
|
||||
RES_MAP = {'network': {True: TOP_NETS, False: BOTTOM_NETS},
|
||||
'subnet': {True: TOP_SUBNETS, False: BOTTOM_SUBNETS},
|
||||
'port': {True: TOP_PORTS, False: BOTTOM_PORTS}}
|
||||
'port': {True: TOP_PORTS, False: BOTTOM_PORTS},
|
||||
'security_group': {True: TOP_SGS, False: BOTTOM_SGS}}
|
||||
|
||||
|
||||
def create_resource(_type, is_top, body):
|
||||
|
@ -117,6 +120,14 @@ class FakeCorePlugin(object):
|
|||
limit=None, marker=None, page_reverse=False):
|
||||
return list_resource('port', False, filters)
|
||||
|
||||
def create_security_group(self, context, security_group, default_sg=False):
|
||||
create_resource('security_group', False,
|
||||
security_group['security_group'])
|
||||
return security_group['security_group']
|
||||
|
||||
def get_security_group(self, context, _id, fields=None, tenant_id=None):
|
||||
return get_resource('security_group', False, _id)
|
||||
|
||||
|
||||
class FakeSession(object):
|
||||
class WithWrapper(object):
|
||||
|
@ -176,6 +187,10 @@ class FakeClient(object):
|
|||
ports.append(copy.deepcopy(port))
|
||||
return {'ports': ports}
|
||||
|
||||
def list_security_groups(self, **kwargs):
|
||||
return {'security_groups': list_resource('security_group',
|
||||
True, kwargs)}
|
||||
|
||||
|
||||
class FakeNeutronHandle(object):
|
||||
def _get_client(self, context):
|
||||
|
@ -210,6 +225,7 @@ class PluginTest(unittest.TestCase):
|
|||
network_id = uuidutils.generate_uuid()
|
||||
subnet_id = uuidutils.generate_uuid()
|
||||
port_id = uuidutils.generate_uuid()
|
||||
sg_id = uuidutils.generate_uuid()
|
||||
t_net = {'id': network_id,
|
||||
'tenant_id': self.tenant_id,
|
||||
'name': 'net1',
|
||||
|
@ -235,10 +251,25 @@ class PluginTest(unittest.TestCase):
|
|||
'fixed_ips': [{'subnet_id': subnet_id,
|
||||
'ip_address': '10.0.1.2'}],
|
||||
'binding:profile': {}}
|
||||
t_sg = {
|
||||
'id': sg_id,
|
||||
'tenant_id': self.tenant_id,
|
||||
'name': 'default',
|
||||
'security_group_rules': [{
|
||||
'remote_group_id': sg_id,
|
||||
'direction': 'ingress',
|
||||
'remote_ip_prefix': None,
|
||||
'protocol': None,
|
||||
'ethertype': 'IPv4',
|
||||
'port_range_max': -1,
|
||||
'port_range_min': -1,
|
||||
'security_group_id': sg_id}]
|
||||
}
|
||||
TOP_NETS.append(t_net)
|
||||
TOP_SUBNETS.append(t_subnet)
|
||||
TOP_PORTS.append(t_port)
|
||||
return t_net, t_subnet, t_port
|
||||
TOP_SGS.append(t_sg)
|
||||
return t_net, t_subnet, t_port, t_sg
|
||||
|
||||
def _validate(self, net, subnet, port):
|
||||
b_net = self.plugin.get_network(self.context, net['id'])
|
||||
|
@ -273,13 +304,13 @@ class PluginTest(unittest.TestCase):
|
|||
|
||||
@patch.object(t_context, 'get_context_from_neutron_context', new=mock.Mock)
|
||||
def test_get_network(self):
|
||||
t_net, t_subnet, t_port = self._prepare_resource()
|
||||
t_net, t_subnet, t_port, _ = self._prepare_resource()
|
||||
self._validate(t_net, t_subnet, t_port)
|
||||
|
||||
@patch.object(t_context, 'get_context_from_neutron_context', new=mock.Mock)
|
||||
def test_get_networks(self):
|
||||
t_net1, t_subnet1, t_port1 = self._prepare_resource()
|
||||
t_net2, t_subnet2, t_port2 = self._prepare_resource()
|
||||
t_net1, t_subnet1, t_port1, _ = self._prepare_resource()
|
||||
t_net2, t_subnet2, t_port2, _ = self._prepare_resource()
|
||||
self.plugin.get_networks(self.context,
|
||||
{'id': [t_net1['id'], t_net2['id'],
|
||||
'fake_net_id']})
|
||||
|
@ -288,10 +319,11 @@ class PluginTest(unittest.TestCase):
|
|||
|
||||
@patch.object(t_context, 'get_context_from_neutron_context', new=mock.Mock)
|
||||
def test_create_port(self):
|
||||
t_net, t_subnet, t_port = self._prepare_resource()
|
||||
t_net, t_subnet, t_port, _ = self._prepare_resource()
|
||||
port = {
|
||||
'port': {'network_id': t_net['id'],
|
||||
'fixed_ips': q_constants.ATTR_NOT_SPECIFIED}
|
||||
'fixed_ips': q_constants.ATTR_NOT_SPECIFIED,
|
||||
'security_groups': []}
|
||||
}
|
||||
t_port = self.plugin.create_port(self.context, port)
|
||||
b_port = get_resource('port', False, t_port['id'])
|
||||
|
@ -299,7 +331,7 @@ class PluginTest(unittest.TestCase):
|
|||
|
||||
@patch.object(t_context, 'get_context_from_neutron_context', new=mock.Mock)
|
||||
def test_create_port_ip_specified(self):
|
||||
t_net, t_subnet, t_port = self._prepare_resource()
|
||||
t_net, t_subnet, t_port, t_sg = self._prepare_resource()
|
||||
port_body = {
|
||||
'port': {'network_id': t_net['id'],
|
||||
'fixed_ips': [{'ip_address': '10.0.1.4'}]}
|
||||
|
@ -315,14 +347,15 @@ class PluginTest(unittest.TestCase):
|
|||
'mac_address': 'fa:16:3e:96:41:04',
|
||||
'fixed_ips': [{'subnet_id': t_subnet['id'],
|
||||
'ip_address': '10.0.1.4'}],
|
||||
'binding:profile': {}}
|
||||
'binding:profile': {},
|
||||
'security_groups': [t_sg['id']]}
|
||||
TOP_PORTS.append(t_port)
|
||||
b_port = self.plugin.create_port(self.context, port_body)
|
||||
self.assertDictEqual(t_port, b_port)
|
||||
|
||||
@patch.object(t_context, 'get_context_from_neutron_context', new=mock.Mock)
|
||||
def test_get_port(self):
|
||||
t_net, t_subnet, t_port = self._prepare_resource()
|
||||
t_net, t_subnet, t_port, _ = self._prepare_resource()
|
||||
port_id = uuidutils.generate_uuid()
|
||||
t_port = {'id': port_id,
|
||||
'tenant_id': self.tenant_id,
|
||||
|
@ -331,7 +364,8 @@ class PluginTest(unittest.TestCase):
|
|||
'mac_address': 'fa:16:3e:96:41:04',
|
||||
'fixed_ips': [{'subnet_id': t_subnet['id'],
|
||||
'ip_address': '10.0.1.4'}],
|
||||
'binding:profile': {}}
|
||||
'binding:profile': {},
|
||||
'security_groups': []}
|
||||
TOP_PORTS.append(t_port)
|
||||
t_port = self.plugin.get_port(self.context, port_id)
|
||||
b_port = get_resource('port', False, t_port['id'])
|
||||
|
@ -339,7 +373,7 @@ class PluginTest(unittest.TestCase):
|
|||
|
||||
@patch.object(t_context, 'get_context_from_neutron_context', new=mock.Mock)
|
||||
def test_get_ports(self):
|
||||
t_net, t_subnet, t_port = self._prepare_resource()
|
||||
t_net, t_subnet, t_port, t_sg = self._prepare_resource()
|
||||
t_ports = []
|
||||
for i in (4, 5):
|
||||
port_id = uuidutils.generate_uuid()
|
||||
|
@ -350,7 +384,8 @@ class PluginTest(unittest.TestCase):
|
|||
'mac_address': 'fa:16:3e:96:41:04',
|
||||
'fixed_ips': [{'subnet_id': t_subnet['id'],
|
||||
'ip_address': '10.0.1.%d' % i}],
|
||||
'binding:profile': {}}
|
||||
'binding:profile': {},
|
||||
'security_groups': [t_sg['id']]}
|
||||
TOP_PORTS.append(t_port)
|
||||
t_ports.append(t_port)
|
||||
self.plugin.get_ports(self.context,
|
||||
|
|
|
@ -30,34 +30,43 @@ from tricircle.xjob import xmanager
|
|||
from tricircle.xjob import xservice
|
||||
|
||||
|
||||
TOP_NETWORK = []
|
||||
BOTTOM1_NETWORK = []
|
||||
BOTTOM2_NETWORK = []
|
||||
TOP_SUBNET = []
|
||||
BOTTOM1_SUBNET = []
|
||||
BOTTOM2_SUBNET = []
|
||||
BOTTOM1_PORT = []
|
||||
BOTTOM2_PORT = []
|
||||
BOTTOM1_ROUTER = []
|
||||
BOTTOM2_ROUTER = []
|
||||
RES_LIST = [BOTTOM1_NETWORK, BOTTOM2_NETWORK, BOTTOM1_SUBNET, BOTTOM2_SUBNET,
|
||||
BOTTOM1_PORT, BOTTOM2_PORT, BOTTOM1_ROUTER, BOTTOM2_ROUTER]
|
||||
RES_MAP = {'pod_1': {'network': BOTTOM1_NETWORK,
|
||||
TOP_SG = []
|
||||
BOTTOM1_SG = []
|
||||
BOTTOM2_SG = []
|
||||
RES_LIST = [TOP_NETWORK, BOTTOM1_NETWORK, BOTTOM2_NETWORK, TOP_SUBNET,
|
||||
BOTTOM1_SUBNET, BOTTOM2_SUBNET, BOTTOM1_PORT, BOTTOM2_PORT,
|
||||
BOTTOM1_ROUTER, BOTTOM2_ROUTER, TOP_SG, BOTTOM1_SG, BOTTOM2_SG]
|
||||
RES_MAP = {'top': {'network': TOP_NETWORK,
|
||||
'subnet': TOP_SUBNET,
|
||||
'security_group': TOP_SG},
|
||||
'pod_1': {'network': BOTTOM1_NETWORK,
|
||||
'subnet': BOTTOM1_SUBNET,
|
||||
'port': BOTTOM1_PORT,
|
||||
'router': BOTTOM1_ROUTER},
|
||||
'router': BOTTOM1_ROUTER,
|
||||
'security_group': BOTTOM1_SG},
|
||||
'pod_2': {'network': BOTTOM2_NETWORK,
|
||||
'subnet': BOTTOM2_SUBNET,
|
||||
'port': BOTTOM2_PORT,
|
||||
'router': BOTTOM2_ROUTER}}
|
||||
'router': BOTTOM2_ROUTER,
|
||||
'security_group': BOTTOM2_SG}}
|
||||
|
||||
|
||||
class FakeXManager(xmanager.XManager):
|
||||
def __init__(self):
|
||||
self.clients = {'pod_1': FakeClient('pod_1'),
|
||||
self.clients = {'top': FakeClient(),
|
||||
'pod_1': FakeClient('pod_1'),
|
||||
'pod_2': FakeClient('pod_2')}
|
||||
|
||||
def _get_client(self, pod_name=None):
|
||||
return self.clients[pod_name]
|
||||
|
||||
|
||||
class FakeClient(object):
|
||||
def __init__(self, pod_name=None):
|
||||
|
@ -85,6 +94,9 @@ class FakeClient(object):
|
|||
def list_ports(self, cxt, filters=None):
|
||||
return self.list_resources('port', cxt, filters)
|
||||
|
||||
def list_subnets(self, cxt, filters=None):
|
||||
return self.list_resources('subnet', cxt, filters)
|
||||
|
||||
def get_subnets(self, cxt, subnet_id):
|
||||
return self.list_resources(
|
||||
'subnet', cxt,
|
||||
|
@ -93,6 +105,20 @@ class FakeClient(object):
|
|||
def update_routers(self, cxt, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def list_security_groups(self, cxt, filters=None):
|
||||
return self.list_resources('security_group', cxt, filters)
|
||||
|
||||
def get_security_groups(self, cxt, sg_id):
|
||||
return self.list_resources(
|
||||
'security_group', cxt,
|
||||
[{'key': 'id', 'comparator': 'eq', 'value': sg_id}])[0]
|
||||
|
||||
def delete_security_group_rules(self, cxt, sg_id):
|
||||
pass
|
||||
|
||||
def create_security_group_rules(self, cxt, *args, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
class XManagerTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
|
@ -106,6 +132,7 @@ class XManagerTest(unittest.TestCase):
|
|||
cfg.CONF.register_opt(opt)
|
||||
self.context = context.Context()
|
||||
self.xmanager = FakeXManager()
|
||||
self.xmanager = FakeXManager()
|
||||
|
||||
@patch.object(FakeClient, 'update_routers')
|
||||
def test_configure_extra_routes(self, mock_update):
|
||||
|
@ -207,6 +234,77 @@ class XManagerTest(unittest.TestCase):
|
|||
called = called and (mock_update.call_args_list[0] == calls[0])
|
||||
self.assertTrue(called)
|
||||
|
||||
@patch.object(FakeClient, 'delete_security_group_rules')
|
||||
@patch.object(FakeClient, 'create_security_group_rules')
|
||||
def test_configure_security_group_rules(self, mock_create, mock_delete):
|
||||
project_id = uuidutils.generate_uuid()
|
||||
sg_id = uuidutils.generate_uuid()
|
||||
sg_rule_id = uuidutils.generate_uuid()
|
||||
sg = {'id': sg_id,
|
||||
'tenant_id': project_id,
|
||||
'name': 'default',
|
||||
'security_group_rules': [{
|
||||
'id': sg_rule_id,
|
||||
'remote_group_id': sg_id,
|
||||
'direction': 'ingress',
|
||||
'remote_ip_prefix': None,
|
||||
'protocol': None,
|
||||
'ethertype': 'IPv4',
|
||||
'port_range_max': -1,
|
||||
'port_range_min': -1,
|
||||
'security_group_id': sg_id}]}
|
||||
RES_MAP['top']['security_group'].append(sg)
|
||||
|
||||
for i in xrange(1, 3):
|
||||
pod_dict = {'pod_id': 'pod_id_%d' % i,
|
||||
'pod_name': 'pod_%d' % i,
|
||||
'az_name': 'az_name_%d' % i}
|
||||
db_api.create_pod(self.context, pod_dict)
|
||||
|
||||
network = {'id': 'network_%d_id' % i,
|
||||
'tenant_id': project_id}
|
||||
subnet = {'id': 'subnet_%d_id' % i,
|
||||
'network_id': network['id'],
|
||||
'cidr': '10.0.%d.0/24' % i,
|
||||
'gateway_ip': '10.0.%d.1' % i,
|
||||
'tenant_id': project_id}
|
||||
RES_MAP['top']['network'].append(network)
|
||||
RES_MAP['top']['subnet'].append(subnet)
|
||||
|
||||
pod_name = 'pod_%d' % i
|
||||
RES_MAP[pod_name]['security_group'].append(sg)
|
||||
route = {'top_id': sg_id, 'bottom_id': sg_id,
|
||||
'pod_id': pod_dict['pod_id'],
|
||||
'resource_type': 'security_group'}
|
||||
with self.context.session.begin():
|
||||
core.create_resource(self.context, models.ResourceRouting,
|
||||
route)
|
||||
|
||||
self.xmanager.configure_security_group_rules(
|
||||
self.context, payload={'seg_rule_setup': project_id})
|
||||
|
||||
calls = [mock.call(self.context, sg_rule_id)]
|
||||
mock_delete.assert_has_calls(calls)
|
||||
calls = [mock.call(self.context,
|
||||
{'security_group_rules': [
|
||||
{'remote_group_id': None,
|
||||
'direction': 'ingress',
|
||||
'remote_ip_prefix': '10.0.1.0/24',
|
||||
'protocol': None,
|
||||
'ethertype': 'IPv4',
|
||||
'port_range_max': -1,
|
||||
'port_range_min': -1,
|
||||
'security_group_id': sg_id},
|
||||
{'remote_group_id': None,
|
||||
'direction': 'ingress',
|
||||
'remote_ip_prefix': '10.0.2.0/24',
|
||||
'protocol': None,
|
||||
'ethertype': 'IPv4',
|
||||
'port_range_max': -1,
|
||||
'port_range_min': -1,
|
||||
'security_group_id': sg_id}]})]
|
||||
mock_create.assert_has_calls(calls)
|
||||
|
||||
def test_job_handle(self):
|
||||
@xmanager._job_handle('fake_resource')
|
||||
def fake_handle(self, ctx, payload):
|
||||
|
|
|
@ -24,6 +24,7 @@ from oslo_log import log as logging
|
|||
import oslo_messaging as messaging
|
||||
from oslo_service import periodic_task
|
||||
|
||||
import neutron_lib.exceptions as q_exceptions
|
||||
import neutronclient.common.exceptions as q_cli_exceptions
|
||||
|
||||
from tricircle.common import client
|
||||
|
@ -150,7 +151,8 @@ class XManager(PeriodicTasks):
|
|||
self.job_handles = {
|
||||
constants.JT_ROUTER: self.configure_extra_routes,
|
||||
constants.JT_ROUTER_SETUP: self.setup_bottom_router,
|
||||
constants.JT_PORT_DELETE: self.delete_server_port}
|
||||
constants.JT_PORT_DELETE: self.delete_server_port,
|
||||
constants.JT_SEG_RULE_SETUP: self.configure_security_group_rules}
|
||||
self.helper = helper.NetworkHelper()
|
||||
self.xjob_handler = xrpcapi.XJobAPI()
|
||||
super(XManager, self).__init__()
|
||||
|
@ -611,8 +613,8 @@ class XManager(PeriodicTasks):
|
|||
router_ips_map[b_router_ids[i]] = {}
|
||||
for b_interface in b_interfaces:
|
||||
ip = b_interface['fixed_ips'][0]['ip_address']
|
||||
ew_bridge_cidr = '100.0.0.0/9'
|
||||
ns_bridge_cidr = '100.128.0.0/9'
|
||||
ew_bridge_cidr = CONF.client.ew_bridge_cidr
|
||||
ns_bridge_cidr = CONF.client.ns_bridge_cidr
|
||||
if netaddr.IPAddress(ip) in netaddr.IPNetwork(ew_bridge_cidr):
|
||||
router_bridge_ip_map[b_router_ids[i]] = ip
|
||||
continue
|
||||
|
@ -655,3 +657,108 @@ class XManager(PeriodicTasks):
|
|||
def delete_server_port(self, ctx, payload):
|
||||
t_port_id = payload[constants.JT_PORT_DELETE]
|
||||
self._get_client().delete_ports(ctx, t_port_id)
|
||||
|
||||
@staticmethod
|
||||
def _safe_create_security_group_rule(context, client, body):
|
||||
try:
|
||||
client.create_security_group_rules(context, body)
|
||||
except q_exceptions.Conflict:
|
||||
return
|
||||
|
||||
@staticmethod
|
||||
def _safe_delete_security_group_rule(context, client, _id):
|
||||
try:
|
||||
client.delete_security_group_rules(context, _id)
|
||||
except q_exceptions.NotFound:
|
||||
return
|
||||
|
||||
@staticmethod
|
||||
def _construct_bottom_rule(rule, sg_id, ip=None):
|
||||
ip = ip or rule['remote_ip_prefix']
|
||||
# if ip is passed, this is a extended rule for remote group
|
||||
return {'remote_group_id': None,
|
||||
'direction': rule['direction'],
|
||||
'remote_ip_prefix': ip,
|
||||
'protocol': rule.get('protocol'),
|
||||
'ethertype': rule['ethertype'],
|
||||
'port_range_max': rule.get('port_range_max'),
|
||||
'port_range_min': rule.get('port_range_min'),
|
||||
'security_group_id': sg_id}
|
||||
|
||||
@staticmethod
|
||||
def _compare_rule(rule1, rule2):
|
||||
for key in ('direction', 'remote_ip_prefix', 'protocol', 'ethertype',
|
||||
'port_range_max', 'port_range_min'):
|
||||
if rule1[key] != rule2[key]:
|
||||
return False
|
||||
return True
|
||||
|
||||
@_job_handle(constants.JT_SEG_RULE_SETUP)
|
||||
def configure_security_group_rules(self, ctx, payload):
|
||||
project_id = payload[constants.JT_SEG_RULE_SETUP]
|
||||
top_client = self._get_client()
|
||||
sg_filters = [{'key': 'tenant_id', 'comparator': 'eq',
|
||||
'value': project_id}]
|
||||
top_sgs = top_client.list_security_groups(ctx, sg_filters)
|
||||
for top_sg in top_sgs:
|
||||
new_b_rules = []
|
||||
for t_rule in top_sg['security_group_rules']:
|
||||
if not t_rule['remote_group_id']:
|
||||
# leave sg_id empty here
|
||||
new_b_rules.append(
|
||||
self._construct_bottom_rule(t_rule, ''))
|
||||
continue
|
||||
if top_sg['name'] != 'default':
|
||||
# currently we only handle rules containing remote_group_id
|
||||
# for default security group
|
||||
continue
|
||||
if t_rule['ethertype'] != 'IPv4':
|
||||
continue
|
||||
subnets = top_client.list_subnets(
|
||||
ctx, [{'key': 'tenant_id', 'comparator': 'eq',
|
||||
'value': project_id}])
|
||||
ew_bridge_ip_net = netaddr.IPNetwork(
|
||||
CONF.client.ew_bridge_cidr)
|
||||
ns_bridge_ip_net = netaddr.IPNetwork(
|
||||
CONF.client.ns_bridge_cidr)
|
||||
for subnet in subnets:
|
||||
ip_net = netaddr.IPNetwork(subnet['cidr'])
|
||||
if ip_net in ew_bridge_ip_net or (
|
||||
ip_net in ns_bridge_ip_net):
|
||||
continue
|
||||
# leave sg_id empty here
|
||||
new_b_rules.append(
|
||||
self._construct_bottom_rule(t_rule, '',
|
||||
subnet['cidr']))
|
||||
|
||||
mappings = db_api.get_bottom_mappings_by_top_id(
|
||||
ctx, top_sg['id'], constants.RT_SG)
|
||||
for pod, b_sg_id in mappings:
|
||||
client = self._get_client(pod['pod_name'])
|
||||
b_sg = client.get_security_groups(ctx, b_sg_id)
|
||||
add_rules = []
|
||||
del_rules = []
|
||||
match_index = set()
|
||||
for b_rule in b_sg['security_group_rules']:
|
||||
match = False
|
||||
for i, rule in enumerate(new_b_rules):
|
||||
if self._compare_rule(b_rule, rule):
|
||||
match = True
|
||||
match_index.add(i)
|
||||
break
|
||||
if not match:
|
||||
del_rules.append(b_rule)
|
||||
for i, rule in enumerate(new_b_rules):
|
||||
if i not in match_index:
|
||||
add_rules.append(rule)
|
||||
|
||||
for del_rule in del_rules:
|
||||
self._safe_delete_security_group_rule(
|
||||
ctx, client, del_rule['id'])
|
||||
if add_rules:
|
||||
rule_body = {'security_group_rules': []}
|
||||
for add_rule in add_rules:
|
||||
add_rule['security_group_id'] = b_sg_id
|
||||
rule_body['security_group_rules'].append(add_rule)
|
||||
self._safe_create_security_group_rule(
|
||||
ctx, client, rule_body)
|
||||
|
|
Loading…
Reference in New Issue