
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
195 lines
7.9 KiB
Python
195 lines
7.9 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 xml.etree.ElementTree as et
|
|
|
|
import netaddr
|
|
from neutron.ipam import exceptions as ipam_exc
|
|
from neutron.ipam import requests as ipam_req
|
|
from neutron_lib.api.definitions import external_net as extnet_apidef
|
|
from neutron_lib.api.definitions import multiprovidernet as mpnet_apidef
|
|
from neutron_lib.api.definitions import provider_net as pnet
|
|
from neutron_lib.api import validators
|
|
from oslo_log import log as logging
|
|
|
|
from vmware_nsx._i18n import _
|
|
from vmware_nsx.plugins.nsx_v.vshield.common import constants
|
|
from vmware_nsx.plugins.nsx_v.vshield.common import exceptions as vc_exc
|
|
from vmware_nsx.services.ipam.common import driver as common
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class NsxvIpamDriver(common.NsxAbstractIpamDriver, common.NsxIpamBase):
|
|
"""IPAM Driver For NSX-V external & provider networks."""
|
|
|
|
def _is_ext_or_provider_net(self, subnet_request):
|
|
"""Return True if the network of the request is external or
|
|
provider network
|
|
"""
|
|
network_id = subnet_request.network_id
|
|
if network_id:
|
|
network = self._fetch_network(self._context, network_id)
|
|
if network.get(extnet_apidef.EXTERNAL):
|
|
# external network
|
|
return True
|
|
if (validators.is_attr_set(network.get(mpnet_apidef.SEGMENTS)) or
|
|
validators.is_attr_set(network.get(pnet.NETWORK_TYPE))):
|
|
# provider network
|
|
return True
|
|
|
|
return False
|
|
|
|
def _is_ipv6_subnet(self, subnet_request):
|
|
"""Return True if the network of the request is an ipv6 network"""
|
|
if isinstance(subnet_request, ipam_req.SpecificSubnetRequest):
|
|
return subnet_request.subnet_cidr.version == 6
|
|
else:
|
|
if subnet_request.allocation_pools:
|
|
for pool in subnet_request.allocation_pools:
|
|
if pool.version == 6:
|
|
return True
|
|
return False
|
|
|
|
def _is_supported_net(self, subnet_request):
|
|
"""This driver supports only ipv4 external/provider networks"""
|
|
return (self._is_ext_or_provider_net(subnet_request) and
|
|
not self._is_ipv6_subnet(subnet_request))
|
|
|
|
@property
|
|
def _subnet_class(self):
|
|
return NsxvIpamSubnet
|
|
|
|
def allocate_backend_pool(self, subnet_request):
|
|
"""Create a pool on the NSX backend and return its ID"""
|
|
if subnet_request.allocation_pools:
|
|
ranges = [
|
|
{'ipRangeDto':
|
|
{'startAddress': netaddr.IPAddress(pool.first),
|
|
'endAddress': netaddr.IPAddress(pool.last)}}
|
|
for pool in subnet_request.allocation_pools]
|
|
else:
|
|
ranges = []
|
|
|
|
request = {'ipamAddressPool':
|
|
# max name length on backend is 255, so there is no problem here
|
|
{'name': 'subnet_' + subnet_request.subnet_id,
|
|
'prefixLength': subnet_request.prefixlen,
|
|
'gateway': subnet_request.gateway_ip,
|
|
'ipRanges': ranges}}
|
|
|
|
try:
|
|
response = self._vcns.create_ipam_ip_pool(request)
|
|
nsx_pool_id = response[1]
|
|
except vc_exc.VcnsApiException as e:
|
|
msg = _('Failed to create subnet IPAM: %s') % e
|
|
raise ipam_exc.IpamValueInvalid(message=msg)
|
|
|
|
return nsx_pool_id
|
|
|
|
def delete_backend_pool(self, nsx_pool_id):
|
|
try:
|
|
self._vcns.delete_ipam_ip_pool(nsx_pool_id)
|
|
except vc_exc.VcnsApiException as e:
|
|
LOG.error("Failed to delete IPAM from backend: %s", e)
|
|
# Continue anyway, since this subnet was already removed
|
|
|
|
def update_backend_pool(self, subnet_request):
|
|
# The NSX-v backend does not support changing the ip pool cidr
|
|
# or gateway.
|
|
# If this function is called - there is no need to update the backend
|
|
pass
|
|
|
|
|
|
class NsxvIpamSubnet(common.NsxAbstractIpamSubnet, common.NsxIpamBase):
|
|
"""Manage IP addresses for the NSX-V IPAM driver."""
|
|
|
|
def _get_vcns_error_code(self, e):
|
|
"""Get the error code out of VcnsApiException"""
|
|
try:
|
|
desc = et.fromstring(e.response)
|
|
return int(desc.find('errorCode').text)
|
|
except Exception:
|
|
LOG.error('IPAM pool: Error code not present. %s',
|
|
e.response)
|
|
|
|
def backend_allocate(self, address_request):
|
|
try:
|
|
# allocate a specific IP
|
|
if isinstance(address_request, ipam_req.SpecificAddressRequest):
|
|
# This handles both specific and automatic address requests
|
|
ip_address = str(address_request.address)
|
|
self._vcns.allocate_ipam_ip_from_pool(self._nsx_pool_id,
|
|
ip_addr=ip_address)
|
|
else:
|
|
# Allocate any free IP
|
|
response = self._vcns.allocate_ipam_ip_from_pool(
|
|
self._nsx_pool_id)[1]
|
|
# get the ip from the response
|
|
root = et.fromstring(response)
|
|
ip_address = root.find('ipAddress').text
|
|
except vc_exc.VcnsApiException as e:
|
|
# handle backend failures
|
|
error_code = self._get_vcns_error_code(e)
|
|
if error_code == constants.NSX_ERROR_IPAM_ALLOCATE_IP_USED:
|
|
# This IP is already in use
|
|
raise ipam_exc.IpAddressAlreadyAllocated(
|
|
ip=ip_address, subnet_id=self._subnet_id)
|
|
if error_code == constants.NSX_ERROR_IPAM_ALLOCATE_ALL_USED:
|
|
# No more IP addresses available on the pool
|
|
raise ipam_exc.IpAddressGenerationFailure(
|
|
subnet_id=self._subnet_id)
|
|
raise ipam_exc.IPAllocationFailed()
|
|
return ip_address
|
|
|
|
def backend_deallocate(self, address):
|
|
try:
|
|
self._vcns.release_ipam_ip_to_pool(self._nsx_pool_id, address)
|
|
except vc_exc.VcnsApiException as e:
|
|
LOG.error("NSX IPAM failed to free ip %(ip)s of subnet %(id)s:"
|
|
" %(e)s",
|
|
{'e': e.response,
|
|
'ip': address,
|
|
'id': self._subnet_id})
|
|
raise ipam_exc.IpAddressAllocationNotFound(
|
|
subnet_id=self._subnet_id,
|
|
ip_address=address)
|
|
|
|
def _get_pool_cidr(self, pool):
|
|
# rebuild the cidr from the pool range & prefix using the first
|
|
# range in the pool, because they all should belong to the same cidr
|
|
cidr = '%s/%s' % (pool['ipRanges'][0]['startAddress'],
|
|
pool['prefixLength'])
|
|
# convert to a proper cidr
|
|
cidr = netaddr.IPNetwork(cidr).cidr
|
|
return str(cidr)
|
|
|
|
def get_details(self):
|
|
"""Return subnet data as a SpecificSubnetRequest"""
|
|
# get the pool from the backend
|
|
pool_details = self._vcns.get_ipam_ip_pool(self._nsx_pool_id)[1]
|
|
gateway_ip = pool_details['gateway']
|
|
# rebuild the cidr from the range & prefix
|
|
cidr = self._get_pool_cidr(pool_details)
|
|
pools = []
|
|
for ip_range in pool_details['ipRanges']:
|
|
pools.append(netaddr.IPRange(ip_range['startAddress'],
|
|
ip_range['endAddress']))
|
|
|
|
return ipam_req.SpecificSubnetRequest(
|
|
self._tenant_id, self._subnet_id,
|
|
cidr, gateway_ip=gateway_ip, allocation_pools=pools)
|