Security Groups implementation
Change-Id: I415938e53d4656b376812dc85e2e9bb6d9986fe9
This commit is contained in:
parent
7e2205e9ab
commit
78ba18f6d2
@ -1,2 +1,2 @@
|
||||
28430956782d
|
||||
393bf843b96
|
||||
53a3254aa95e
|
||||
|
@ -0,0 +1,47 @@
|
||||
# Copyright 2015 OpenStack Foundation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
"""nsxv3_security_groups
|
||||
|
||||
Revision ID: 28430956782d
|
||||
Revises: 53a3254aa95e
|
||||
Create Date: 2015-08-24 18:19:09.397813
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '28430956782d'
|
||||
down_revision = '53a3254aa95e'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.create_table(
|
||||
'neutron_nsx_firewall_section_mappings',
|
||||
sa.Column('neutron_id', sa.String(36), nullable=False),
|
||||
sa.Column('nsx_id', sa.String(36), nullable=False),
|
||||
sa.ForeignKeyConstraint(['neutron_id'], ['securitygroups.id'],
|
||||
ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('neutron_id'))
|
||||
|
||||
op.create_table(
|
||||
'neutron_nsx_rule_mappings',
|
||||
sa.Column('neutron_id', sa.String(36), nullable=False),
|
||||
sa.Column('nsx_id', sa.String(36), nullable=False),
|
||||
sa.ForeignKeyConstraint(['neutron_id'], ['securitygrouprules.id'],
|
||||
ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('neutron_id'))
|
@ -89,6 +89,34 @@ class NeutronNsxSecurityGroupMapping(model_base.BASEV2):
|
||||
nsx_id = sa.Column(sa.String(36), primary_key=True)
|
||||
|
||||
|
||||
class NeutronNsxFirewallSectionMapping(model_base.BASEV2):
|
||||
"""Backend mappings for Neutron Security-group associated fw sections."""
|
||||
|
||||
__tablename__ = 'neutron_nsx_firewall_section_mappings'
|
||||
neutron_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('securitygroups.id',
|
||||
ondelete='CASCADE'),
|
||||
primary_key=True,
|
||||
nullable=False)
|
||||
nsx_id = sa.Column(sa.String(36), nullable=False)
|
||||
|
||||
|
||||
class NeutronNsxRuleMapping(model_base.BASEV2):
|
||||
"""Backend mappings for firewall rules.
|
||||
|
||||
This class maps a neutron security group rule with NSX firewall rule.
|
||||
"""
|
||||
|
||||
__tablename__ = 'neutron_nsx_rule_mappings'
|
||||
|
||||
neutron_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('securitygrouprules.id',
|
||||
ondelete="CASCADE"),
|
||||
primary_key=True,
|
||||
nullable=False)
|
||||
nsx_id = sa.Column(sa.String(36), nullable=False)
|
||||
|
||||
|
||||
class NeutronNsxPortMapping(model_base.BASEV2):
|
||||
"""Represents the mapping between neutron and nsx port uuids."""
|
||||
|
||||
|
@ -86,7 +86,7 @@ def create_resource(resource, data):
|
||||
verify=verify, headers=headers,
|
||||
data=jsonutils.dumps(data),
|
||||
cert=cfg.CONF.nsx_v3.ca_file)
|
||||
_validate_result(result, [requests.codes.created],
|
||||
_validate_result(result, [requests.codes.created, requests.codes.ok],
|
||||
_("creating resource at: %s") % resource)
|
||||
return result.json()
|
||||
|
||||
|
193
vmware_nsx/neutron/plugins/vmware/nsxlib/v3/dfw_api.py
Normal file
193
vmware_nsx/neutron/plugins/vmware/nsxlib/v3/dfw_api.py
Normal file
@ -0,0 +1,193 @@
|
||||
# Copyright 2015 OpenStack Foundation
|
||||
# All Rights Reserved
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
"""
|
||||
NSX-V3 Distributed Firewall
|
||||
"""
|
||||
|
||||
from vmware_nsx.neutron.plugins.vmware.common import exceptions as nsx_exc
|
||||
from vmware_nsx.neutron.plugins.vmware.common import utils
|
||||
from vmware_nsx.neutron.plugins.vmware.nsxlib.v3 import client as nsclient
|
||||
|
||||
|
||||
# firewall section types
|
||||
LAYER3 = 'LAYER3'
|
||||
|
||||
# firewall rule actions
|
||||
ALLOW = 'ALLOW'
|
||||
DROP = 'DROP'
|
||||
REJECT = 'REJECT'
|
||||
|
||||
# filtering operators
|
||||
EQUALS = 'EQUALS'
|
||||
|
||||
NSGROUP = 'NSGroup'
|
||||
LOGICAL_SWITCH = 'LogicalSwitch'
|
||||
LOGICAL_PORT = 'LogicalPort'
|
||||
IPV4ADDRESS = 'IPv4Address'
|
||||
IPV6ADDRESS = 'IPv6Address'
|
||||
|
||||
IN = 'IN'
|
||||
OUT = 'OUT'
|
||||
|
||||
# NSServices resource types
|
||||
L4_PORT_SET_NSSERVICE = 'L4PortSetNSService'
|
||||
ICMP_TYPE_NSSERVICE = 'ICMPTypeNSService'
|
||||
IP_PROTOCOL_NSSERVICE = 'IPProtocolNSService'
|
||||
|
||||
TCP = 'TCP'
|
||||
UDP = 'UDP'
|
||||
ICMPV4 = 'ICMPv4'
|
||||
ICMPV6 = 'ICMPv6'
|
||||
|
||||
IPV4 = 'IPV4'
|
||||
IPV6 = 'IPV6'
|
||||
|
||||
|
||||
def get_nsservice(resource_type, **properties):
|
||||
service = {'resource_type': resource_type}
|
||||
service.update(properties)
|
||||
return {'service': service}
|
||||
|
||||
|
||||
def create_nsgroup(display_name, description, tags):
|
||||
body = {'display_name': display_name,
|
||||
'description': description,
|
||||
'tags': tags}
|
||||
return nsclient.create_resource('ns-groups', body)
|
||||
|
||||
|
||||
def list_nsgroups():
|
||||
return nsclient.get_resource('ns-groups')
|
||||
|
||||
|
||||
@utils.retry_upon_exception_nsxv3(nsx_exc.StaleRevision)
|
||||
def update_nsgroup(nsgroup_id, display_name, description):
|
||||
nsgroup = read_nsgroup(nsgroup_id)
|
||||
nsgroup.update({'display_name': display_name,
|
||||
'description': description})
|
||||
return nsclient.update_resource('ns-groups/%s' % nsgroup_id, nsgroup)
|
||||
|
||||
|
||||
@utils.retry_upon_exception_nsxv3(nsx_exc.StaleRevision)
|
||||
def add_nsgroup_member(nsgroup_id, target_type, target_id):
|
||||
nsgroup = read_nsgroup(nsgroup_id)
|
||||
if 'members' not in nsgroup:
|
||||
nsgroup['members'] = []
|
||||
nsgroup['members'].append({'target_property': 'id',
|
||||
'target_type': target_type,
|
||||
'op': EQUALS,
|
||||
'value': target_id})
|
||||
return nsclient.update_resource('ns-groups/%s' % nsgroup_id, nsgroup)
|
||||
|
||||
|
||||
@utils.retry_upon_exception_nsxv3(nsx_exc.StaleRevision)
|
||||
def remove_nsgroup_member(nsgroup_id, target_id):
|
||||
nsgroup = read_nsgroup(nsgroup_id)
|
||||
for i, member in enumerate(nsgroup.get('members', [])):
|
||||
if target_id == member['value']:
|
||||
break
|
||||
else:
|
||||
return
|
||||
del nsgroup['members'][i]
|
||||
return nsclient.update_resource('ns-groups/%s' % nsgroup_id, nsgroup)
|
||||
|
||||
|
||||
def read_nsgroup(nsgroup_id):
|
||||
return nsclient.get_resource('ns-groups/%s' % nsgroup_id)
|
||||
|
||||
|
||||
def delete_nsgroup(nsgroup_id):
|
||||
return nsclient.delete_resource('ns-groups/%s' % nsgroup_id)
|
||||
|
||||
|
||||
def _build_section(display_name, description, applied_tos, tags):
|
||||
return {'display_name': display_name,
|
||||
'description': description,
|
||||
'stateful': True,
|
||||
'section_type': LAYER3,
|
||||
'applied_tos': [get_nsgroup_reference(t_id)
|
||||
for t_id in applied_tos],
|
||||
'tags': tags}
|
||||
|
||||
|
||||
def create_empty_section(display_name, description, applied_tos, tags):
|
||||
resource = 'firewall/sections'
|
||||
body = _build_section(display_name, description, applied_tos, tags)
|
||||
return nsclient.create_resource(resource, body)
|
||||
|
||||
|
||||
@utils.retry_upon_exception_nsxv3(nsx_exc.StaleRevision)
|
||||
def update_section(section_id, display_name, description, applied_tos=None):
|
||||
resource = 'firewall/sections/%s' % section_id
|
||||
section = read_section(section_id)
|
||||
section.update({'display_name': display_name,
|
||||
'description': description})
|
||||
if applied_tos is not None:
|
||||
section['applied_tos'] = applied_tos
|
||||
return nsclient.update_resource(resource, section)
|
||||
|
||||
|
||||
def read_section(section_id):
|
||||
resource = 'firewall/sections/%s' % section_id
|
||||
return nsclient.get_resource(resource)
|
||||
|
||||
|
||||
def list_sections():
|
||||
resource = 'firewall/sections'
|
||||
return nsclient.get_resource(resource)
|
||||
|
||||
|
||||
def delete_section(section_id):
|
||||
resource = 'firewall/sections/%s?cascade=true' % section_id
|
||||
return nsclient.delete_resource(resource)
|
||||
|
||||
|
||||
def get_nsgroup_reference(nsgroup_id):
|
||||
return {'target_id': nsgroup_id,
|
||||
'target_type': NSGROUP}
|
||||
|
||||
|
||||
def get_ip_cidr_reference(ip_cidr_block, ip_protocol):
|
||||
target_type = IPV4ADDRESS if ip_protocol == IPV4 else IPV6ADDRESS
|
||||
return {'target_id': ip_cidr_block,
|
||||
'target_type': target_type}
|
||||
|
||||
|
||||
def get_firewall_rule_dict(display_name, source, destination, direction,
|
||||
ip_protocol, service, action):
|
||||
return {'display_name': display_name,
|
||||
'sources': [source] if source else [],
|
||||
'destinations': [destination] if destination else [],
|
||||
'direction': direction,
|
||||
'ip_protocol': ip_protocol,
|
||||
'services': [service] if service else [],
|
||||
'action': action}
|
||||
|
||||
|
||||
def add_rule_in_section(rule, section_id):
|
||||
resource = 'firewall/sections/%s/rules' % section_id
|
||||
return nsclient.create_resource(resource, rule)
|
||||
|
||||
|
||||
def add_rules_in_section(rules, section_id):
|
||||
resource = 'firewall/sections/%s/rules?action=create_multiple' % section_id
|
||||
return nsclient.create_resource(resource, {'rules': rules})
|
||||
|
||||
|
||||
def delete_rule(section_id, rule_id):
|
||||
resource = 'firewall/sections/%s/rules/%s' % (section_id, rule_id)
|
||||
return nsclient.delete_resource(resource)
|
172
vmware_nsx/neutron/plugins/vmware/nsxlib/v3/security.py
Normal file
172
vmware_nsx/neutron/plugins/vmware/nsxlib/v3/security.py
Normal file
@ -0,0 +1,172 @@
|
||||
# Copyright 2015 OpenStack Foundation
|
||||
|
||||
# All Rights Reserved
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
NSX-V3 Plugin security integration module
|
||||
"""
|
||||
|
||||
from neutron.db import securitygroups_db
|
||||
|
||||
from vmware_nsx.neutron.plugins.vmware.dbexts import nsx_models
|
||||
from vmware_nsx.neutron.plugins.vmware.nsxlib.v3 import dfw_api as firewall
|
||||
|
||||
|
||||
def _get_l4_protocol_name(proto_num):
|
||||
if proto_num == 6:
|
||||
return firewall.TCP
|
||||
elif proto_num == 17:
|
||||
return firewall.UDP
|
||||
elif proto_num == 1:
|
||||
return firewall.ICMPV4
|
||||
|
||||
|
||||
def _decide_service(sg_rule):
|
||||
ip_proto = securitygroups_db.IP_PROTOCOL_MAP.get(sg_rule['protocol'],
|
||||
sg_rule['protocol'])
|
||||
l4_protocol = _get_l4_protocol_name(ip_proto)
|
||||
|
||||
if l4_protocol in [firewall.TCP, firewall.UDP]:
|
||||
# If port_range_min is not specified then we assume all ports are
|
||||
# matched, relying on neutron to perform validation.
|
||||
if sg_rule['port_range_min'] is None:
|
||||
source_ports = []
|
||||
else:
|
||||
source_ports = ['%(port_range_min)s-%(port_range_max)s' % sg_rule]
|
||||
return firewall.get_nsservice(firewall.L4_PORT_SET_NSSERVICE,
|
||||
l4_protocol=l4_protocol,
|
||||
source_ports=source_ports)
|
||||
elif l4_protocol == firewall.ICMPV4:
|
||||
return firewall.get_nsservice(firewall.ICMP_TYPE_NSSERVICE,
|
||||
protocol=l4_protocol,
|
||||
icmp_type=sg_rule['port_range_min'],
|
||||
icmp_code=sg_rule['port_range_max'])
|
||||
elif ip_proto is not None:
|
||||
return firewall.get_nsservice(firewall.IP_PROTOCOL_NSSERVICE,
|
||||
protocol_number=ip_proto)
|
||||
|
||||
|
||||
def _get_fw_rule_from_sg_rule(sg_rule, nsgroup_id, rmt_nsgroup_id):
|
||||
# IPV4 or IPV6
|
||||
ip_protocol = sg_rule['ethertype'].upper()
|
||||
direction = (
|
||||
firewall.IN if sg_rule['direction'] == 'ingress' else firewall.OUT)
|
||||
|
||||
source = None
|
||||
local_group = firewall.get_nsgroup_reference(nsgroup_id)
|
||||
if sg_rule['remote_ip_prefix'] is not None:
|
||||
source = firewall.get_ip_cidr_reference(sg_rule['remote_ip_prefix'],
|
||||
ip_protocol)
|
||||
destination = local_group
|
||||
else:
|
||||
if rmt_nsgroup_id:
|
||||
source = firewall.get_nsgroup_reference(rmt_nsgroup_id)
|
||||
destination = local_group
|
||||
if direction == firewall.OUT:
|
||||
source, destination = destination, source
|
||||
|
||||
service = _decide_service(sg_rule)
|
||||
name = sg_rule['id']
|
||||
|
||||
return firewall.get_firewall_rule_dict(name, source,
|
||||
destination, direction,
|
||||
ip_protocol, service,
|
||||
firewall.ALLOW)
|
||||
|
||||
|
||||
def create_firewall_rules(context, section_id, nsgroup_id,
|
||||
security_group_rules):
|
||||
|
||||
# 1. translate rules
|
||||
# 2. insert in section
|
||||
# 3. save mappings
|
||||
|
||||
firewall_rules = []
|
||||
for sg_rule in security_group_rules:
|
||||
remote_nsgroup_id = _get_remote_nsg_mapping(
|
||||
context, sg_rule, nsgroup_id)
|
||||
|
||||
fw_rule = _get_fw_rule_from_sg_rule(
|
||||
sg_rule, nsgroup_id, remote_nsgroup_id)
|
||||
|
||||
firewall_rules.append(
|
||||
firewall.add_rule_in_section(fw_rule, section_id))
|
||||
return {'rules': firewall_rules}
|
||||
|
||||
|
||||
def get_nsgroup_name(security_group):
|
||||
# NOTE(roeyc): We add the security-group id to the NSGroup name,
|
||||
# for usability purposes.
|
||||
return '%(name)s - %(id)s' % security_group
|
||||
|
||||
|
||||
def save_sg_rule_mappings(session, firewall_rules):
|
||||
# REVISIT(roeyc): This method should take care db access only.
|
||||
rules = [(rule['display_name'], rule['id']) for rule in firewall_rules]
|
||||
with session.begin(subtransactions=True):
|
||||
for neutron_id, nsx_id in rules:
|
||||
mapping = nsx_models.NeutronNsxRuleMapping(
|
||||
neutron_id=neutron_id, nsx_id=nsx_id)
|
||||
session.add(mapping)
|
||||
return mapping
|
||||
|
||||
|
||||
def save_sg_mappings(session, sg_id, nsgroup_id, section_id):
|
||||
with session.begin(subtransactions=True):
|
||||
session.add(
|
||||
nsx_models.NeutronNsxFirewallSectionMapping(neutron_id=sg_id,
|
||||
nsx_id=section_id))
|
||||
session.add(
|
||||
nsx_models.NeutronNsxSecurityGroupMapping(neutron_id=sg_id,
|
||||
nsx_id=nsgroup_id))
|
||||
|
||||
|
||||
def get_sg_rule_mapping(session, rule_id):
|
||||
rule_mapping = session.query(nsx_models.NeutronNsxRuleMapping).filter_by(
|
||||
neutron_id=rule_id).one()
|
||||
return rule_mapping.nsx_id
|
||||
|
||||
|
||||
def get_sg_mappings(session, sg_id):
|
||||
nsgroup_mapping = session.query(nsx_models.NeutronNsxSecurityGroupMapping
|
||||
).filter_by(neutron_id=sg_id).one()
|
||||
section_mapping = session.query(nsx_models.NeutronNsxFirewallSectionMapping
|
||||
).filter_by(neutron_id=sg_id).one()
|
||||
return nsgroup_mapping.nsx_id, section_mapping.nsx_id
|
||||
|
||||
|
||||
def _get_remote_nsg_mapping(context, sg_rule, nsgroup_id):
|
||||
remote_nsgroup_id = None
|
||||
remote_group_id = sg_rule.get('remote_group_id')
|
||||
# skip unnecessary db access when possible
|
||||
if remote_group_id == sg_rule['security_group_id']:
|
||||
remote_nsgroup_id = nsgroup_id
|
||||
elif remote_group_id:
|
||||
remote_nsgroup_id, _ = get_sg_mappings(context.session,
|
||||
remote_group_id)
|
||||
return remote_nsgroup_id
|
||||
|
||||
|
||||
def update_lport_with_security_groups(context, lport_id, original, updated):
|
||||
added = set(updated) - set(original)
|
||||
removed = set(original) - set(updated)
|
||||
for sg_id in added:
|
||||
nsgroup_id, _ = get_sg_mappings(context.session, sg_id)
|
||||
firewall.add_nsgroup_member(
|
||||
nsgroup_id, firewall.LOGICAL_PORT, lport_id)
|
||||
for sg_id in removed:
|
||||
nsgroup_id, _ = get_sg_mappings(context.session, sg_id)
|
||||
firewall.remove_nsgroup_member(
|
||||
nsgroup_id, lport_id)
|
@ -32,6 +32,7 @@ from neutron.extensions import extra_dhcp_opt as edo_ext
|
||||
from neutron.extensions import l3
|
||||
from neutron.extensions import portbindings as pbin
|
||||
from neutron.extensions import providernet as pnet
|
||||
from neutron.extensions import securitygroup as ext_sg
|
||||
|
||||
from neutron.common import constants as const
|
||||
from neutron.common import exceptions as n_exc
|
||||
@ -55,6 +56,8 @@ from vmware_nsx.neutron.plugins.vmware.common import exceptions as nsx_exc
|
||||
from vmware_nsx.neutron.plugins.vmware.common import utils
|
||||
from vmware_nsx.neutron.plugins.vmware.dbexts import db as nsx_db
|
||||
from vmware_nsx.neutron.plugins.vmware.nsxlib import v3 as nsxlib
|
||||
from vmware_nsx.neutron.plugins.vmware.nsxlib.v3 import dfw_api as firewall
|
||||
from vmware_nsx.neutron.plugins.vmware.nsxlib.v3 import security
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
@ -66,8 +69,6 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
portbindings_db.PortBindingMixin,
|
||||
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
||||
extradhcpopt_db.ExtraDhcpOptMixin):
|
||||
# NOTE(salv-orlando): Security groups are not actually implemented by this
|
||||
# plugin at the moment
|
||||
|
||||
__native_bulk_support = True
|
||||
__native_pagination_support = True
|
||||
@ -438,6 +439,7 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
nsx_db.add_neutron_nsx_port_mapping(
|
||||
context.session, neutron_db['id'],
|
||||
neutron_db['network_id'], result['id'])
|
||||
return result
|
||||
|
||||
def create_port(self, context, port):
|
||||
dhcp_opts = port['port'].get(edo_ext.EXTRADHCPOPTS, [])
|
||||
@ -456,7 +458,7 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
|
||||
if not self._network_is_external(
|
||||
context, port['port']['network_id']):
|
||||
self._create_port_at_the_backend(
|
||||
lport = self._create_port_at_the_backend(
|
||||
context, neutron_db, port['port'])
|
||||
self._process_portbindings_create_and_update(context,
|
||||
port['port'],
|
||||
@ -466,11 +468,15 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
if (pbin.PROFILE in port['port'] and
|
||||
attributes.is_attr_set(port['port'][pbin.PROFILE])):
|
||||
neutron_db[pbin.PROFILE] = port['port'][pbin.PROFILE]
|
||||
sgids = self._get_security_groups_on_port(context, port)
|
||||
self._process_port_create_security_group(
|
||||
context, neutron_db, sgids)
|
||||
self._process_port_create_extra_dhcp_opts(context, neutron_db,
|
||||
dhcp_opts)
|
||||
|
||||
sgids = self._get_security_groups_on_port(context, port)
|
||||
if sgids is not None:
|
||||
self._process_port_create_security_group(
|
||||
context, neutron_db, sgids)
|
||||
security.update_lport_with_security_groups(
|
||||
context, lport['id'], [], sgids)
|
||||
return neutron_db
|
||||
|
||||
def delete_port(self, context, port_id, l3_port_check=True):
|
||||
@ -497,12 +503,15 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
self._update_extra_dhcp_opts_on_port(context, id, port,
|
||||
updated_port)
|
||||
sec_grp_updated = self.update_security_group_on_port(
|
||||
context, id, port, original_port,
|
||||
updated_port)
|
||||
context, id, port, original_port, updated_port)
|
||||
try:
|
||||
nsxlib.update_logical_port(
|
||||
nsx_lport_id, name=port['port'].get('name'),
|
||||
admin_state=port['port'].get('admin_state_up'))
|
||||
security.update_lport_with_security_groups(
|
||||
context, nsx_lport_id,
|
||||
original_port.get(ext_sg.SECURITYGROUPS, []),
|
||||
updated_port.get(ext_sg.SECURITYGROUPS, []))
|
||||
except nsx_exc.ManagerError:
|
||||
# In case if there is a failure on NSX-v3 backend, rollback the
|
||||
# previous update operation on neutron side.
|
||||
@ -517,6 +526,8 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
context, id, {'port': original_port}, updated_port,
|
||||
original_port)
|
||||
|
||||
#TODO(roeyc): add port to nsgroups
|
||||
|
||||
return updated_port
|
||||
|
||||
def create_router(self, context, router):
|
||||
@ -616,10 +627,128 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
return super(NsxV3Plugin, self).remove_router_interface(
|
||||
context, router_id, interface_info)
|
||||
|
||||
def create_security_group_rule_bulk(self, context, security_group_rules):
|
||||
return super(NsxV3Plugin, self).create_security_group_rule_bulk_native(
|
||||
context, security_group_rules)
|
||||
|
||||
def extend_port_dict_binding(self, port_res, port_db):
|
||||
super(NsxV3Plugin, self).extend_port_dict_binding(port_res, port_db)
|
||||
port_res[pbin.VNIC_TYPE] = pbin.VNIC_NORMAL
|
||||
|
||||
def create_security_group(self, context, security_group, default_sg=False):
|
||||
secgroup = security_group['security_group']
|
||||
secgroup['id'] = uuidutils.generate_uuid()
|
||||
|
||||
tags = utils.build_v3_tags_payload(secgroup)
|
||||
name = security.get_nsgroup_name(secgroup)
|
||||
ns_group = None
|
||||
|
||||
try:
|
||||
# NOTE(roeyc): We first create the nsgroup so that once the sg is
|
||||
# saved into db its already backed up by an nsx resource.
|
||||
ns_group = firewall.create_nsgroup(
|
||||
name, secgroup['description'], tags)
|
||||
# security-group rules are located in a dedicated firewall section.
|
||||
firewall_section = firewall.create_empty_section(
|
||||
name, secgroup.get('description', ''), [ns_group['id']], tags)
|
||||
|
||||
# REVISIT(roeyc): Idealy, at this point we need not be under an
|
||||
# open db transactions, however, unittests fail if omitting
|
||||
# subtransactions=True.
|
||||
with context.session.begin(subtransactions=True):
|
||||
secgroup_db = (
|
||||
super(NsxV3Plugin, self).create_security_group(
|
||||
context, security_group, default_sg))
|
||||
|
||||
security.save_sg_mappings(context.session,
|
||||
secgroup_db['id'],
|
||||
ns_group['id'],
|
||||
firewall_section['id'])
|
||||
except nsx_exc.ManagerError:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.exception(_LE("Unable to create security-group on the "
|
||||
"backend."))
|
||||
if ns_group:
|
||||
firewall.delete_nsgroup(ns_group['id'])
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.debug("Neutron failed to create security-group, "
|
||||
"deleting backend resources: "
|
||||
"section %s, ns-group %s.",
|
||||
firewall_section['id'], ns_group['id'])
|
||||
firewall.delete_nsgroup(ns_group['id'])
|
||||
firewall.delete_section(firewall_section['id'])
|
||||
try:
|
||||
sg_rules = secgroup_db['security_group_rules']
|
||||
# translate and creates firewall rules.
|
||||
rules = security.create_firewall_rules(
|
||||
context, firewall_section['id'], ns_group['id'], sg_rules)
|
||||
security.save_sg_rule_mappings(context.session, rules['rules'])
|
||||
except nsx_exc.ManagerError:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.exception(_LE("Failed to create backend firewall rules "
|
||||
" for security-group %(name)s (%(id)s), "
|
||||
"rolling back changes."), secgroup_db)
|
||||
# default security group deletion requires admin context
|
||||
if default_sg:
|
||||
context = context.elevated()
|
||||
super(NsxV3Plugin, self).delete_security_group(
|
||||
context, secgroup_db['id'])
|
||||
firewall.delete_nsgroup(ns_group['id'])
|
||||
firewall.delete_section(firewall_section['id'])
|
||||
|
||||
return secgroup_db
|
||||
|
||||
def update_security_group(self, context, id, security_group):
|
||||
nsgroup_id, section_id = security.get_sg_mappings(context.session, id)
|
||||
original_security_group = self.get_security_group(
|
||||
context, id, fields=['id', 'name', 'description'])
|
||||
updated_security_group = (
|
||||
super(NsxV3Plugin, self).update_security_group(context, id,
|
||||
security_group))
|
||||
name = security.get_nsgroup_name(updated_security_group)
|
||||
description = updated_security_group['description']
|
||||
try:
|
||||
firewall.update_nsgroup(nsgroup_id, name, description)
|
||||
firewall.update_section(section_id, name, description)
|
||||
except nsx_exc.ManagerError:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.exception(_LE("Failed to update security-group %(name)s "
|
||||
"(%(id)s), rolling back changes in "
|
||||
"Neutron."), original_security_group)
|
||||
super(NsxV3Plugin, self).update_security_group(
|
||||
context, id, {'security_group': original_security_group})
|
||||
|
||||
return updated_security_group
|
||||
|
||||
def delete_security_group(self, context, id):
|
||||
nsgroup_id, section_id = security.get_sg_mappings(context.session, id)
|
||||
super(NsxV3Plugin, self).delete_security_group(context, id)
|
||||
firewall.delete_section(section_id)
|
||||
firewall.delete_nsgroup(nsgroup_id)
|
||||
|
||||
def create_security_group_rule(self, context, security_group_rule):
|
||||
bulk_rule = {'security_group_rules': [security_group_rule]}
|
||||
return self.create_security_group_rule_bulk(context, bulk_rule)[0]
|
||||
|
||||
def create_security_group_rule_bulk(self, context, security_group_rules):
|
||||
security_group_rules_db = (
|
||||
super(NsxV3Plugin, self).create_security_group_rule_bulk_native(
|
||||
context, security_group_rules))
|
||||
sg_id = security_group_rules_db[0]['security_group_id']
|
||||
nsgroup_id, section_id = security.get_sg_mappings(context.session,
|
||||
sg_id)
|
||||
try:
|
||||
rules = security.create_firewall_rules(
|
||||
context, section_id, nsgroup_id, security_group_rules_db)
|
||||
except nsx_exc.ManagerError:
|
||||
with excutils.save_and_reraise_exception():
|
||||
for rule in security_group_rules_db:
|
||||
super(NsxV3Plugin, self).delete_security_group_rule(
|
||||
context, rule['id'])
|
||||
security.save_sg_rule_mappings(context.session, rules['rules'])
|
||||
return security_group_rules_db
|
||||
|
||||
def delete_security_group_rule(self, context, id):
|
||||
rule_db = self._get_security_group_rule(context, id)
|
||||
sg_id = rule_db['security_group_id']
|
||||
_, section_id = security.get_sg_mappings(context.session, sg_id)
|
||||
fw_rule_id = security.get_sg_rule_mapping(context.session, id)
|
||||
super(NsxV3Plugin, self).delete_security_group_rule(context, id)
|
||||
firewall.delete_rule(section_id, fw_rule_id)
|
||||
|
@ -193,3 +193,26 @@ def get_logical_router(lrouter_uuid):
|
||||
"id": lrouter_uuid,
|
||||
"edge_cluster_uuid": uuidutils.generate_uuid()}
|
||||
return FAKE_LROUTER
|
||||
|
||||
|
||||
def add_rules_in_section(rules, section_id):
|
||||
for rule in rules:
|
||||
rule['id'] = uuidutils.generate_uuid()
|
||||
return {'rules': rules}
|
||||
|
||||
|
||||
def get_resource(resource):
|
||||
return {'id': resource.split('/')[-1]}
|
||||
|
||||
|
||||
def create_resource(resource, data):
|
||||
data['id'] = uuidutils.generate_uuid()
|
||||
return data
|
||||
|
||||
|
||||
def update_resource(resource, data):
|
||||
return resource
|
||||
|
||||
|
||||
def delete_resource(resource):
|
||||
pass
|
||||
|
@ -20,6 +20,7 @@ import neutron.tests.unit.db.test_db_base_plugin_v2 as test_plugin
|
||||
from neutron.tests.unit.extensions import test_extra_dhcp_opt as test_dhcpopts
|
||||
import neutron.tests.unit.extensions.test_securitygroup as ext_sg
|
||||
from vmware_nsx.neutron.plugins.vmware.nsxlib import v3 as nsxlib
|
||||
from vmware_nsx.neutron.plugins.vmware.nsxlib.v3 import dfw_api as firewall
|
||||
from vmware_nsx.neutron.tests.unit.vmware import nsx_v3_mocks
|
||||
|
||||
PLUGIN_NAME = ('vmware_nsx.neutron.plugins.vmware.'
|
||||
@ -49,6 +50,11 @@ class NsxPluginV3TestCase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
# TODO(berlin): fill valid data
|
||||
nsxlib.get_edge_cluster = nsx_v3_mocks.get_edge_cluster
|
||||
nsxlib.get_logical_router = nsx_v3_mocks.get_logical_router
|
||||
firewall.add_rules_in_section = nsx_v3_mocks.add_rules_in_section
|
||||
firewall.nsclient.create_resource = nsx_v3_mocks.create_resource
|
||||
firewall.nsclient.update_resource = nsx_v3_mocks.update_resource
|
||||
firewall.nsclient.get_resource = nsx_v3_mocks.get_resource
|
||||
firewall.nsclient.delete_resource = nsx_v3_mocks.delete_resource
|
||||
|
||||
|
||||
class TestNetworksV2(test_plugin.TestNetworksV2, NsxPluginV3TestCase):
|
||||
@ -64,14 +70,20 @@ class SecurityGroupsTestCase(ext_sg.SecurityGroupDBTestCase):
|
||||
def setUp(self,
|
||||
plugin=PLUGIN_NAME,
|
||||
ext_mgr=None):
|
||||
super(SecurityGroupsTestCase, self).setUp(plugin=PLUGIN_NAME,
|
||||
ext_mgr=ext_mgr)
|
||||
nsxlib.create_logical_switch = nsx_v3_mocks.create_logical_switch
|
||||
nsxlib.create_logical_port = nsx_v3_mocks.create_logical_port
|
||||
nsxlib.update_logical_port = nsx_v3_mocks.update_logical_port
|
||||
nsxlib.delete_logical_port = mock.Mock()
|
||||
nsxlib.delete_logical_switch = mock.Mock()
|
||||
|
||||
super(SecurityGroupsTestCase, self).setUp(plugin=PLUGIN_NAME,
|
||||
ext_mgr=ext_mgr)
|
||||
nsxlib.get_logical_port = nsx_v3_mocks.get_logical_port
|
||||
nsxlib.update_logical_port = nsx_v3_mocks.update_logical_port
|
||||
firewall.add_rules_in_section = nsx_v3_mocks.add_rules_in_section
|
||||
firewall.nsclient.create_resource = nsx_v3_mocks.create_resource
|
||||
firewall.nsclient.update_resource = nsx_v3_mocks.update_resource
|
||||
firewall.nsclient.get_resource = nsx_v3_mocks.get_resource
|
||||
firewall.nsclient.delete_resource = nsx_v3_mocks.delete_resource
|
||||
|
||||
|
||||
class TestSecurityGroups(ext_sg.TestSecurityGroups, SecurityGroupsTestCase):
|
||||
|
Loading…
x
Reference in New Issue
Block a user