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',
|
cfg.StrOpt('admin_tenant_domain_name',
|
||||||
default='Default',
|
default='Default',
|
||||||
help='tenant domain name of admin account, needed when'
|
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')
|
client_opt_group = cfg.OptGroup('client')
|
||||||
cfg.CONF.register_group(client_opt_group)
|
cfg.CONF.register_group(client_opt_group)
|
||||||
|
|
|
@ -79,6 +79,7 @@ PROFILE_REGION = 'region'
|
||||||
JT_ROUTER = 'router'
|
JT_ROUTER = 'router'
|
||||||
JT_ROUTER_SETUP = 'router_setup'
|
JT_ROUTER_SETUP = 'router_setup'
|
||||||
JT_PORT_DELETE = 'port_delete'
|
JT_PORT_DELETE = 'port_delete'
|
||||||
|
JT_SEG_RULE_SETUP = 'seg_rule_setup'
|
||||||
|
|
||||||
# network type
|
# network type
|
||||||
NT_LOCAL = 'local'
|
NT_LOCAL = 'local'
|
||||||
|
|
|
@ -94,3 +94,8 @@ class XJobAPI(object):
|
||||||
self.client.prepare(exchange='openstack').cast(
|
self.client.prepare(exchange='openstack').cast(
|
||||||
ctxt, 'delete_server_port',
|
ctxt, 'delete_server_port',
|
||||||
payload={constants.JT_PORT_DELETE: port_id})
|
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)
|
gateway_port_body)
|
||||||
return super(TricirclePlugin, self).get_port(context, t_gateway_id)
|
return super(TricirclePlugin, self).get_port(context, t_gateway_id)
|
||||||
db_port = super(TricirclePlugin, self).create_port_db(context, port)
|
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):
|
def update_port(self, context, port_id, port):
|
||||||
# TODO(zhiyuan) handle bottom port update
|
# 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']]
|
t_constants.RT_SUBNET) for ip in res['fixed_ips']]
|
||||||
entries.append((res['network_id'], t_constants.RT_NETWORK))
|
entries.append((res['network_id'], t_constants.RT_NETWORK))
|
||||||
entries.append((res['id'], t_constants.RT_PORT))
|
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:
|
for resource_id, resource_type in entries:
|
||||||
if db_api.get_bottom_id_by_top_id_pod_name(
|
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'],
|
admin_context, res['network_id'],
|
||||||
interfaces[0]['device_id'], pod['pod_id'])
|
interfaces[0]['device_id'], pod['pod_id'])
|
||||||
|
|
||||||
|
self.xjob_handler.configure_security_group_rules(t_ctx,
|
||||||
|
res['tenant_id'])
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def delete_port(self, context, port_id, l3_port_check=True):
|
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):
|
def _get_bridge_subnet_pool_id(self, t_ctx, q_ctx, project_id, pod, is_ew):
|
||||||
if is_ew:
|
if is_ew:
|
||||||
pool_name = t_constants.ew_bridge_subnet_pool_name
|
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:
|
else:
|
||||||
pool_name = t_constants.ns_bridge_subnet_pool_name
|
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}
|
pool_ele = {'id': pool_name}
|
||||||
body = {'subnetpool': {'tenant_id': project_id,
|
body = {'subnetpool': {'tenant_id': project_id,
|
||||||
'name': pool_name,
|
'name': pool_name,
|
||||||
|
|
|
@ -567,3 +567,18 @@ class NetworkHelper(object):
|
||||||
return getattr(self.call_obj, 'get_%s' % _type)(q_ctx, _id)
|
return getattr(self.call_obj, 'get_%s' % _type)(q_ctx, _id)
|
||||||
else:
|
else:
|
||||||
return getattr(self._get_client(), 'get_%ss' % _type)(t_ctx, _id)
|
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
|
import neutron_lib.exceptions as q_exceptions
|
||||||
|
|
||||||
from neutron.common import utils
|
from neutron.common import utils
|
||||||
|
import neutron.extensions.securitygroup as ext_sg
|
||||||
from neutron.plugins.ml2 import plugin
|
from neutron.plugins.ml2 import plugin
|
||||||
|
|
||||||
from tricircle.common import client # noqa
|
from tricircle.common import client # noqa
|
||||||
|
@ -381,6 +382,8 @@ class TricirclePlugin(plugin.Ml2Plugin):
|
||||||
for field in ('name', 'device_id'):
|
for field in ('name', 'device_id'):
|
||||||
if port_body.get(field):
|
if port_body.get(field):
|
||||||
t_port[field] = port_body[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})
|
b_port = self.core_plugin.create_port(context, {'port': t_port})
|
||||||
return b_port
|
return b_port
|
||||||
|
|
||||||
|
@ -408,6 +411,7 @@ class TricirclePlugin(plugin.Ml2Plugin):
|
||||||
raise q_exceptions.PortNotFound(port_id=_id)
|
raise q_exceptions.PortNotFound(port_id=_id)
|
||||||
self._ensure_network_subnet(context, t_port)
|
self._ensure_network_subnet(context, t_port)
|
||||||
self._adapt_port_body_for_call(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})
|
b_port = self.core_plugin.create_port(context, {'port': t_port})
|
||||||
return self._fields(b_port, fields)
|
return self._fields(b_port, fields)
|
||||||
|
|
||||||
|
@ -446,6 +450,7 @@ class TricirclePlugin(plugin.Ml2Plugin):
|
||||||
for port in t_ports:
|
for port in t_ports:
|
||||||
self._ensure_network_subnet(context, port)
|
self._ensure_network_subnet(context, port)
|
||||||
self._adapt_port_body_for_call(port)
|
self._adapt_port_body_for_call(port)
|
||||||
|
self._handle_security_group(t_ctx, context, port)
|
||||||
b_port = self.core_plugin.create_port(context,
|
b_port = self.core_plugin.create_port(context,
|
||||||
{'port': port})
|
{'port': port})
|
||||||
b_ports.append(self._fields(b_port, fields))
|
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)
|
t_ctx = t_context.get_context_from_neutron_context(context)
|
||||||
self.neutron_handle.handle_delete(t_ctx, t_constants.RT_PORT, _id)
|
self.neutron_handle.handle_delete(t_ctx, t_constants.RT_PORT, _id)
|
||||||
self.core_plugin.delete_port(context, _id, l3_port_check)
|
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_NETS = []
|
||||||
TOP_SUBNETS = []
|
TOP_SUBNETS = []
|
||||||
TOP_PORTS = []
|
TOP_PORTS = []
|
||||||
|
TOP_SGS = []
|
||||||
BOTTOM_NETS = []
|
BOTTOM_NETS = []
|
||||||
BOTTOM_SUBNETS = []
|
BOTTOM_SUBNETS = []
|
||||||
BOTTOM_PORTS = []
|
BOTTOM_PORTS = []
|
||||||
RES_LIST = [TOP_NETS, TOP_SUBNETS, TOP_PORTS,
|
BOTTOM_SGS = []
|
||||||
BOTTOM_NETS, BOTTOM_SUBNETS, BOTTOM_PORTS]
|
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},
|
RES_MAP = {'network': {True: TOP_NETS, False: BOTTOM_NETS},
|
||||||
'subnet': {True: TOP_SUBNETS, False: BOTTOM_SUBNETS},
|
'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):
|
def create_resource(_type, is_top, body):
|
||||||
|
@ -117,6 +120,14 @@ class FakeCorePlugin(object):
|
||||||
limit=None, marker=None, page_reverse=False):
|
limit=None, marker=None, page_reverse=False):
|
||||||
return list_resource('port', False, filters)
|
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 FakeSession(object):
|
||||||
class WithWrapper(object):
|
class WithWrapper(object):
|
||||||
|
@ -176,6 +187,10 @@ class FakeClient(object):
|
||||||
ports.append(copy.deepcopy(port))
|
ports.append(copy.deepcopy(port))
|
||||||
return {'ports': ports}
|
return {'ports': ports}
|
||||||
|
|
||||||
|
def list_security_groups(self, **kwargs):
|
||||||
|
return {'security_groups': list_resource('security_group',
|
||||||
|
True, kwargs)}
|
||||||
|
|
||||||
|
|
||||||
class FakeNeutronHandle(object):
|
class FakeNeutronHandle(object):
|
||||||
def _get_client(self, context):
|
def _get_client(self, context):
|
||||||
|
@ -210,6 +225,7 @@ class PluginTest(unittest.TestCase):
|
||||||
network_id = uuidutils.generate_uuid()
|
network_id = uuidutils.generate_uuid()
|
||||||
subnet_id = uuidutils.generate_uuid()
|
subnet_id = uuidutils.generate_uuid()
|
||||||
port_id = uuidutils.generate_uuid()
|
port_id = uuidutils.generate_uuid()
|
||||||
|
sg_id = uuidutils.generate_uuid()
|
||||||
t_net = {'id': network_id,
|
t_net = {'id': network_id,
|
||||||
'tenant_id': self.tenant_id,
|
'tenant_id': self.tenant_id,
|
||||||
'name': 'net1',
|
'name': 'net1',
|
||||||
|
@ -235,10 +251,25 @@ class PluginTest(unittest.TestCase):
|
||||||
'fixed_ips': [{'subnet_id': subnet_id,
|
'fixed_ips': [{'subnet_id': subnet_id,
|
||||||
'ip_address': '10.0.1.2'}],
|
'ip_address': '10.0.1.2'}],
|
||||||
'binding:profile': {}}
|
'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_NETS.append(t_net)
|
||||||
TOP_SUBNETS.append(t_subnet)
|
TOP_SUBNETS.append(t_subnet)
|
||||||
TOP_PORTS.append(t_port)
|
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):
|
def _validate(self, net, subnet, port):
|
||||||
b_net = self.plugin.get_network(self.context, net['id'])
|
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)
|
@patch.object(t_context, 'get_context_from_neutron_context', new=mock.Mock)
|
||||||
def test_get_network(self):
|
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)
|
self._validate(t_net, t_subnet, t_port)
|
||||||
|
|
||||||
@patch.object(t_context, 'get_context_from_neutron_context', new=mock.Mock)
|
@patch.object(t_context, 'get_context_from_neutron_context', new=mock.Mock)
|
||||||
def test_get_networks(self):
|
def test_get_networks(self):
|
||||||
t_net1, t_subnet1, t_port1 = self._prepare_resource()
|
t_net1, t_subnet1, t_port1, _ = self._prepare_resource()
|
||||||
t_net2, t_subnet2, t_port2 = self._prepare_resource()
|
t_net2, t_subnet2, t_port2, _ = self._prepare_resource()
|
||||||
self.plugin.get_networks(self.context,
|
self.plugin.get_networks(self.context,
|
||||||
{'id': [t_net1['id'], t_net2['id'],
|
{'id': [t_net1['id'], t_net2['id'],
|
||||||
'fake_net_id']})
|
'fake_net_id']})
|
||||||
|
@ -288,10 +319,11 @@ class PluginTest(unittest.TestCase):
|
||||||
|
|
||||||
@patch.object(t_context, 'get_context_from_neutron_context', new=mock.Mock)
|
@patch.object(t_context, 'get_context_from_neutron_context', new=mock.Mock)
|
||||||
def test_create_port(self):
|
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 = {
|
||||||
'port': {'network_id': t_net['id'],
|
'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)
|
t_port = self.plugin.create_port(self.context, port)
|
||||||
b_port = get_resource('port', False, t_port['id'])
|
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)
|
@patch.object(t_context, 'get_context_from_neutron_context', new=mock.Mock)
|
||||||
def test_create_port_ip_specified(self):
|
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_body = {
|
||||||
'port': {'network_id': t_net['id'],
|
'port': {'network_id': t_net['id'],
|
||||||
'fixed_ips': [{'ip_address': '10.0.1.4'}]}
|
'fixed_ips': [{'ip_address': '10.0.1.4'}]}
|
||||||
|
@ -315,14 +347,15 @@ class PluginTest(unittest.TestCase):
|
||||||
'mac_address': 'fa:16:3e:96:41:04',
|
'mac_address': 'fa:16:3e:96:41:04',
|
||||||
'fixed_ips': [{'subnet_id': t_subnet['id'],
|
'fixed_ips': [{'subnet_id': t_subnet['id'],
|
||||||
'ip_address': '10.0.1.4'}],
|
'ip_address': '10.0.1.4'}],
|
||||||
'binding:profile': {}}
|
'binding:profile': {},
|
||||||
|
'security_groups': [t_sg['id']]}
|
||||||
TOP_PORTS.append(t_port)
|
TOP_PORTS.append(t_port)
|
||||||
b_port = self.plugin.create_port(self.context, port_body)
|
b_port = self.plugin.create_port(self.context, port_body)
|
||||||
self.assertDictEqual(t_port, b_port)
|
self.assertDictEqual(t_port, b_port)
|
||||||
|
|
||||||
@patch.object(t_context, 'get_context_from_neutron_context', new=mock.Mock)
|
@patch.object(t_context, 'get_context_from_neutron_context', new=mock.Mock)
|
||||||
def test_get_port(self):
|
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()
|
port_id = uuidutils.generate_uuid()
|
||||||
t_port = {'id': port_id,
|
t_port = {'id': port_id,
|
||||||
'tenant_id': self.tenant_id,
|
'tenant_id': self.tenant_id,
|
||||||
|
@ -331,7 +364,8 @@ class PluginTest(unittest.TestCase):
|
||||||
'mac_address': 'fa:16:3e:96:41:04',
|
'mac_address': 'fa:16:3e:96:41:04',
|
||||||
'fixed_ips': [{'subnet_id': t_subnet['id'],
|
'fixed_ips': [{'subnet_id': t_subnet['id'],
|
||||||
'ip_address': '10.0.1.4'}],
|
'ip_address': '10.0.1.4'}],
|
||||||
'binding:profile': {}}
|
'binding:profile': {},
|
||||||
|
'security_groups': []}
|
||||||
TOP_PORTS.append(t_port)
|
TOP_PORTS.append(t_port)
|
||||||
t_port = self.plugin.get_port(self.context, port_id)
|
t_port = self.plugin.get_port(self.context, port_id)
|
||||||
b_port = get_resource('port', False, t_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)
|
@patch.object(t_context, 'get_context_from_neutron_context', new=mock.Mock)
|
||||||
def test_get_ports(self):
|
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 = []
|
t_ports = []
|
||||||
for i in (4, 5):
|
for i in (4, 5):
|
||||||
port_id = uuidutils.generate_uuid()
|
port_id = uuidutils.generate_uuid()
|
||||||
|
@ -350,7 +384,8 @@ class PluginTest(unittest.TestCase):
|
||||||
'mac_address': 'fa:16:3e:96:41:04',
|
'mac_address': 'fa:16:3e:96:41:04',
|
||||||
'fixed_ips': [{'subnet_id': t_subnet['id'],
|
'fixed_ips': [{'subnet_id': t_subnet['id'],
|
||||||
'ip_address': '10.0.1.%d' % i}],
|
'ip_address': '10.0.1.%d' % i}],
|
||||||
'binding:profile': {}}
|
'binding:profile': {},
|
||||||
|
'security_groups': [t_sg['id']]}
|
||||||
TOP_PORTS.append(t_port)
|
TOP_PORTS.append(t_port)
|
||||||
t_ports.append(t_port)
|
t_ports.append(t_port)
|
||||||
self.plugin.get_ports(self.context,
|
self.plugin.get_ports(self.context,
|
||||||
|
|
|
@ -30,34 +30,43 @@ from tricircle.xjob import xmanager
|
||||||
from tricircle.xjob import xservice
|
from tricircle.xjob import xservice
|
||||||
|
|
||||||
|
|
||||||
|
TOP_NETWORK = []
|
||||||
BOTTOM1_NETWORK = []
|
BOTTOM1_NETWORK = []
|
||||||
BOTTOM2_NETWORK = []
|
BOTTOM2_NETWORK = []
|
||||||
|
TOP_SUBNET = []
|
||||||
BOTTOM1_SUBNET = []
|
BOTTOM1_SUBNET = []
|
||||||
BOTTOM2_SUBNET = []
|
BOTTOM2_SUBNET = []
|
||||||
BOTTOM1_PORT = []
|
BOTTOM1_PORT = []
|
||||||
BOTTOM2_PORT = []
|
BOTTOM2_PORT = []
|
||||||
BOTTOM1_ROUTER = []
|
BOTTOM1_ROUTER = []
|
||||||
BOTTOM2_ROUTER = []
|
BOTTOM2_ROUTER = []
|
||||||
RES_LIST = [BOTTOM1_NETWORK, BOTTOM2_NETWORK, BOTTOM1_SUBNET, BOTTOM2_SUBNET,
|
TOP_SG = []
|
||||||
BOTTOM1_PORT, BOTTOM2_PORT, BOTTOM1_ROUTER, BOTTOM2_ROUTER]
|
BOTTOM1_SG = []
|
||||||
RES_MAP = {'pod_1': {'network': BOTTOM1_NETWORK,
|
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,
|
'subnet': BOTTOM1_SUBNET,
|
||||||
'port': BOTTOM1_PORT,
|
'port': BOTTOM1_PORT,
|
||||||
'router': BOTTOM1_ROUTER},
|
'router': BOTTOM1_ROUTER,
|
||||||
|
'security_group': BOTTOM1_SG},
|
||||||
'pod_2': {'network': BOTTOM2_NETWORK,
|
'pod_2': {'network': BOTTOM2_NETWORK,
|
||||||
'subnet': BOTTOM2_SUBNET,
|
'subnet': BOTTOM2_SUBNET,
|
||||||
'port': BOTTOM2_PORT,
|
'port': BOTTOM2_PORT,
|
||||||
'router': BOTTOM2_ROUTER}}
|
'router': BOTTOM2_ROUTER,
|
||||||
|
'security_group': BOTTOM2_SG}}
|
||||||
|
|
||||||
|
|
||||||
class FakeXManager(xmanager.XManager):
|
class FakeXManager(xmanager.XManager):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.clients = {'pod_1': FakeClient('pod_1'),
|
self.clients = {'top': FakeClient(),
|
||||||
|
'pod_1': FakeClient('pod_1'),
|
||||||
'pod_2': FakeClient('pod_2')}
|
'pod_2': FakeClient('pod_2')}
|
||||||
|
|
||||||
def _get_client(self, pod_name=None):
|
|
||||||
return self.clients[pod_name]
|
|
||||||
|
|
||||||
|
|
||||||
class FakeClient(object):
|
class FakeClient(object):
|
||||||
def __init__(self, pod_name=None):
|
def __init__(self, pod_name=None):
|
||||||
|
@ -85,6 +94,9 @@ class FakeClient(object):
|
||||||
def list_ports(self, cxt, filters=None):
|
def list_ports(self, cxt, filters=None):
|
||||||
return self.list_resources('port', cxt, filters)
|
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):
|
def get_subnets(self, cxt, subnet_id):
|
||||||
return self.list_resources(
|
return self.list_resources(
|
||||||
'subnet', cxt,
|
'subnet', cxt,
|
||||||
|
@ -93,6 +105,20 @@ class FakeClient(object):
|
||||||
def update_routers(self, cxt, *args, **kwargs):
|
def update_routers(self, cxt, *args, **kwargs):
|
||||||
pass
|
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):
|
class XManagerTest(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -106,6 +132,7 @@ class XManagerTest(unittest.TestCase):
|
||||||
cfg.CONF.register_opt(opt)
|
cfg.CONF.register_opt(opt)
|
||||||
self.context = context.Context()
|
self.context = context.Context()
|
||||||
self.xmanager = FakeXManager()
|
self.xmanager = FakeXManager()
|
||||||
|
self.xmanager = FakeXManager()
|
||||||
|
|
||||||
@patch.object(FakeClient, 'update_routers')
|
@patch.object(FakeClient, 'update_routers')
|
||||||
def test_configure_extra_routes(self, mock_update):
|
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])
|
called = called and (mock_update.call_args_list[0] == calls[0])
|
||||||
self.assertTrue(called)
|
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):
|
def test_job_handle(self):
|
||||||
@xmanager._job_handle('fake_resource')
|
@xmanager._job_handle('fake_resource')
|
||||||
def fake_handle(self, ctx, payload):
|
def fake_handle(self, ctx, payload):
|
||||||
|
|
|
@ -24,6 +24,7 @@ from oslo_log import log as logging
|
||||||
import oslo_messaging as messaging
|
import oslo_messaging as messaging
|
||||||
from oslo_service import periodic_task
|
from oslo_service import periodic_task
|
||||||
|
|
||||||
|
import neutron_lib.exceptions as q_exceptions
|
||||||
import neutronclient.common.exceptions as q_cli_exceptions
|
import neutronclient.common.exceptions as q_cli_exceptions
|
||||||
|
|
||||||
from tricircle.common import client
|
from tricircle.common import client
|
||||||
|
@ -150,7 +151,8 @@ class XManager(PeriodicTasks):
|
||||||
self.job_handles = {
|
self.job_handles = {
|
||||||
constants.JT_ROUTER: self.configure_extra_routes,
|
constants.JT_ROUTER: self.configure_extra_routes,
|
||||||
constants.JT_ROUTER_SETUP: self.setup_bottom_router,
|
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.helper = helper.NetworkHelper()
|
||||||
self.xjob_handler = xrpcapi.XJobAPI()
|
self.xjob_handler = xrpcapi.XJobAPI()
|
||||||
super(XManager, self).__init__()
|
super(XManager, self).__init__()
|
||||||
|
@ -611,8 +613,8 @@ class XManager(PeriodicTasks):
|
||||||
router_ips_map[b_router_ids[i]] = {}
|
router_ips_map[b_router_ids[i]] = {}
|
||||||
for b_interface in b_interfaces:
|
for b_interface in b_interfaces:
|
||||||
ip = b_interface['fixed_ips'][0]['ip_address']
|
ip = b_interface['fixed_ips'][0]['ip_address']
|
||||||
ew_bridge_cidr = '100.0.0.0/9'
|
ew_bridge_cidr = CONF.client.ew_bridge_cidr
|
||||||
ns_bridge_cidr = '100.128.0.0/9'
|
ns_bridge_cidr = CONF.client.ns_bridge_cidr
|
||||||
if netaddr.IPAddress(ip) in netaddr.IPNetwork(ew_bridge_cidr):
|
if netaddr.IPAddress(ip) in netaddr.IPNetwork(ew_bridge_cidr):
|
||||||
router_bridge_ip_map[b_router_ids[i]] = ip
|
router_bridge_ip_map[b_router_ids[i]] = ip
|
||||||
continue
|
continue
|
||||||
|
@ -655,3 +657,108 @@ class XManager(PeriodicTasks):
|
||||||
def delete_server_port(self, ctx, payload):
|
def delete_server_port(self, ctx, payload):
|
||||||
t_port_id = payload[constants.JT_PORT_DELETE]
|
t_port_id = payload[constants.JT_PORT_DELETE]
|
||||||
self._get_client().delete_ports(ctx, t_port_id)
|
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