asarfaty 50afa71853 Fix broken Victoria branch
1.Upgrade pylint to 2.4.4, add exclusions to the tests, and
  fix some lint errors in the code

2. Fix user creation with GRANT in MySQL 8.0(Ubuntu Focal)
In Ubuntu Bionic (18.04) mysql 5.7 version used to create
the user implicitly when using using the GRANT.
Ubuntu Focal (20.04) has mysql 8.0 and with mysql 8.0 there
is no implicit user creation with GRANT. We need to
create the user first before using GRANT command.
See also commit I97b0dcbb88c6ef7c22e3c55970211bed792bbd0d

3. Remove fwaas from the zuul.yaml
4. Remove DB migration test which is failing ue to FWaaS migration
with py38
5. Fix cover tests python version in .tox
6. fix requirememnts

Change-Id: I22654a5d5ccaad3185ae3365a90afba1ce870695
2020-09-21 15:31:18 +02:00

352 lines
16 KiB
Python

# Copyright 2016 VMware, Inc.
# 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.
import netaddr
from neutron_lib.plugins import directory
from neutron_vpnaas.services.vpn import service_drivers
from oslo_log import log as logging
from oslo_utils import excutils
from vmware_nsx._i18n import _
from vmware_nsx.common import exceptions as nsxv_exc
from vmware_nsx.common import locking
from vmware_nsx.common import nsxv_constants
from vmware_nsx.db import nsxv_db
from vmware_nsx.extensions import projectpluginmap
from vmware_nsx.plugins.nsx_v.vshield.common import exceptions as vcns_exc
from vmware_nsx.services.vpnaas.nsxv import ipsec_validator
LOG = logging.getLogger(__name__)
IPSEC = 'ipsec'
class NSXvIPsecVpnDriver(service_drivers.VpnDriver):
def __init__(self, service_plugin):
self._core_plugin = directory.get_plugin()
if self._core_plugin.is_tvd_plugin():
self._core_plugin = self._core_plugin.get_plugin_by_type(
projectpluginmap.NsxPlugins.NSX_V)
self._vcns = self._core_plugin.nsx_v.vcns
validator = ipsec_validator.IPsecValidator(service_plugin)
super(NSXvIPsecVpnDriver, self).__init__(service_plugin, validator)
@property
def l3_plugin(self):
return self._core_plugin
@property
def service_type(self):
return IPSEC
def _get_router_edge_id(self, context, vpnservice_id):
vpnservice = self.service_plugin._get_vpnservice(context,
vpnservice_id)
router_id = vpnservice['router_id']
edge_binding = nsxv_db.get_nsxv_router_binding(context.session,
router_id)
if not edge_binding:
msg = _("Couldn't find edge binding for router %s") % router_id
raise nsxv_exc.NsxPluginException(err_msg=msg)
if edge_binding['edge_type'] == nsxv_constants.VDR_EDGE:
edge_manager = self._core_plugin.edge_manager
router_id = edge_manager.get_plr_by_tlr_id(context, router_id)
binding = nsxv_db.get_nsxv_router_binding(context.session,
router_id)
edge_id = binding['edge_id']
else:
# Get exclusive edge id
edge_id = edge_binding['edge_id']
return router_id, edge_id
def _convert_ipsec_conn(self, context, ipsec_site_connection):
ipsec_id = ipsec_site_connection['ipsecpolicy_id']
vpnservice_id = ipsec_site_connection['vpnservice_id']
ipsecpolicy = self.service_plugin.get_ipsecpolicy(context, ipsec_id)
vpnservice = self.service_plugin._get_vpnservice(context,
vpnservice_id)
local_cidr = vpnservice['subnet']['cidr']
router_id = vpnservice['router_id']
router = self._core_plugin.get_router(context, router_id)
local_addr = (router['external_gateway_info']['external_fixed_ips']
[0]["ip_address"])
encrypt = nsxv_constants.ENCRYPTION_ALGORITHM_MAP.get(
ipsecpolicy.get('encryption_algorithm'))
site = {
'enabled': True,
'enablePfs': True,
'dhGroup': nsxv_constants.PFS_MAP.get(ipsecpolicy.get('pfs')),
'name': ipsec_site_connection.get('name'),
'description': ipsec_site_connection.get('description'),
'localId': local_addr,
'localIp': local_addr,
'peerId': ipsec_site_connection['peer_id'],
'peerIp': ipsec_site_connection.get('peer_address'),
'localSubnets': {
'subnets': [local_cidr]},
'peerSubnets': {
'subnets': ipsec_site_connection.get('peer_cidrs')},
'authenticationMode': ipsec_site_connection.get('auth_mode'),
'psk': ipsec_site_connection.get('psk'),
'encryptionAlgorithm': encrypt
}
return site
def _generate_new_sites(self, edge_id, ipsec_site_conn):
# Fetch the previous ipsec vpn configuration
ipsecvpn_configs = self._get_ipsec_config(edge_id)
vse_sites = []
if ipsecvpn_configs[1]['enabled']:
vse_sites = ([site for site
in ipsecvpn_configs[1]['sites']['sites']])
vse_sites.append(ipsec_site_conn)
return vse_sites
def _generate_ipsecvpn_firewall_rules(self, plugin_type, context,
edge_id=None):
ipsecvpn_configs = self._get_ipsec_config(edge_id)
ipsec_vpn_fw_rules = []
if ipsecvpn_configs[1]['enabled']:
for site in ipsecvpn_configs[1]['sites']['sites']:
peer_subnets = site['peerSubnets']['subnets']
local_subnets = site['localSubnets']['subnets']
ipsec_vpn_fw_rules.append({
'name': 'VPN ' + site.get('name', 'rule'),
'action': 'allow',
'enabled': True,
'source_ip_address': peer_subnets,
'destination_ip_address': local_subnets})
return ipsec_vpn_fw_rules
def _update_firewall_rules(self, context, vpnservice_id):
vpnservice = self.service_plugin._get_vpnservice(context,
vpnservice_id)
router_db = (
self._core_plugin._get_router(context, vpnservice['router_id']))
self._core_plugin._update_subnets_and_dnat_firewall(context,
router_db)
def _update_status(self, context, vpn_service_id, ipsec_site_conn_id,
status, updated_pending_status=True):
status_list = []
vpn_status = {}
ipsec_site_conn = {}
vpn_status['id'] = vpn_service_id
vpn_status['updated_pending_status'] = updated_pending_status
vpn_status['status'] = status
ipsec_site_conn['status'] = status
ipsec_site_conn['updated_pending_status'] = updated_pending_status
vpn_status['ipsec_site_connections'] = {ipsec_site_conn_id:
ipsec_site_conn}
status_list.append(vpn_status)
self.service_plugin.update_status_by_agent(context, status_list)
def create_ipsec_site_connection(self, context, ipsec_site_connection):
LOG.debug('Creating ipsec site connection %(conn_info)s.',
{"conn_info": ipsec_site_connection})
new_ipsec = self._convert_ipsec_conn(context, ipsec_site_connection)
vpnservice_id = ipsec_site_connection['vpnservice_id']
edge_id = self._get_router_edge_id(context, vpnservice_id)[1]
with locking.LockManager.get_lock(edge_id):
vse_sites = self._generate_new_sites(edge_id, new_ipsec)
ipsec_id = ipsec_site_connection["id"]
try:
LOG.debug('Updating ipsec vpn configuration %(vse_sites)s.',
{'vse_sites': vse_sites})
self._update_ipsec_config(edge_id, vse_sites, enabled=True)
except vcns_exc.VcnsApiException:
self._update_status(context, vpnservice_id, ipsec_id,
"ERROR")
msg = (_("Failed to create ipsec site connection "
"configuration with %(edge_id)s.") %
{'edge_id': edge_id})
raise nsxv_exc.NsxPluginException(err_msg=msg)
LOG.debug('Updating ipsec vpn firewall')
try:
self._update_firewall_rules(context, vpnservice_id)
except vcns_exc.VcnsApiException:
self._update_status(context, vpnservice_id, ipsec_id, "ERROR")
msg = (_("Failed to update firewall rule for ipsec vpn "
"with %(edge_id)s.") % {'edge_id': edge_id})
raise nsxv_exc.NsxPluginException(err_msg=msg)
self._update_status(context, vpnservice_id, ipsec_id, "ACTIVE")
def _get_ipsec_config(self, edge_id):
return self._vcns.get_ipsec_config(edge_id)
def delete_ipsec_site_connection(self, context, ipsec_site_conn):
LOG.debug('Deleting ipsec site connection %(site)s.',
{"site": ipsec_site_conn})
ipsec_id = ipsec_site_conn['id']
edge_id = self._get_router_edge_id(context,
ipsec_site_conn['vpnservice_id'])[1]
with locking.LockManager.get_lock(edge_id):
del_site, vse_sites = self._find_vse_site(context, edge_id,
ipsec_site_conn)
if not del_site:
LOG.error("Failed to find ipsec_site_connection "
"%(ipsec_site_conn)s with %(edge_id)s.",
{'ipsec_site_conn': ipsec_site_conn,
'edge_id': edge_id})
raise nsxv_exc.NsxIPsecVpnMappingNotFound(conn=ipsec_id)
vse_sites.remove(del_site)
enabled = bool(vse_sites)
try:
self._update_ipsec_config(edge_id, vse_sites, enabled)
except vcns_exc.VcnsApiException:
msg = (_("Failed to delete ipsec site connection "
"configuration with edge_id: %(edge_id)s.") %
{'egde_id': edge_id})
raise nsxv_exc.NsxPluginException(err_msg=msg)
try:
self._update_firewall_rules(context,
ipsec_site_conn['vpnservice_id'])
except vcns_exc.VcnsApiException:
msg = _("Failed to update firewall rule for ipsec vpn with "
"%(edge_id)s.") % {'edge_id': edge_id}
raise nsxv_exc.NsxPluginException(err_msg=msg)
def _find_vse_site(self, context, edge_id, site):
# Fetch the previous ipsec vpn configuration
ipsecvpn_configs = self._get_ipsec_config(edge_id)[1]
vpnservice = self.service_plugin._get_vpnservice(context,
site['vpnservice_id'])
local_cidr = vpnservice['subnet']['cidr']
old_site = None
vse_sites = None
if ipsecvpn_configs['enabled']:
vse_sites = ipsecvpn_configs['sites'].get('sites')
for s in vse_sites:
if ((s['peerSubnets'].get('subnets') == site['peer_cidrs']) and
(s['localSubnets'].get('subnets')[0] == local_cidr)):
old_site = s
break
return old_site, vse_sites
def _update_site_dict(self, context, edge_id, site,
ipsec_site_connection):
# Fetch the previous ipsec vpn configuration
old_site, vse_sites = self._find_vse_site(context, edge_id, site)
if old_site:
vse_sites.remove(old_site)
if 'peer_addresses' in ipsec_site_connection:
old_site['peerIp'] = ipsec_site_connection['peer_address']
if 'peer_cidrs' in ipsec_site_connection:
old_site['peerSubnets']['subnets'] = (ipsec_site_connection
['peer_cidrs'])
vse_sites.append(old_site)
return vse_sites
def update_ipsec_site_connection(self, context, old_ipsec_conn,
ipsec_site_connection):
LOG.debug('Updating ipsec site connection %(site)s.',
{"site": ipsec_site_connection})
vpnservice_id = old_ipsec_conn['vpnservice_id']
ipsec_id = old_ipsec_conn['id']
edge_id = self._get_router_edge_id(context, vpnservice_id)[1]
with locking.LockManager.get_lock(edge_id):
vse_sites = self._update_site_dict(context, edge_id,
old_ipsec_conn,
ipsec_site_connection)
if not vse_sites:
self._update_status(context, vpnservice_id, ipsec_id,
"ERROR")
LOG.error("Failed to find ipsec_site_connection "
"%(ipsec_site_conn)s with %(edge_id)s.",
{'ipsec_site_conn': ipsec_site_connection,
'edge_id': edge_id})
raise nsxv_exc.NsxIPsecVpnMappingNotFound(conn=ipsec_id)
try:
LOG.debug('Updating ipsec vpn configuration %(vse_sites)s.',
{'vse_sites': vse_sites})
self._update_ipsec_config(edge_id, vse_sites)
except vcns_exc.VcnsApiException:
self._update_status(context, vpnservice_id, ipsec_id, "ERROR")
msg = (_("Failed to create ipsec site connection "
"configuration with %(edge_id)s.") %
{'edge_id': edge_id})
raise nsxv_exc.NsxPluginException(err_msg=msg)
if 'peer_cidrs' in ipsec_site_connection:
# Update firewall
old_ipsec_conn['peer_cidrs'] = (
ipsec_site_connection['peer_cidrs'])
try:
self._update_firewall_rules(context, vpnservice_id)
except vcns_exc.VcnsApiException:
self._update_status(context, vpnservice_id, ipsec_id,
"ERROR")
msg = (_("Failed to update firewall rule for ipsec "
"vpn with %(edge_id)s.") % {'edge_id': edge_id})
raise nsxv_exc.NsxPluginException(err_msg=msg)
def _get_gateway_ips(self, router):
"""Obtain the IPv4 and/or IPv6 GW IP for the router.
If there are multiples, (arbitrarily) use the first one.
"""
v4_ip = v6_ip = None
for fixed_ip in router.gw_port['fixed_ips']:
addr = fixed_ip['ip_address']
vers = netaddr.IPAddress(addr).version
if vers == 4:
if v4_ip is None:
v4_ip = addr
elif v6_ip is None:
v6_ip = addr
return v4_ip, v6_ip
def create_vpnservice(self, context, vpnservice):
LOG.debug('Creating VPN service %(vpn)s', {'vpn': vpnservice})
vpnservice_id = vpnservice['id']
try:
self.validator.validate_vpnservice(context, vpnservice)
except Exception:
with excutils.save_and_reraise_exception():
# Rolling back change on the neutron
self.service_plugin.delete_vpnservice(context, vpnservice_id)
vpnservice = self.service_plugin._get_vpnservice(context,
vpnservice_id)
v4_ip, v6_ip = self._get_gateway_ips(vpnservice.router)
if v4_ip:
vpnservice['external_v4_ip'] = v4_ip
if v6_ip:
vpnservice['external_v6_ip'] = v6_ip
self.service_plugin.set_external_tunnel_ips(context,
vpnservice_id,
v4_ip=v4_ip, v6_ip=v6_ip)
def update_vpnservice(self, context, old_vpnservice, vpnservice):
pass
def delete_vpnservice(self, context, vpnservice):
pass
def _update_ipsec_config(self, edge_id, sites, enabled=True):
ipsec_config = {'featureType': "ipsec_4.0",
'enabled': enabled}
ipsec_config['sites'] = {'sites': sites}
try:
self._vcns.update_ipsec_config(edge_id, ipsec_config)
except vcns_exc.VcnsApiException:
msg = _("Failed to update ipsec vpn configuration with "
"edge_id: %s") % edge_id
raise nsxv_exc.NsxPluginException(err_msg=msg)