Fix plugging member subnets on existing networks
CalculateAmphoraDelta uses now subnest instead of networks. HandleNetworkDelta plugs subnets on existing ports, or removes subnet from ports The Amphora server supports multiple 'plug' calls to the same port, allowing to update the settings of an interface. Co-Authored-By: Gregory Thiemonge <gthiemon@redhat.com> Depends-On: https://review.opendev.org/815313 Change-Id: I1384c6f52eec99e6573a8e83fe5a80a632804083
This commit is contained in:
parent
1a25289e2e
commit
79898a49b7
|
@ -66,7 +66,7 @@ class BaseOS(object):
|
|||
def write_vip_interface_file(self, interface, vip, ip_version,
|
||||
prefixlen, gateway,
|
||||
mtu, vrrp_ip,
|
||||
host_routes):
|
||||
host_routes, fixed_ips=None):
|
||||
vip_interface = interface_file.VIPInterfaceFile(
|
||||
name=interface,
|
||||
mtu=mtu,
|
||||
|
@ -76,6 +76,7 @@ class BaseOS(object):
|
|||
gateway=gateway,
|
||||
vrrp_ip=vrrp_ip,
|
||||
host_routes=host_routes,
|
||||
fixed_ips=fixed_ips,
|
||||
topology=CONF.controller_worker.loadbalancer_topology)
|
||||
vip_interface.write()
|
||||
|
||||
|
@ -94,7 +95,8 @@ class BaseOS(object):
|
|||
try:
|
||||
out = subprocess.check_output(cmd.split(),
|
||||
stderr=subprocess.STDOUT)
|
||||
LOG.debug(out)
|
||||
for line in out.decode('utf-8').split('\n'):
|
||||
LOG.debug(line)
|
||||
except subprocess.CalledProcessError as e:
|
||||
LOG.error('Failed to set up %s due to error: %s %s', interface,
|
||||
e, e.output)
|
||||
|
|
|
@ -132,16 +132,52 @@ class Plug(object):
|
|||
except socket.error:
|
||||
socket.inet_pton(socket.AF_INET6, ip.get('ip_address'))
|
||||
|
||||
def plug_network(self, mac_address, fixed_ips, mtu=None):
|
||||
def plug_network(self, mac_address, fixed_ips, mtu=None,
|
||||
vip_net_info=None):
|
||||
# Check if the interface is already in the network namespace
|
||||
# Do not attempt to re-plug the network if it is already in the
|
||||
# network namespace
|
||||
# network namespace, just ensure all fixed_ips are up
|
||||
if self._netns_interface_exists(mac_address):
|
||||
return webob.Response(json=dict(
|
||||
message="Interface already exists"), status=409)
|
||||
# Get the existing interface name and path
|
||||
existing_interface = self._netns_interface_by_mac(mac_address)
|
||||
|
||||
# This is the interface as it was initially plugged into the
|
||||
# default network namespace, this will likely always be eth1
|
||||
# If we have net_info, this is the special case of plugging a new
|
||||
# subnet on the vrrp port, which is essentially a re-vip-plug
|
||||
if vip_net_info:
|
||||
ip = ipaddress.ip_address(vip_net_info['vip'])
|
||||
network = ipaddress.ip_network(vip_net_info['subnet_cidr'])
|
||||
vip = ip.exploded
|
||||
prefixlen = network.prefixlen
|
||||
|
||||
vrrp_ip = vip_net_info.get('vrrp_ip')
|
||||
gateway = vip_net_info['gateway']
|
||||
host_routes = vip_net_info.get('host_routes', ())
|
||||
|
||||
self._osutils.write_vip_interface_file(
|
||||
interface=existing_interface,
|
||||
vip=vip,
|
||||
ip_version=ip.version,
|
||||
prefixlen=prefixlen,
|
||||
gateway=gateway,
|
||||
vrrp_ip=vrrp_ip,
|
||||
host_routes=host_routes,
|
||||
mtu=mtu,
|
||||
fixed_ips=fixed_ips)
|
||||
self._osutils.bring_interface_up(existing_interface, 'vip')
|
||||
# Otherwise, we are just plugging a run-of-the-mill network
|
||||
else:
|
||||
# Write an updated config
|
||||
self._osutils.write_port_interface_file(
|
||||
interface=existing_interface,
|
||||
fixed_ips=fixed_ips,
|
||||
mtu=mtu)
|
||||
self._osutils.bring_interface_up(existing_interface, 'network')
|
||||
return webob.Response(json=dict(
|
||||
message="OK",
|
||||
details="Updated existing interface {interface}".format(
|
||||
# TODO(rm_work): Everything in this should probably use
|
||||
# HTTP code 200, but continuing to use 202 for consistency.
|
||||
interface=existing_interface)), status=202)
|
||||
|
||||
try:
|
||||
self._check_ip_addresses(fixed_ips=fixed_ips)
|
||||
|
@ -149,6 +185,8 @@ class Plug(object):
|
|||
return webob.Response(json=dict(
|
||||
message="Invalid network port"), status=400)
|
||||
|
||||
# This is the interface as it was initially plugged into the
|
||||
# default network namespace, this will likely always be eth1
|
||||
default_netns_interface = self._interface_by_mac(mac_address)
|
||||
|
||||
# We need to determine the interface name when inside the namespace
|
||||
|
@ -222,11 +260,14 @@ class Plug(object):
|
|||
text_file.write("{mac_address} {interface}\n".format(
|
||||
mac_address=mac_address, interface=interface))
|
||||
|
||||
def _netns_interface_exists(self, mac_address):
|
||||
def _netns_interface_by_mac(self, mac_address):
|
||||
with pyroute2.NetNS(consts.AMPHORA_NAMESPACE,
|
||||
flags=os.O_CREAT) as netns:
|
||||
for link in netns.get_links():
|
||||
for attr in link['attrs']:
|
||||
if attr[0] == 'IFLA_ADDRESS' and attr[1] == mac_address:
|
||||
return True
|
||||
return False
|
||||
attr_dict = dict(link['attrs'])
|
||||
if attr_dict.get('IFLA_ADDRESS') == mac_address:
|
||||
return attr_dict.get('IFLA_IFNAME')
|
||||
return None
|
||||
|
||||
def _netns_interface_exists(self, mac_address):
|
||||
return self._netns_interface_by_mac(mac_address) is not None
|
||||
|
|
|
@ -214,7 +214,8 @@ class Server(object):
|
|||
description='Invalid port information') from e
|
||||
return self._plug.plug_network(port_info['mac_address'],
|
||||
port_info.get('fixed_ips'),
|
||||
port_info.get('mtu'))
|
||||
port_info.get('mtu'),
|
||||
port_info.get('vip_net_info'))
|
||||
|
||||
def upload_cert(self):
|
||||
return certificate_update.upload_server_cert()
|
||||
|
|
|
@ -162,6 +162,8 @@ class AmphoraLoadBalancerDriver(object, metaclass=abc.ABCMeta):
|
|||
:param amphorae_network_config: A data model containing information
|
||||
about the subnets and ports that an
|
||||
amphorae owns.
|
||||
:type amphorae_network_config: octavia.network.data_models.
|
||||
AmphoraNetworkConfig
|
||||
:param vrrp_port: VRRP port associated with the load balancer
|
||||
:type vrrp_port: octavia.network.data_models.Port
|
||||
|
||||
|
@ -175,13 +177,18 @@ class AmphoraLoadBalancerDriver(object, metaclass=abc.ABCMeta):
|
|||
the vip, such as bring up interfaces.
|
||||
"""
|
||||
|
||||
def post_network_plug(self, amphora, port):
|
||||
def post_network_plug(self, amphora, port, amphora_network_config):
|
||||
"""Called after amphora added to network
|
||||
|
||||
:param amphora: amphora object, needs id and network ip(s)
|
||||
:type amphora: octavia.db.models.Amphora
|
||||
:param port: contains information of the plugged port
|
||||
:type port: octavia.network.data_models.Port
|
||||
:param amphora_network_config: A data model containing information
|
||||
about the subnets and ports that an
|
||||
amphorae owns.
|
||||
:type amphora_network_config: octavia.network.data_models.
|
||||
AmphoraNetworkConfig
|
||||
|
||||
This method is optional to implement. After adding an amphora to a
|
||||
network, there may be steps necessary on the amphora to allow it to
|
||||
|
|
|
@ -39,6 +39,7 @@ from octavia.common.tls_utils import cert_parser
|
|||
from octavia.common import utils
|
||||
from octavia.db import api as db_apis
|
||||
from octavia.db import repositories as repo
|
||||
from octavia.network import data_models as network_models
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -381,23 +382,33 @@ class HaproxyAmphoraLoadBalancerDriver(
|
|||
def finalize_amphora(self, amphora):
|
||||
pass
|
||||
|
||||
def _build_net_info(self, port, amphora, subnet, mtu=None):
|
||||
# NOTE(blogan): using the vrrp port here because that
|
||||
# is what the allowed address pairs network driver sets
|
||||
# this particular port to. This does expose a bit of
|
||||
# tight coupling between the network driver and amphora
|
||||
# driver. We will need to revisit this to try and remove
|
||||
# this tight coupling.
|
||||
# NOTE (johnsom): I am loading the vrrp_ip into the
|
||||
# net_info structure here so that I don't break
|
||||
# compatibility with old amphora agent versions.
|
||||
host_routes = [{'nexthop': hr[consts.NEXTHOP],
|
||||
'destination': hr[consts.DESTINATION]}
|
||||
for hr in subnet[consts.HOST_ROUTES]]
|
||||
net_info = {'subnet_cidr': subnet[consts.CIDR],
|
||||
'gateway': subnet[consts.GATEWAY_IP],
|
||||
'mac_address': port[consts.MAC_ADDRESS],
|
||||
'vrrp_ip': amphora[consts.VRRP_IP],
|
||||
'mtu': mtu or port[consts.NETWORK][consts.MTU],
|
||||
'host_routes': host_routes}
|
||||
return net_info
|
||||
|
||||
def post_vip_plug(self, amphora, load_balancer, amphorae_network_config,
|
||||
vrrp_port=None, vip_subnet=None):
|
||||
if amphora.status != consts.DELETED:
|
||||
self._populate_amphora_api_version(amphora)
|
||||
if vip_subnet is None:
|
||||
subnet = amphorae_network_config.get(amphora.id).vip_subnet
|
||||
else:
|
||||
subnet = vip_subnet
|
||||
# NOTE(blogan): using the vrrp port here because that
|
||||
# is what the allowed address pairs network driver sets
|
||||
# this particular port to. This does expose a bit of
|
||||
# tight coupling between the network driver and amphora
|
||||
# driver. We will need to revisit this to try and remove
|
||||
# this tight coupling.
|
||||
# NOTE (johnsom): I am loading the vrrp_ip into the
|
||||
# net_info structure here so that I don't break
|
||||
# compatibility with old amphora agent versions.
|
||||
vip_subnet = amphorae_network_config.get(amphora.id).vip_subnet
|
||||
if vrrp_port is None:
|
||||
port = amphorae_network_config.get(amphora.id).vrrp_port
|
||||
mtu = port.network.mtu
|
||||
|
@ -406,15 +417,9 @@ class HaproxyAmphoraLoadBalancerDriver(
|
|||
mtu = port.network['mtu']
|
||||
LOG.debug("Post-VIP-Plugging with vrrp_ip %s vrrp_port %s",
|
||||
amphora.vrrp_ip, port.id)
|
||||
host_routes = [{'nexthop': hr.nexthop,
|
||||
'destination': hr.destination}
|
||||
for hr in subnet.host_routes]
|
||||
net_info = {'subnet_cidr': subnet.cidr,
|
||||
'gateway': subnet.gateway_ip,
|
||||
'mac_address': port.mac_address,
|
||||
'vrrp_ip': amphora.vrrp_ip,
|
||||
'mtu': mtu,
|
||||
'host_routes': host_routes}
|
||||
net_info = self._build_net_info(
|
||||
port.to_dict(recurse=True), amphora.to_dict(),
|
||||
vip_subnet.to_dict(recurse=True), mtu)
|
||||
try:
|
||||
self.clients[amphora.api_version].plug_vip(
|
||||
amphora, load_balancer.vip.ip_address, net_info)
|
||||
|
@ -423,7 +428,7 @@ class HaproxyAmphoraLoadBalancerDriver(
|
|||
'skipping post_vip_plug',
|
||||
{'mac': port.mac_address})
|
||||
|
||||
def post_network_plug(self, amphora, port):
|
||||
def post_network_plug(self, amphora, port, amphora_network_config):
|
||||
fixed_ips = []
|
||||
for fixed_ip in port.fixed_ips:
|
||||
host_routes = [{'nexthop': hr.nexthop,
|
||||
|
@ -431,11 +436,25 @@ class HaproxyAmphoraLoadBalancerDriver(
|
|||
for hr in fixed_ip.subnet.host_routes]
|
||||
ip = {'ip_address': fixed_ip.ip_address,
|
||||
'subnet_cidr': fixed_ip.subnet.cidr,
|
||||
'host_routes': host_routes}
|
||||
'host_routes': host_routes,
|
||||
'gateway': fixed_ip.subnet.gateway_ip}
|
||||
fixed_ips.append(ip)
|
||||
port_info = {'mac_address': port.mac_address,
|
||||
'fixed_ips': fixed_ips,
|
||||
'mtu': port.network.mtu}
|
||||
if port.id == amphora.vrrp_port_id:
|
||||
if isinstance(amphora_network_config,
|
||||
network_models.AmphoraNetworkConfig):
|
||||
amphora_network_config = amphora_network_config.to_dict(
|
||||
recurse=True)
|
||||
# We have to special-case sharing the vrrp port and pass through
|
||||
# enough extra information to populate the whole VIP port
|
||||
net_info = self._build_net_info(
|
||||
port.to_dict(recurse=True), amphora.to_dict(),
|
||||
amphora_network_config[consts.VIP_SUBNET],
|
||||
port.network.mtu)
|
||||
net_info['vip'] = amphora.ha_ip
|
||||
port_info['vip_net_info'] = net_info
|
||||
try:
|
||||
self._populate_amphora_api_version(amphora)
|
||||
self.clients[amphora.api_version].plug_network(amphora, port_info)
|
||||
|
|
|
@ -85,9 +85,10 @@ class NoopManager(object):
|
|||
self.__class__.__name__, amphora.id)
|
||||
self.amphoraconfig[amphora.id] = (amphora.id, 'finalize amphora')
|
||||
|
||||
def post_network_plug(self, amphora, port):
|
||||
LOG.debug("Amphora %s no-op, post network plug amphora %s, port %s",
|
||||
self.__class__.__name__, amphora.id, port.id)
|
||||
def post_network_plug(self, amphora, port, amphora_network_config):
|
||||
LOG.debug("Amphora %s no-op, post network plug amphora %s, port %s, "
|
||||
"amphora_network_config %s", self.__class__.__name__,
|
||||
amphora.id, port.id, amphora_network_config)
|
||||
self.amphoraconfig[amphora.id, port.id] = (amphora.id, port.id,
|
||||
'post_network_plug')
|
||||
|
||||
|
@ -160,9 +161,9 @@ class NoopAmphoraLoadBalancerDriver(
|
|||
|
||||
self.driver.finalize_amphora(amphora)
|
||||
|
||||
def post_network_plug(self, amphora, port):
|
||||
def post_network_plug(self, amphora, port, amphora_network_config):
|
||||
|
||||
self.driver.post_network_plug(amphora, port)
|
||||
self.driver.post_network_plug(amphora, port, amphora_network_config)
|
||||
|
||||
def post_vip_plug(self, amphora, load_balancer, amphorae_network_config,
|
||||
vrrp_port=None, vip_subnet=None):
|
||||
|
|
|
@ -298,7 +298,7 @@ SUPPORTED_TASKFLOW_ENGINE_TYPES = ['serial', 'parallel']
|
|||
# Task/Flow constants
|
||||
ACTIVE_CONNECTIONS = 'active_connections'
|
||||
ADD_NICS = 'add_nics'
|
||||
ADDED_PORTS = 'added_ports'
|
||||
ADD_SUBNETS = 'add_subnets'
|
||||
ADMIN_STATE_UP = 'admin_state_up'
|
||||
ALLOWED_ADDRESS_PAIRS = 'allowed_address_pairs'
|
||||
AMP_DATA = 'amp_data'
|
||||
|
@ -330,9 +330,11 @@ CREATED_AT = 'created_at'
|
|||
CRL_CONTAINER_ID = 'crl_container_id'
|
||||
DEFAULT_TLS_CONTAINER_DATA = 'default_tls_container_data'
|
||||
DELETE_NICS = 'delete_nics'
|
||||
DELETE_SUBNETS = 'delete_subnets'
|
||||
DELTA = 'delta'
|
||||
DELTAS = 'deltas'
|
||||
DESCRIPTION = 'description'
|
||||
DESTINATION = 'destination'
|
||||
DEVICE_OWNER = 'device_owner'
|
||||
ENABLED = 'enabled'
|
||||
FAILED_AMP_VRRP_PORT_ID = 'failed_amp_vrrp_port_id'
|
||||
|
@ -342,6 +344,7 @@ FAILOVER_AMPHORA_ID = 'failover_amphora_id'
|
|||
FIELDS = 'fields'
|
||||
FIXED_IPS = 'fixed_ips'
|
||||
FLAVOR_ID = 'flavor_id'
|
||||
GATEWAY_IP = 'gateway_ip'
|
||||
HA_IP = 'ha_ip'
|
||||
HA_PORT_ID = 'ha_port_id'
|
||||
HEALTH_MON = 'health_mon'
|
||||
|
@ -349,6 +352,7 @@ HEALTH_MONITOR = 'health_monitor'
|
|||
HEALTH_MONITOR_ID = 'health_monitor_id'
|
||||
HEALTHMONITOR_ID = 'healthmonitor_id'
|
||||
HEALTH_MONITOR_UPDATES = 'health_monitor_updates'
|
||||
HOST_ROUTES = 'host_routes'
|
||||
ID = 'id'
|
||||
IMAGE_ID = 'image_id'
|
||||
IP_ADDRESS = 'ip_address'
|
||||
|
@ -367,6 +371,7 @@ LOADBALANCER = 'loadbalancer'
|
|||
LOADBALANCER_ID = 'loadbalancer_id'
|
||||
LOAD_BALANCER_ID = 'load_balancer_id'
|
||||
LOAD_BALANCER_UPDATES = 'load_balancer_updates'
|
||||
MAC_ADDRESS = 'mac_address'
|
||||
MANAGEMENT_NETWORK = 'management_network'
|
||||
MEMBER = 'member'
|
||||
MEMBER_ID = 'member_id'
|
||||
|
@ -376,6 +381,7 @@ MESSAGE = 'message'
|
|||
NAME = 'name'
|
||||
NETWORK = 'network'
|
||||
NETWORK_ID = 'network_id'
|
||||
NEXTHOP = 'nexthop'
|
||||
NICS = 'nics'
|
||||
OBJECT = 'object'
|
||||
ORIGINAL_HEALTH_MONITOR = 'original_health_monitor'
|
||||
|
@ -423,10 +429,12 @@ TOPOLOGY = 'topology'
|
|||
TOTAL_CONNECTIONS = 'total_connections'
|
||||
UPDATED_AT = 'updated_at'
|
||||
UPDATE_DICT = 'update_dict'
|
||||
UPDATED_PORTS = 'updated_ports'
|
||||
VALID_VIP_NETWORKS = 'valid_vip_networks'
|
||||
VIP = 'vip'
|
||||
VIP_ADDRESS = 'vip_address'
|
||||
VIP_NETWORK = 'vip_network'
|
||||
VIP_NETWORK_ID = 'vip_network_id'
|
||||
VIP_PORT_ID = 'vip_port_id'
|
||||
VIP_QOS_POLICY_ID = 'vip_qos_policy_id'
|
||||
VIP_SG_ID = 'vip_sg_id'
|
||||
|
|
|
@ -429,6 +429,7 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
|
|||
constants.MEMBER: member,
|
||||
constants.LISTENERS: listeners,
|
||||
constants.LOADBALANCER: load_balancer,
|
||||
constants.LOADBALANCER_ID: load_balancer.id,
|
||||
constants.POOL: pool}
|
||||
if load_balancer.availability_zone:
|
||||
store[constants.AVAILABILITY_ZONE] = (
|
||||
|
@ -461,6 +462,7 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
|
|||
constants.MEMBER: member,
|
||||
constants.LISTENERS: listeners,
|
||||
constants.LOADBALANCER: load_balancer,
|
||||
constants.LOADBALANCER_ID: load_balancer.id,
|
||||
constants.POOL: pool}
|
||||
if load_balancer.availability_zone:
|
||||
store[constants.AVAILABILITY_ZONE] = (
|
||||
|
|
|
@ -443,11 +443,11 @@ class AmphoraFlows(object):
|
|||
amp_for_failover_flow.add(network_tasks.HandleNetworkDelta(
|
||||
name=prefix + '-' + constants.HANDLE_NETWORK_DELTA,
|
||||
requires=(constants.AMPHORA, constants.DELTA),
|
||||
provides=constants.ADDED_PORTS))
|
||||
provides=constants.UPDATED_PORTS))
|
||||
|
||||
amp_for_failover_flow.add(amphora_driver_tasks.AmphoraePostNetworkPlug(
|
||||
name=prefix + '-' + constants.AMPHORAE_POST_NETWORK_PLUG,
|
||||
requires=(constants.LOADBALANCER, constants.ADDED_PORTS)))
|
||||
requires=(constants.LOADBALANCER, constants.UPDATED_PORTS)))
|
||||
|
||||
return amp_for_failover_flow
|
||||
|
||||
|
|
|
@ -202,12 +202,12 @@ class LoadBalancerFlows(object):
|
|||
)
|
||||
flows.append(
|
||||
network_tasks.HandleNetworkDeltas(
|
||||
requires=constants.DELTAS, provides=constants.ADDED_PORTS
|
||||
requires=constants.DELTAS, provides=constants.UPDATED_PORTS
|
||||
)
|
||||
)
|
||||
flows.append(
|
||||
amphora_driver_tasks.AmphoraePostNetworkPlug(
|
||||
requires=(constants.LOADBALANCER, constants.ADDED_PORTS)
|
||||
requires=(constants.LOADBALANCER, constants.UPDATED_PORTS)
|
||||
)
|
||||
)
|
||||
flows.append(
|
||||
|
|
|
@ -43,10 +43,14 @@ class MemberFlows(object):
|
|||
requires=(constants.LOADBALANCER, constants.AVAILABILITY_ZONE),
|
||||
provides=constants.DELTAS))
|
||||
create_member_flow.add(network_tasks.HandleNetworkDeltas(
|
||||
requires=constants.DELTAS, provides=constants.ADDED_PORTS))
|
||||
requires=(constants.DELTAS, constants.LOADBALANCER),
|
||||
provides=constants.UPDATED_PORTS))
|
||||
create_member_flow.add(network_tasks.GetAmphoraeNetworkConfigs(
|
||||
requires=constants.LOADBALANCER_ID,
|
||||
provides=constants.AMPHORAE_NETWORK_CONFIG))
|
||||
create_member_flow.add(amphora_driver_tasks.AmphoraePostNetworkPlug(
|
||||
requires=(constants.LOADBALANCER, constants.ADDED_PORTS)
|
||||
))
|
||||
requires=(constants.LOADBALANCER, constants.UPDATED_PORTS,
|
||||
constants.AMPHORAE_NETWORK_CONFIG)))
|
||||
create_member_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||
requires=constants.LOADBALANCER))
|
||||
create_member_flow.add(database_tasks.MarkMemberActiveInDB(
|
||||
|
@ -73,6 +77,18 @@ class MemberFlows(object):
|
|||
constants.POOL]))
|
||||
delete_member_flow.add(database_tasks.MarkMemberPendingDeleteInDB(
|
||||
requires=constants.MEMBER))
|
||||
delete_member_flow.add(network_tasks.CalculateDelta(
|
||||
requires=(constants.LOADBALANCER, constants.AVAILABILITY_ZONE),
|
||||
provides=constants.DELTAS))
|
||||
delete_member_flow.add(network_tasks.HandleNetworkDeltas(
|
||||
requires=(constants.DELTAS, constants.LOADBALANCER),
|
||||
provides=constants.UPDATED_PORTS))
|
||||
delete_member_flow.add(network_tasks.GetAmphoraeNetworkConfigs(
|
||||
requires=constants.LOADBALANCER_ID,
|
||||
provides=constants.AMPHORAE_NETWORK_CONFIG))
|
||||
delete_member_flow.add(amphora_driver_tasks.AmphoraePostNetworkPlug(
|
||||
requires=(constants.LOADBALANCER, constants.UPDATED_PORTS,
|
||||
constants.AMPHORAE_NETWORK_CONFIG)))
|
||||
delete_member_flow.add(model_tasks.
|
||||
DeleteModelObject(rebind={constants.OBJECT:
|
||||
constants.MEMBER}))
|
||||
|
@ -188,10 +204,15 @@ class MemberFlows(object):
|
|||
requires=(constants.LOADBALANCER, constants.AVAILABILITY_ZONE),
|
||||
provides=constants.DELTAS))
|
||||
batch_update_members_flow.add(network_tasks.HandleNetworkDeltas(
|
||||
requires=constants.DELTAS, provides=constants.ADDED_PORTS))
|
||||
requires=(constants.DELTAS, constants.LOADBALANCER),
|
||||
provides=constants.UPDATED_PORTS))
|
||||
batch_update_members_flow.add(network_tasks.GetAmphoraeNetworkConfigs(
|
||||
requires=constants.LOADBALANCER_ID,
|
||||
provides=constants.AMPHORAE_NETWORK_CONFIG))
|
||||
batch_update_members_flow.add(
|
||||
amphora_driver_tasks.AmphoraePostNetworkPlug(
|
||||
requires=(constants.LOADBALANCER, constants.ADDED_PORTS)))
|
||||
requires=(constants.LOADBALANCER, constants.UPDATED_PORTS,
|
||||
constants.AMPHORAE_NETWORK_CONFIG)))
|
||||
|
||||
# Update the Listener (this makes the changes active on the Amp)
|
||||
batch_update_members_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||
|
|
|
@ -196,10 +196,11 @@ class AmphoraFinalize(BaseAmphoraTask):
|
|||
class AmphoraPostNetworkPlug(BaseAmphoraTask):
|
||||
"""Task to notify the amphora post network plug."""
|
||||
|
||||
def execute(self, amphora, ports):
|
||||
def execute(self, amphora, ports, amphora_network_config):
|
||||
"""Execute post_network_plug routine."""
|
||||
for port in ports:
|
||||
self.amphora_driver.post_network_plug(amphora, port)
|
||||
self.amphora_driver.post_network_plug(
|
||||
amphora, port, amphora_network_config)
|
||||
LOG.debug("post_network_plug called on compute instance "
|
||||
"%(compute_id)s for port %(port_id)s",
|
||||
{"compute_id": amphora.compute_id, "port_id": port.id})
|
||||
|
@ -215,7 +216,7 @@ class AmphoraPostNetworkPlug(BaseAmphoraTask):
|
|||
class AmphoraePostNetworkPlug(BaseAmphoraTask):
|
||||
"""Task to notify the amphorae post network plug."""
|
||||
|
||||
def execute(self, loadbalancer, added_ports):
|
||||
def execute(self, loadbalancer, updated_ports, amphorae_network_config):
|
||||
"""Execute post_network_plug routine."""
|
||||
amp_post_plug = AmphoraPostNetworkPlug()
|
||||
# We need to make sure we have the fresh list of amphora
|
||||
|
@ -223,10 +224,11 @@ class AmphoraePostNetworkPlug(BaseAmphoraTask):
|
|||
db_apis.get_session(), load_balancer_id=loadbalancer.id,
|
||||
status=constants.AMPHORA_ALLOCATED)[0]
|
||||
for amphora in amphorae:
|
||||
if amphora.id in added_ports:
|
||||
amp_post_plug.execute(amphora, added_ports[amphora.id])
|
||||
if amphora.id in updated_ports:
|
||||
amp_post_plug.execute(amphora, updated_ports[amphora.id],
|
||||
amphorae_network_config[amphora.id])
|
||||
|
||||
def revert(self, result, loadbalancer, added_ports, *args, **kwargs):
|
||||
def revert(self, result, loadbalancer, updated_ports, *args, **kwargs):
|
||||
"""Handle a failed post network plug."""
|
||||
if isinstance(result, failure.Failure):
|
||||
return
|
||||
|
|
|
@ -58,37 +58,101 @@ class CalculateAmphoraDelta(BaseNetworkTask):
|
|||
LOG.debug("Calculating network delta for amphora id: %s", amphora.id)
|
||||
|
||||
if vrrp_port is None:
|
||||
vrrp_port = self.network_driver.get_port(amphora.vrrp_port_id)
|
||||
vrrp_port = self.network_driver.get_port(
|
||||
amphora.vrrp_port_id)
|
||||
|
||||
vip_subnet_to_net_map = {
|
||||
loadbalancer.vip.subnet_id:
|
||||
loadbalancer.vip.network_id,
|
||||
}
|
||||
|
||||
# Figure out what networks we want
|
||||
# seed with lb network(s)
|
||||
if (availability_zone and
|
||||
availability_zone.get(constants.MANAGEMENT_NETWORK)):
|
||||
management_nets = [availability_zone.get(
|
||||
constants.MANAGEMENT_NETWORK)]
|
||||
management_nets = [
|
||||
availability_zone.get(constants.MANAGEMENT_NETWORK)]
|
||||
else:
|
||||
management_nets = CONF.controller_worker.amp_boot_network_list
|
||||
desired_network_ids = {vrrp_port.network_id}.union(management_nets)
|
||||
|
||||
desired_subnet_to_net_map = {
|
||||
subnet: mgmt_net_id
|
||||
for mgmt_net_id in management_nets
|
||||
for subnet in self.network_driver.get_network(
|
||||
mgmt_net_id).subnets
|
||||
}
|
||||
desired_subnet_to_net_map.update(vip_subnet_to_net_map)
|
||||
|
||||
for pool in loadbalancer.pools:
|
||||
member_networks = [
|
||||
self.network_driver.get_subnet(member.subnet_id).network_id
|
||||
for member in pool.members
|
||||
if member.subnet_id
|
||||
]
|
||||
desired_network_ids.update(member_networks)
|
||||
for member in pool.members:
|
||||
if (member.subnet_id and
|
||||
member.provisioning_status !=
|
||||
constants.PENDING_DELETE):
|
||||
member_network = self.network_driver.get_subnet(
|
||||
member.subnet_id).network_id
|
||||
desired_subnet_to_net_map[member.subnet_id] = (
|
||||
member_network)
|
||||
|
||||
nics = self.network_driver.get_plugged_networks(amphora.compute_id)
|
||||
desired_network_ids = set(desired_subnet_to_net_map.values())
|
||||
desired_subnet_ids = set(desired_subnet_to_net_map)
|
||||
|
||||
# Calculate Network deltas
|
||||
nics = self.network_driver.get_plugged_networks(
|
||||
amphora.compute_id)
|
||||
# assume we don't have two nics in the same network
|
||||
actual_network_nics = dict((nic.network_id, nic) for nic in nics)
|
||||
# TODO(rm_work): how accurate is this assumption really?
|
||||
network_to_nic_map = {nic.network_id: nic for nic in nics}
|
||||
|
||||
del_ids = set(actual_network_nics) - desired_network_ids
|
||||
delete_nics = list(
|
||||
actual_network_nics[net_id] for net_id in del_ids)
|
||||
del_ids = set(network_to_nic_map) - desired_network_ids
|
||||
delete_nics = [n_data_models.Interface(
|
||||
network_id=net_id,
|
||||
port_id=network_to_nic_map[net_id].port_id)
|
||||
for net_id in del_ids]
|
||||
|
||||
add_ids = desired_network_ids - set(network_to_nic_map)
|
||||
add_nics = [n_data_models.Interface(
|
||||
network_id=net_id,
|
||||
fixed_ips=[
|
||||
n_data_models.FixedIP(
|
||||
subnet_id=subnet_id)
|
||||
for subnet_id in desired_subnet_to_net_map
|
||||
if desired_subnet_to_net_map[subnet_id] == net_id])
|
||||
for net_id in add_ids]
|
||||
|
||||
# Calculate member Subnet deltas
|
||||
plugged_subnets = {
|
||||
fixed_ip.subnet_id: nic.network_id
|
||||
for nic in network_to_nic_map.values()
|
||||
for fixed_ip in nic.fixed_ips or []
|
||||
}
|
||||
|
||||
del_subnet_ids = set(plugged_subnets) - desired_subnet_ids
|
||||
add_subnet_ids = desired_subnet_ids - set(plugged_subnets)
|
||||
|
||||
def _subnet_updates(subnet_ids, subnets):
|
||||
updates = []
|
||||
for s in subnet_ids:
|
||||
network_id = subnets[s]
|
||||
nic = network_to_nic_map.get(network_id)
|
||||
port_id = nic.port_id if nic else None
|
||||
updates.append({
|
||||
constants.SUBNET_ID: s,
|
||||
constants.NETWORK_ID: network_id,
|
||||
constants.PORT_ID: port_id
|
||||
})
|
||||
return updates
|
||||
|
||||
add_subnets = _subnet_updates(add_subnet_ids,
|
||||
desired_subnet_to_net_map)
|
||||
del_subnets = _subnet_updates(del_subnet_ids,
|
||||
plugged_subnets)
|
||||
|
||||
add_ids = desired_network_ids - set(actual_network_nics)
|
||||
add_nics = list(n_data_models.Interface(
|
||||
network_id=net_id) for net_id in add_ids)
|
||||
delta = n_data_models.Delta(
|
||||
amphora_id=amphora.id, compute_id=amphora.compute_id,
|
||||
add_nics=add_nics, delete_nics=delete_nics)
|
||||
amphora_id=amphora.id,
|
||||
compute_id=amphora.compute_id,
|
||||
add_nics=add_nics, delete_nics=delete_nics,
|
||||
add_subnets=add_subnets,
|
||||
delete_subnets=del_subnets)
|
||||
return delta
|
||||
|
||||
|
||||
|
@ -234,28 +298,81 @@ class HandleNetworkDelta(BaseNetworkTask):
|
|||
Plug or unplug networks based on delta
|
||||
"""
|
||||
|
||||
def _fill_port_info(self, port):
|
||||
port.network = self.network_driver.get_network(port.network_id)
|
||||
for fixed_ip in port.fixed_ips:
|
||||
fixed_ip.subnet = self.network_driver.get_subnet(
|
||||
fixed_ip.subnet_id)
|
||||
|
||||
def execute(self, amphora, delta):
|
||||
"""Handle network plugging based off deltas."""
|
||||
added_ports = {}
|
||||
added_ports[amphora.id] = []
|
||||
updated_ports = {}
|
||||
for nic in delta.add_nics:
|
||||
interface = self.network_driver.plug_network(delta.compute_id,
|
||||
nic.network_id)
|
||||
subnet_id = [
|
||||
fixed_ip.subnet_id
|
||||
for fixed_ip in nic.fixed_ips][0]
|
||||
interface = self.network_driver.plug_network(
|
||||
amphora.compute_id, nic.network_id)
|
||||
port = self.network_driver.get_port(interface.port_id)
|
||||
port.network = self.network_driver.get_network(port.network_id)
|
||||
self._fill_port_info(port)
|
||||
updated_ports[port.network_id] = port
|
||||
|
||||
for update in delta.add_subnets:
|
||||
network_id = update[constants.NETWORK_ID]
|
||||
# Get already existing port from Deltas or
|
||||
# newly created port from updated_ports dict
|
||||
port_id = (update[constants.PORT_ID] or
|
||||
updated_ports[network_id].id)
|
||||
subnet_id = update[constants.SUBNET_ID]
|
||||
# Avoid duplicated subnets
|
||||
has_subnet = False
|
||||
if network_id in updated_ports:
|
||||
for fixed_ip in updated_ports[network_id].fixed_ips:
|
||||
if fixed_ip.subnet_id == subnet_id:
|
||||
has_subnet = True
|
||||
if not has_subnet:
|
||||
port = self.network_driver.plug_fixed_ip(
|
||||
port_id=port_id, subnet_id=subnet_id)
|
||||
self._fill_port_info(port)
|
||||
updated_ports[network_id] = port
|
||||
|
||||
for update in delta.delete_subnets:
|
||||
network_id = update[constants.NETWORK_ID]
|
||||
port_id = update[constants.PORT_ID]
|
||||
subnet_id = update[constants.SUBNET_ID]
|
||||
port = self.network_driver.unplug_fixed_ip(
|
||||
port_id=port_id, subnet_id=subnet_id)
|
||||
self._fill_port_info(port)
|
||||
# In neutron, when removing an ipv6 subnet (with slaac) from a
|
||||
# port, it just ignores it.
|
||||
# https://bugs.launchpad.net/neutron/+bug/1945156
|
||||
# When it happens, don't add the port to the updated_ports dict
|
||||
has_subnet = False
|
||||
for fixed_ip in port.fixed_ips:
|
||||
fixed_ip.subnet = self.network_driver.get_subnet(
|
||||
fixed_ip.subnet_id)
|
||||
added_ports[amphora.id].append(port)
|
||||
if fixed_ip.subnet_id == subnet_id:
|
||||
has_subnet = True
|
||||
break
|
||||
if not has_subnet:
|
||||
updated_ports[network_id] = port
|
||||
|
||||
for nic in delta.delete_nics:
|
||||
network_id = nic.network_id
|
||||
try:
|
||||
self.network_driver.unplug_network(delta.compute_id,
|
||||
nic.network_id)
|
||||
self.network_driver.unplug_network(
|
||||
amphora.compute_id, network_id)
|
||||
except base.NetworkNotFound:
|
||||
LOG.debug("Network %d not found ", nic.network_id)
|
||||
LOG.debug("Network %s not found", network_id)
|
||||
except Exception:
|
||||
LOG.exception("Unable to unplug network")
|
||||
return added_ports
|
||||
|
||||
port_id = nic.port_id
|
||||
try:
|
||||
self.network_driver.delete_port(port_id)
|
||||
except Exception:
|
||||
LOG.exception("Unable to delete the port")
|
||||
|
||||
updated_ports.pop(network_id, None)
|
||||
return {amphora.id: list(updated_ports.values())}
|
||||
|
||||
def revert(self, result, amphora, delta, *args, **kwargs):
|
||||
"""Handle a network plug or unplug failures."""
|
||||
|
@ -276,6 +393,12 @@ class HandleNetworkDelta(BaseNetworkTask):
|
|||
except Exception:
|
||||
pass
|
||||
|
||||
port_id = nic.port_id
|
||||
try:
|
||||
self.network_driver.delete_port(port_id)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
class HandleNetworkDeltas(BaseNetworkTask):
|
||||
"""Task to plug and unplug networks
|
||||
|
@ -284,35 +407,28 @@ class HandleNetworkDeltas(BaseNetworkTask):
|
|||
networks based on delta
|
||||
"""
|
||||
|
||||
def execute(self, deltas):
|
||||
def execute(self, deltas, loadbalancer):
|
||||
"""Handle network plugging based off deltas."""
|
||||
added_ports = {}
|
||||
amphorae = {amp.id: amp for amp in loadbalancer.amphorae}
|
||||
|
||||
updated_ports = {}
|
||||
handle_delta = HandleNetworkDelta()
|
||||
|
||||
for amp_id, delta in deltas.items():
|
||||
added_ports[amp_id] = []
|
||||
for nic in delta.add_nics:
|
||||
interface = self.network_driver.plug_network(delta.compute_id,
|
||||
nic.network_id)
|
||||
port = self.network_driver.get_port(interface.port_id)
|
||||
port.network = self.network_driver.get_network(port.network_id)
|
||||
for fixed_ip in port.fixed_ips:
|
||||
fixed_ip.subnet = self.network_driver.get_subnet(
|
||||
fixed_ip.subnet_id)
|
||||
added_ports[amp_id].append(port)
|
||||
for nic in delta.delete_nics:
|
||||
try:
|
||||
self.network_driver.unplug_network(delta.compute_id,
|
||||
nic.network_id)
|
||||
except base.NetworkNotFound:
|
||||
LOG.debug("Network %d not found ", nic.network_id)
|
||||
except Exception:
|
||||
LOG.exception("Unable to unplug network")
|
||||
return added_ports
|
||||
ret = handle_delta.execute(amphorae[amp_id], delta)
|
||||
updated_ports.update(ret)
|
||||
|
||||
return updated_ports
|
||||
|
||||
def revert(self, result, deltas, *args, **kwargs):
|
||||
"""Handle a network plug or unplug failures."""
|
||||
|
||||
if isinstance(result, failure.Failure):
|
||||
return
|
||||
|
||||
if not deltas:
|
||||
return
|
||||
|
||||
for amp_id, delta in deltas.items():
|
||||
LOG.warning("Unable to plug networks for amp id %s",
|
||||
delta.amphora_id)
|
||||
|
@ -323,7 +439,13 @@ class HandleNetworkDeltas(BaseNetworkTask):
|
|||
try:
|
||||
self.network_driver.unplug_network(delta.compute_id,
|
||||
nic.network_id)
|
||||
except base.NetworkNotFound:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
port_id = nic.port_id
|
||||
try:
|
||||
self.network_driver.delete_port(port_id)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
|
|
|
@ -410,11 +410,11 @@ class AmphoraFlows(object):
|
|||
amp_for_failover_flow.add(network_tasks.HandleNetworkDelta(
|
||||
name=prefix + '-' + constants.HANDLE_NETWORK_DELTA,
|
||||
requires=(constants.AMPHORA, constants.DELTA),
|
||||
provides=constants.ADDED_PORTS))
|
||||
provides=constants.UPDATED_PORTS))
|
||||
|
||||
amp_for_failover_flow.add(amphora_driver_tasks.AmphoraePostNetworkPlug(
|
||||
name=prefix + '-' + constants.AMPHORAE_POST_NETWORK_PLUG,
|
||||
requires=(constants.LOADBALANCER, constants.ADDED_PORTS)))
|
||||
requires=(constants.LOADBALANCER, constants.UPDATED_PORTS)))
|
||||
|
||||
return amp_for_failover_flow
|
||||
|
||||
|
|
|
@ -196,12 +196,12 @@ class LoadBalancerFlows(object):
|
|||
)
|
||||
flows.append(
|
||||
network_tasks.HandleNetworkDeltas(
|
||||
requires=constants.DELTAS, provides=constants.ADDED_PORTS
|
||||
requires=constants.DELTAS, provides=constants.UPDATED_PORTS
|
||||
)
|
||||
)
|
||||
flows.append(
|
||||
amphora_driver_tasks.AmphoraePostNetworkPlug(
|
||||
requires=(constants.LOADBALANCER, constants.ADDED_PORTS)
|
||||
requires=(constants.LOADBALANCER, constants.UPDATED_PORTS)
|
||||
)
|
||||
)
|
||||
flows.append(
|
||||
|
|
|
@ -42,10 +42,14 @@ class MemberFlows(object):
|
|||
requires=(constants.LOADBALANCER, constants.AVAILABILITY_ZONE),
|
||||
provides=constants.DELTAS))
|
||||
create_member_flow.add(network_tasks.HandleNetworkDeltas(
|
||||
requires=constants.DELTAS, provides=constants.ADDED_PORTS))
|
||||
requires=(constants.DELTAS, constants.LOADBALANCER),
|
||||
provides=constants.UPDATED_PORTS))
|
||||
create_member_flow.add(network_tasks.GetAmphoraeNetworkConfigs(
|
||||
requires=constants.LOADBALANCER_ID,
|
||||
provides=constants.AMPHORAE_NETWORK_CONFIG))
|
||||
create_member_flow.add(amphora_driver_tasks.AmphoraePostNetworkPlug(
|
||||
requires=(constants.LOADBALANCER, constants.ADDED_PORTS)
|
||||
))
|
||||
requires=(constants.LOADBALANCER, constants.UPDATED_PORTS,
|
||||
constants.AMPHORAE_NETWORK_CONFIG)))
|
||||
create_member_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||
requires=constants.LOADBALANCER_ID))
|
||||
create_member_flow.add(database_tasks.MarkMemberActiveInDB(
|
||||
|
@ -72,6 +76,18 @@ class MemberFlows(object):
|
|||
constants.POOL_ID]))
|
||||
delete_member_flow.add(database_tasks.MarkMemberPendingDeleteInDB(
|
||||
requires=constants.MEMBER))
|
||||
delete_member_flow.add(network_tasks.CalculateDelta(
|
||||
requires=(constants.LOADBALANCER, constants.AVAILABILITY_ZONE),
|
||||
provides=constants.DELTAS))
|
||||
delete_member_flow.add(network_tasks.HandleNetworkDeltas(
|
||||
requires=(constants.DELTAS, constants.LOADBALANCER),
|
||||
provides=constants.UPDATED_PORTS))
|
||||
delete_member_flow.add(network_tasks.GetAmphoraeNetworkConfigs(
|
||||
requires=constants.LOADBALANCER_ID,
|
||||
provides=constants.AMPHORAE_NETWORK_CONFIG))
|
||||
delete_member_flow.add(amphora_driver_tasks.AmphoraePostNetworkPlug(
|
||||
requires=(constants.LOADBALANCER, constants.UPDATED_PORTS,
|
||||
constants.AMPHORAE_NETWORK_CONFIG)))
|
||||
delete_member_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||
requires=constants.LOADBALANCER_ID))
|
||||
delete_member_flow.add(database_tasks.DeleteMemberInDB(
|
||||
|
@ -183,10 +199,15 @@ class MemberFlows(object):
|
|||
requires=(constants.LOADBALANCER, constants.AVAILABILITY_ZONE),
|
||||
provides=constants.DELTAS))
|
||||
batch_update_members_flow.add(network_tasks.HandleNetworkDeltas(
|
||||
requires=constants.DELTAS, provides=constants.ADDED_PORTS))
|
||||
requires=(constants.DELTAS, constants.LOADBALANCER),
|
||||
provides=constants.UPDATED_PORTS))
|
||||
batch_update_members_flow.add(network_tasks.GetAmphoraeNetworkConfigs(
|
||||
requires=constants.LOADBALANCER_ID,
|
||||
provides=constants.AMPHORAE_NETWORK_CONFIG))
|
||||
batch_update_members_flow.add(
|
||||
amphora_driver_tasks.AmphoraePostNetworkPlug(
|
||||
requires=(constants.LOADBALANCER, constants.ADDED_PORTS)))
|
||||
requires=(constants.LOADBALANCER, constants.UPDATED_PORTS,
|
||||
constants.AMPHORAE_NETWORK_CONFIG)))
|
||||
|
||||
# Update the Listener (this makes the changes active on the Amp)
|
||||
batch_update_members_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||
|
|
|
@ -259,7 +259,7 @@ class AmphoraFinalize(BaseAmphoraTask):
|
|||
class AmphoraPostNetworkPlug(BaseAmphoraTask):
|
||||
"""Task to notify the amphora post network plug."""
|
||||
|
||||
def execute(self, amphora, ports):
|
||||
def execute(self, amphora, ports, amphora_network_config):
|
||||
"""Execute post_network_plug routine."""
|
||||
db_amp = self.amphora_repo.get(db_apis.get_session(),
|
||||
id=amphora[constants.ID])
|
||||
|
@ -279,8 +279,9 @@ class AmphoraPostNetworkPlug(BaseAmphoraTask):
|
|||
fixed_ips.append(data_models.FixedIP(
|
||||
subnet=data_models.Subnet(**subnet_arg), **ip))
|
||||
self.amphora_driver.post_network_plug(
|
||||
db_amp, data_models.Port(network=net, fixed_ips=fixed_ips,
|
||||
**port))
|
||||
db_amp,
|
||||
data_models.Port(network=net, fixed_ips=fixed_ips, **port),
|
||||
amphora_network_config)
|
||||
|
||||
LOG.debug("post_network_plug called on compute instance "
|
||||
"%(compute_id)s for port %(port_id)s",
|
||||
|
@ -298,17 +299,18 @@ class AmphoraPostNetworkPlug(BaseAmphoraTask):
|
|||
class AmphoraePostNetworkPlug(BaseAmphoraTask):
|
||||
"""Task to notify the amphorae post network plug."""
|
||||
|
||||
def execute(self, loadbalancer, added_ports):
|
||||
def execute(self, loadbalancer, updated_ports, amphorae_network_config):
|
||||
"""Execute post_network_plug routine."""
|
||||
amp_post_plug = AmphoraPostNetworkPlug()
|
||||
db_lb = self.loadbalancer_repo.get(
|
||||
db_apis.get_session(), id=loadbalancer[constants.LOADBALANCER_ID])
|
||||
for amphora in db_lb.amphorae:
|
||||
if amphora.id in added_ports:
|
||||
if amphora.id in updated_ports:
|
||||
amp_post_plug.execute(amphora.to_dict(),
|
||||
added_ports[amphora.id])
|
||||
updated_ports[amphora.id],
|
||||
amphorae_network_config[amphora.id])
|
||||
|
||||
def revert(self, result, loadbalancer, added_ports, *args, **kwargs):
|
||||
def revert(self, result, loadbalancer, updated_ports, *args, **kwargs):
|
||||
"""Handle a failed post network plug."""
|
||||
if isinstance(result, failure.Failure):
|
||||
return
|
||||
|
|
|
@ -55,17 +55,16 @@ class CalculateAmphoraDelta(BaseNetworkTask):
|
|||
|
||||
default_provides = constants.DELTA
|
||||
|
||||
# TODO(gthiemonge) ensure we no longer need vrrp_port
|
||||
def execute(self, loadbalancer, amphora, availability_zone,
|
||||
vrrp_port=None):
|
||||
LOG.debug("Calculating network delta for amphora id: %s",
|
||||
amphora.get(constants.ID))
|
||||
|
||||
if vrrp_port is None:
|
||||
vrrp_port = self.network_driver.get_port(
|
||||
amphora[constants.VRRP_PORT_ID])
|
||||
vrrp_port_network_id = vrrp_port.network_id
|
||||
else:
|
||||
vrrp_port_network_id = vrrp_port[constants.NETWORK_ID]
|
||||
vip_subnet_to_net_map = {
|
||||
loadbalancer[constants.VIP_SUBNET_ID]:
|
||||
loadbalancer[constants.VIP_NETWORK_ID]
|
||||
}
|
||||
|
||||
# Figure out what networks we want
|
||||
# seed with lb network(s)
|
||||
|
@ -75,33 +74,88 @@ class CalculateAmphoraDelta(BaseNetworkTask):
|
|||
availability_zone.get(constants.MANAGEMENT_NETWORK)]
|
||||
else:
|
||||
management_nets = CONF.controller_worker.amp_boot_network_list
|
||||
desired_network_ids = {vrrp_port_network_id}.union(management_nets)
|
||||
|
||||
db_lb = self.loadbalancer_repo.get(
|
||||
db_apis.get_session(), id=loadbalancer[constants.LOADBALANCER_ID])
|
||||
for pool in db_lb.pools:
|
||||
member_networks = [
|
||||
self.network_driver.get_subnet(member.subnet_id).network_id
|
||||
for member in pool.members
|
||||
if member.subnet_id
|
||||
]
|
||||
desired_network_ids.update(member_networks)
|
||||
|
||||
desired_subnet_to_net_map = {
|
||||
subnet: mgmt_net_id
|
||||
for mgmt_net_id in management_nets
|
||||
for subnet in self.network_driver.get_network(
|
||||
mgmt_net_id).subnets
|
||||
}
|
||||
desired_subnet_to_net_map.update(vip_subnet_to_net_map)
|
||||
|
||||
for pool in db_lb.pools:
|
||||
for member in pool.members:
|
||||
if (member.subnet_id and
|
||||
member.provisioning_status !=
|
||||
constants.PENDING_DELETE):
|
||||
member_network = self.network_driver.get_subnet(
|
||||
member.subnet_id).network_id
|
||||
desired_subnet_to_net_map[member.subnet_id] = (
|
||||
member_network)
|
||||
|
||||
desired_network_ids = set(desired_subnet_to_net_map.values())
|
||||
desired_subnet_ids = set(desired_subnet_to_net_map)
|
||||
|
||||
# Calculate Network deltas
|
||||
nics = self.network_driver.get_plugged_networks(
|
||||
amphora[constants.COMPUTE_ID])
|
||||
# assume we don't have two nics in the same network
|
||||
actual_network_nics = dict((nic.network_id, nic) for nic in nics)
|
||||
# TODO(rm_work): how accurate is this assumption really?
|
||||
network_to_nic_map = {nic.network_id: nic for nic in nics}
|
||||
|
||||
del_ids = set(actual_network_nics) - desired_network_ids
|
||||
delete_nics = list(
|
||||
n_data_models.Interface(network_id=net_id) for net_id in del_ids)
|
||||
del_ids = set(network_to_nic_map) - desired_network_ids
|
||||
delete_nics = [n_data_models.Interface(
|
||||
network_id=net_id,
|
||||
port_id=network_to_nic_map[net_id].port_id)
|
||||
for net_id in del_ids]
|
||||
|
||||
add_ids = desired_network_ids - set(network_to_nic_map)
|
||||
add_nics = [n_data_models.Interface(
|
||||
network_id=net_id,
|
||||
fixed_ips=[
|
||||
n_data_models.FixedIP(
|
||||
subnet_id=subnet_id)
|
||||
for subnet_id in desired_subnet_to_net_map
|
||||
if desired_subnet_to_net_map[subnet_id] == net_id])
|
||||
for net_id in add_ids]
|
||||
|
||||
# Calculate member Subnet deltas
|
||||
plugged_subnets = {
|
||||
fixed_ip.subnet_id: nic.network_id
|
||||
for nic in network_to_nic_map.values()
|
||||
for fixed_ip in nic.fixed_ips or []
|
||||
}
|
||||
|
||||
del_subnet_ids = set(plugged_subnets) - desired_subnet_ids
|
||||
add_subnet_ids = desired_subnet_ids - set(plugged_subnets)
|
||||
|
||||
def _subnet_updates(subnet_ids, subnets):
|
||||
updates = []
|
||||
for s in subnet_ids:
|
||||
network_id = subnets[s]
|
||||
nic = network_to_nic_map.get(network_id)
|
||||
port_id = nic.port_id if nic else None
|
||||
updates.append({
|
||||
constants.SUBNET_ID: s,
|
||||
constants.NETWORK_ID: network_id,
|
||||
constants.PORT_ID: port_id
|
||||
})
|
||||
return updates
|
||||
|
||||
add_subnets = _subnet_updates(add_subnet_ids,
|
||||
desired_subnet_to_net_map)
|
||||
del_subnets = _subnet_updates(del_subnet_ids,
|
||||
plugged_subnets)
|
||||
|
||||
add_ids = desired_network_ids - set(actual_network_nics)
|
||||
add_nics = list(n_data_models.Interface(
|
||||
network_id=net_id) for net_id in add_ids)
|
||||
delta = n_data_models.Delta(
|
||||
amphora_id=amphora[constants.ID],
|
||||
compute_id=amphora[constants.COMPUTE_ID],
|
||||
add_nics=add_nics, delete_nics=delete_nics)
|
||||
add_nics=add_nics, delete_nics=delete_nics,
|
||||
add_subnets=add_subnets,
|
||||
delete_subnets=del_subnets)
|
||||
return delta.to_dict(recurse=True)
|
||||
|
||||
|
||||
|
@ -256,29 +310,86 @@ class HandleNetworkDelta(BaseNetworkTask):
|
|||
Plug or unplug networks based on delta
|
||||
"""
|
||||
|
||||
def _fill_port_info(self, port):
|
||||
port.network = self.network_driver.get_network(port.network_id)
|
||||
for fixed_ip in port.fixed_ips:
|
||||
fixed_ip.subnet = self.network_driver.get_subnet(
|
||||
fixed_ip.subnet_id)
|
||||
|
||||
def execute(self, amphora, delta):
|
||||
"""Handle network plugging based off deltas."""
|
||||
added_ports = {}
|
||||
added_ports[amphora[constants.ID]] = []
|
||||
db_amp = self.amphora_repo.get(db_apis.get_session(),
|
||||
id=amphora.get(constants.ID))
|
||||
updated_ports = {}
|
||||
for nic in delta[constants.ADD_NICS]:
|
||||
subnet_id = [
|
||||
fixed_ip[constants.SUBNET_ID]
|
||||
for fixed_ip in nic[constants.FIXED_IPS]][0]
|
||||
interface = self.network_driver.plug_network(
|
||||
delta[constants.COMPUTE_ID], nic[constants.NETWORK_ID])
|
||||
db_amp.compute_id, nic[constants.NETWORK_ID])
|
||||
port = self.network_driver.get_port(interface.port_id)
|
||||
port.network = self.network_driver.get_network(port.network_id)
|
||||
self._fill_port_info(port)
|
||||
updated_ports[port.network_id] = port.to_dict(recurse=True)
|
||||
|
||||
for update in delta.get(constants.ADD_SUBNETS, []):
|
||||
network_id = update[constants.NETWORK_ID]
|
||||
# Get already existing port from Deltas or
|
||||
# newly created port from updated_ports dict
|
||||
port_id = (update[constants.PORT_ID] or
|
||||
updated_ports[network_id][constants.ID])
|
||||
subnet_id = update[constants.SUBNET_ID]
|
||||
# Avoid duplicated subnets
|
||||
has_subnet = False
|
||||
if network_id in updated_ports:
|
||||
for fixed_ip in updated_ports[network_id][
|
||||
constants.FIXED_IPS]:
|
||||
if fixed_ip[constants.SUBNET_ID] == subnet_id:
|
||||
has_subnet = True
|
||||
if not has_subnet:
|
||||
port = self.network_driver.plug_fixed_ip(
|
||||
port_id=port_id, subnet_id=subnet_id)
|
||||
self._fill_port_info(port)
|
||||
updated_ports[network_id] = (
|
||||
port.to_dict(recurse=True))
|
||||
|
||||
for update in delta.get(constants.DELETE_SUBNETS, []):
|
||||
network_id = update[constants.NETWORK_ID]
|
||||
port_id = update[constants.PORT_ID]
|
||||
subnet_id = update[constants.SUBNET_ID]
|
||||
port = self.network_driver.unplug_fixed_ip(
|
||||
port_id=port_id, subnet_id=subnet_id)
|
||||
self._fill_port_info(port)
|
||||
# In neutron, when removing an ipv6 subnet (with slaac) from a
|
||||
# port, it just ignores it.
|
||||
# https://bugs.launchpad.net/neutron/+bug/1945156
|
||||
# When it happens, don't add the port to the updated_ports dict
|
||||
has_subnet = False
|
||||
for fixed_ip in port.fixed_ips:
|
||||
fixed_ip.subnet = self.network_driver.get_subnet(
|
||||
fixed_ip.subnet_id)
|
||||
added_ports[amphora[constants.ID]].append(port.to_dict(
|
||||
recurse=True))
|
||||
if fixed_ip.subnet_id == subnet_id:
|
||||
has_subnet = True
|
||||
break
|
||||
if not has_subnet:
|
||||
updated_ports[network_id] = (
|
||||
port.to_dict(recurse=True))
|
||||
|
||||
for nic in delta[constants.DELETE_NICS]:
|
||||
network_id = nic[constants.NETWORK_ID]
|
||||
try:
|
||||
self.network_driver.unplug_network(
|
||||
delta[constants.COMPUTE_ID], nic[constants.NETWORK_ID])
|
||||
db_amp.compute_id, network_id)
|
||||
except base.NetworkNotFound:
|
||||
LOG.debug("Network %d not found ", nic[constants.NETWORK_ID])
|
||||
LOG.debug("Network %s not found", network_id)
|
||||
except Exception:
|
||||
LOG.exception("Unable to unplug network")
|
||||
return added_ports
|
||||
|
||||
port_id = nic[constants.PORT_ID]
|
||||
try:
|
||||
self.network_driver.delete_port(port_id)
|
||||
except Exception:
|
||||
LOG.exception("Unable to delete the port")
|
||||
|
||||
updated_ports.pop(network_id, None)
|
||||
return {amphora[constants.ID]: list(updated_ports.values())}
|
||||
|
||||
def revert(self, result, amphora, delta, *args, **kwargs):
|
||||
"""Handle a network plug or unplug failures."""
|
||||
|
@ -299,6 +410,12 @@ class HandleNetworkDelta(BaseNetworkTask):
|
|||
except Exception:
|
||||
pass
|
||||
|
||||
port_id = nic[constants.PORT_ID]
|
||||
try:
|
||||
self.network_driver.delete_port(port_id)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
class HandleNetworkDeltas(BaseNetworkTask):
|
||||
"""Task to plug and unplug networks
|
||||
|
@ -307,49 +424,45 @@ class HandleNetworkDeltas(BaseNetworkTask):
|
|||
networks based on delta
|
||||
"""
|
||||
|
||||
def execute(self, deltas):
|
||||
def execute(self, deltas, loadbalancer):
|
||||
"""Handle network plugging based off deltas."""
|
||||
added_ports = {}
|
||||
db_lb = self.loadbalancer_repo.get(
|
||||
db_apis.get_session(), id=loadbalancer[constants.LOADBALANCER_ID])
|
||||
amphorae = {amp.id: amp for amp in db_lb.amphorae}
|
||||
|
||||
updated_ports = {}
|
||||
handle_delta = HandleNetworkDelta()
|
||||
|
||||
for amp_id, delta in deltas.items():
|
||||
added_ports[amp_id] = []
|
||||
for nic in delta[constants.ADD_NICS]:
|
||||
interface = self.network_driver.plug_network(
|
||||
delta[constants.COMPUTE_ID], nic[constants.NETWORK_ID])
|
||||
port = self.network_driver.get_port(interface.port_id)
|
||||
port.network = self.network_driver.get_network(port.network_id)
|
||||
for fixed_ip in port.fixed_ips:
|
||||
fixed_ip.subnet = self.network_driver.get_subnet(
|
||||
fixed_ip.subnet_id)
|
||||
added_ports[amp_id].append(port.to_dict(recurse=True))
|
||||
for nic in delta[constants.DELETE_NICS]:
|
||||
try:
|
||||
self.network_driver.unplug_network(
|
||||
delta[constants.COMPUTE_ID],
|
||||
nic[constants.NETWORK_ID])
|
||||
except base.NetworkNotFound:
|
||||
LOG.debug("Network %d not found ",
|
||||
nic[constants.NETWORK_ID])
|
||||
except Exception:
|
||||
LOG.exception("Unable to unplug network")
|
||||
return added_ports
|
||||
ret = handle_delta.execute(amphorae[amp_id].to_dict(), delta)
|
||||
updated_ports.update(ret)
|
||||
|
||||
return updated_ports
|
||||
|
||||
def revert(self, result, deltas, *args, **kwargs):
|
||||
"""Handle a network plug or unplug failures."""
|
||||
|
||||
if isinstance(result, failure.Failure):
|
||||
return
|
||||
|
||||
if not deltas:
|
||||
return
|
||||
|
||||
for amp_id, delta in deltas.items():
|
||||
LOG.warning("Unable to plug networks for amp id %s",
|
||||
delta[constants.AMPHORA_ID])
|
||||
if not delta:
|
||||
return
|
||||
|
||||
for nic in delta[constants.ADD_NICS]:
|
||||
try:
|
||||
self.network_driver.unplug_network(
|
||||
delta[constants.COMPUTE_ID],
|
||||
nic[constants.NETWORK_ID])
|
||||
except base.NetworkNotFound:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
port_id = nic[constants.PORT_ID]
|
||||
try:
|
||||
self.network_driver.delete_port(port_id)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
|
|
|
@ -45,6 +45,10 @@ class UnplugNetworkException(NetworkException):
|
|||
pass
|
||||
|
||||
|
||||
class AllocateNetworkException(NetworkException):
|
||||
pass
|
||||
|
||||
|
||||
class VIPInUseException(NetworkException):
|
||||
pass
|
||||
|
||||
|
@ -169,7 +173,7 @@ class AbstractNetworkDriver(object, metaclass=abc.ABCMeta):
|
|||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def plug_network(self, compute_id, network_id, ip_address=None):
|
||||
def plug_network(self, amphora, network_id, subnet_id=None):
|
||||
"""Connects an existing amphora to an existing network.
|
||||
|
||||
:param compute_id: id of an amphora in the compute service
|
||||
|
@ -180,10 +184,10 @@ class AbstractNetworkDriver(object, metaclass=abc.ABCMeta):
|
|||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def unplug_network(self, compute_id, network_id, ip_address=None):
|
||||
def unplug_network(self, compute_id, network_id):
|
||||
"""Disconnects an existing amphora from an existing network.
|
||||
|
||||
If ip_address is not specificed, all the interfaces plugged on
|
||||
If ip_address is not specified, all the interfaces plugged on
|
||||
network_id should be unplugged.
|
||||
|
||||
:param compute_id: id of an amphora in the compute service
|
||||
|
@ -194,6 +198,29 @@ class AbstractNetworkDriver(object, metaclass=abc.ABCMeta):
|
|||
NetworkException
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def plug_fixed_ip(self, port_id, subnet_id, ip_address=None):
|
||||
"""Plug a fixed ip to an existing port.
|
||||
|
||||
If ip_address is not specified, one will be auto-assigned.
|
||||
|
||||
:param port_id: id of a port to add a fixed ip
|
||||
:param subnet_id: id of a subnet
|
||||
:param ip_address: specific ip_address to add
|
||||
:return: octavia.network.data_models.Port
|
||||
:raises: NetworkException, PortNotFound
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def unplug_fixed_ip(self, port_id, subnet_id):
|
||||
"""Unplug a fixed ip from an existing port.
|
||||
|
||||
:param port_id: id of a port to remove the fixed ip from
|
||||
:param subnet_id: id of a subnet
|
||||
:return: octavia.network.data_models.Port
|
||||
:raises: NetworkException, PortNotFound
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_plugged_networks(self, compute_id):
|
||||
"""Retrieves the current plugged networking configuration.
|
||||
|
|
|
@ -29,11 +29,14 @@ class Interface(data_models.BaseDataModel):
|
|||
class Delta(data_models.BaseDataModel):
|
||||
|
||||
def __init__(self, amphora_id=None, compute_id=None,
|
||||
add_nics=None, delete_nics=None):
|
||||
add_nics=None, delete_nics=None,
|
||||
add_subnets=None, delete_subnets=None):
|
||||
self.compute_id = compute_id
|
||||
self.amphora_id = amphora_id
|
||||
self.add_nics = add_nics
|
||||
self.delete_nics = delete_nics
|
||||
self.add_subnets = add_subnets
|
||||
self.delete_subnets = delete_subnets
|
||||
|
||||
|
||||
class Network(data_models.BaseDataModel):
|
||||
|
|
|
@ -547,7 +547,7 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
|
|||
amphora.compute_id)
|
||||
return
|
||||
try:
|
||||
self.unplug_network(amphora.compute_id, subnet.network_id)
|
||||
self.unplug_network(amphora, subnet.network_id)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
|
@ -610,15 +610,14 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
|
|||
|
||||
return self._nova_interface_to_octavia_interface(compute_id, interface)
|
||||
|
||||
def unplug_network(self, compute_id, network_id, ip_address=None):
|
||||
def unplug_network(self, compute_id, network_id):
|
||||
interfaces = self.get_plugged_networks(compute_id)
|
||||
if not interfaces:
|
||||
msg = ('Amphora with compute id {compute_id} does not have any '
|
||||
'plugged networks').format(compute_id=compute_id)
|
||||
raise base.NetworkNotFound(msg)
|
||||
|
||||
unpluggers = self._get_interfaces_to_unplug(interfaces, network_id,
|
||||
ip_address=ip_address)
|
||||
unpluggers = self._get_interfaces_to_unplug(interfaces, network_id)
|
||||
for index, unplugger in enumerate(unpluggers):
|
||||
self.compute.detach_port(
|
||||
compute_id=compute_id, port_id=unplugger.port_id)
|
||||
|
|
|
@ -275,3 +275,35 @@ class BaseNeutronDriver(base.AbstractNetworkDriver):
|
|||
|
||||
def get_network_ip_availability(self, network):
|
||||
return self._get_resource('network_ip_availability', network.id)
|
||||
|
||||
def plug_fixed_ip(self, port_id, subnet_id, ip_address=None):
|
||||
port = self.get_port(port_id).to_dict(recurse=True)
|
||||
fixed_ips = port['fixed_ips']
|
||||
|
||||
new_fixed_ip = {'subnet_id': subnet_id}
|
||||
if ip_address:
|
||||
new_fixed_ip['ip_address'] = ip_address
|
||||
|
||||
fixed_ips.append(new_fixed_ip)
|
||||
|
||||
body = {'port': {'fixed_ips': fixed_ips}}
|
||||
try:
|
||||
updated_port = self.neutron_client.update_port(port_id, body)
|
||||
return utils.convert_port_dict_to_model(updated_port)
|
||||
except Exception as e:
|
||||
raise base.NetworkException(str(e))
|
||||
|
||||
def unplug_fixed_ip(self, port_id, subnet_id):
|
||||
port = self.get_port(port_id)
|
||||
fixed_ips = [
|
||||
fixed_ip.to_dict()
|
||||
for fixed_ip in port.fixed_ips
|
||||
if fixed_ip.subnet_id != subnet_id
|
||||
]
|
||||
|
||||
body = {'port': {'fixed_ips': fixed_ips}}
|
||||
try:
|
||||
updated_port = self.neutron_client.update_port(port_id, body)
|
||||
return utils.convert_port_dict_to_model(updated_port)
|
||||
except Exception as e:
|
||||
raise base.NetworkException(str(e))
|
||||
|
|
|
@ -21,8 +21,12 @@ from octavia.network import data_models as network_models
|
|||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
_PLUGGED_NETWORKS = {}
|
||||
_PORTS = {}
|
||||
|
||||
|
||||
class NoopManager(object):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.networkconfigconfig = {}
|
||||
|
@ -110,33 +114,41 @@ class NoopManager(object):
|
|||
vip.ip_address)] = (vip, amphora, subnet,
|
||||
'unplug_aap_port')
|
||||
|
||||
def plug_network(self, compute_id, network_id, ip_address=None):
|
||||
def plug_network(self, compute_id, network_id, subnet_id=None):
|
||||
LOG.debug("Network %s no-op, plug_network compute_id %s, network_id "
|
||||
"%s, ip_address %s", self.__class__.__name__, compute_id,
|
||||
network_id, ip_address)
|
||||
self.networkconfigconfig[(compute_id, network_id, ip_address)] = (
|
||||
compute_id, network_id, ip_address, 'plug_network')
|
||||
return network_models.Interface(
|
||||
"%s, subnet %s", self.__class__.__name__, compute_id,
|
||||
network_id, subnet_id)
|
||||
self.networkconfigconfig[(compute_id, network_id)] = (
|
||||
compute_id, network_id, subnet_id, 'plug_network')
|
||||
interface = network_models.Interface(
|
||||
id=uuidutils.generate_uuid(),
|
||||
compute_id=compute_id,
|
||||
network_id=network_id,
|
||||
fixed_ips=[],
|
||||
fixed_ips=[network_models.FixedIP(
|
||||
subnet_id=subnet_id)],
|
||||
port_id=uuidutils.generate_uuid()
|
||||
)
|
||||
_PORTS[interface.port_id] = network_models.Port(
|
||||
id=interface.port_id,
|
||||
network_id=network_id)
|
||||
_PLUGGED_NETWORKS[(network_id, compute_id)] = interface
|
||||
return interface
|
||||
|
||||
def unplug_network(self, compute_id, network_id, ip_address=None):
|
||||
def unplug_network(self, compute_id, network_id):
|
||||
LOG.debug("Network %s no-op, unplug_network compute_id %s, "
|
||||
"network_id %s",
|
||||
self.__class__.__name__, compute_id, network_id)
|
||||
self.networkconfigconfig[(compute_id, network_id, ip_address)] = (
|
||||
compute_id, network_id, ip_address, 'unplug_network')
|
||||
self.networkconfigconfig[(compute_id, network_id)] = (
|
||||
compute_id, network_id, 'unplug_network')
|
||||
_PLUGGED_NETWORKS.pop((network_id, compute_id), None)
|
||||
|
||||
def get_plugged_networks(self, compute_id):
|
||||
LOG.debug("Network %s no-op, get_plugged_networks amphora_id %s",
|
||||
self.__class__.__name__, compute_id)
|
||||
self.networkconfigconfig[compute_id] = (
|
||||
compute_id, 'get_plugged_networks')
|
||||
return []
|
||||
return [pn for pn in _PLUGGED_NETWORKS.values()
|
||||
if pn.compute_id == compute_id]
|
||||
|
||||
def update_vip(self, loadbalancer, for_delete=False):
|
||||
LOG.debug("Network %s no-op, update_vip loadbalancer %s "
|
||||
|
@ -175,7 +187,10 @@ class NoopManager(object):
|
|||
LOG.debug("Port %s no-op, get_port port_id %s",
|
||||
self.__class__.__name__, port_id)
|
||||
self.networkconfigconfig[port_id] = (port_id, 'get_port')
|
||||
return network_models.Port(id=uuidutils.generate_uuid())
|
||||
if port_id in _PORTS:
|
||||
return _PORTS[port_id]
|
||||
return network_models.Port(id=uuidutils.generate_uuid(),
|
||||
network_id=uuidutils.generate_uuid())
|
||||
|
||||
def get_network_by_name(self, network_name):
|
||||
LOG.debug("Network %s no-op, get_network_by_name network_name %s",
|
||||
|
@ -337,6 +352,27 @@ class NoopManager(object):
|
|||
admin_state_up=admin_state_up, fixed_ips=fixed_ip_obj_list,
|
||||
qos_policy_id=qos_policy_id, security_group_ids=security_group_ids)
|
||||
|
||||
def plug_fixed_ip(self, port_id, subnet_id, ip_address=None):
|
||||
LOG.debug("Network %s no-op, plug_fixed_ip port_id %s, subnet_id "
|
||||
"%s, ip_address %s", self.__class__.__name__, port_id,
|
||||
subnet_id, ip_address)
|
||||
self.networkconfigconfig[(port_id, subnet_id)] = (
|
||||
port_id, subnet_id, ip_address, 'plug_fixed_ip')
|
||||
|
||||
port = network_models.Port(id=port_id,
|
||||
network_id=uuidutils.generate_uuid())
|
||||
_PORTS[port.id] = port
|
||||
return port
|
||||
|
||||
def unplug_fixed_ip(self, port_id, subnet_id):
|
||||
LOG.debug("Network %s no-op, unplug_fixed_ip port_id %s, subnet_id "
|
||||
"%s", self.__class__.__name__, port_id,
|
||||
subnet_id)
|
||||
self.networkconfigconfig[(port_id, subnet_id)] = (
|
||||
port_id, subnet_id, 'unplug_fixed_ip')
|
||||
|
||||
return _PORTS.get(port_id)
|
||||
|
||||
|
||||
class NoopNetworkDriver(driver_base.AbstractNetworkDriver):
|
||||
def __init__(self):
|
||||
|
@ -355,15 +391,15 @@ class NoopNetworkDriver(driver_base.AbstractNetworkDriver):
|
|||
def unplug_vip(self, loadbalancer, vip):
|
||||
self.driver.unplug_vip(loadbalancer, vip)
|
||||
|
||||
def plug_network(self, amphora_id, network_id, ip_address=None):
|
||||
return self.driver.plug_network(amphora_id, network_id, ip_address)
|
||||
def plug_network(self, compute_id, network_id, subnet_id=None):
|
||||
return self.driver.plug_network(compute_id, network_id,
|
||||
subnet_id=subnet_id)
|
||||
|
||||
def unplug_network(self, amphora_id, network_id, ip_address=None):
|
||||
self.driver.unplug_network(amphora_id, network_id,
|
||||
ip_address=ip_address)
|
||||
def unplug_network(self, compute_id, network_id):
|
||||
self.driver.unplug_network(compute_id, network_id)
|
||||
|
||||
def get_plugged_networks(self, amphora_id):
|
||||
return self.driver.get_plugged_networks(amphora_id)
|
||||
def get_plugged_networks(self, compute_id):
|
||||
return self.driver.get_plugged_networks(compute_id)
|
||||
|
||||
def update_vip(self, loadbalancer, for_delete=False):
|
||||
self.driver.update_vip(loadbalancer, for_delete)
|
||||
|
@ -437,3 +473,9 @@ class NoopNetworkDriver(driver_base.AbstractNetworkDriver):
|
|||
return self.driver.create_port(
|
||||
network_id, name, fixed_ips, secondary_ips, security_group_ids,
|
||||
admin_state_up, qos_policy_id)
|
||||
|
||||
def plug_fixed_ip(self, port_id, subnet_id, ip_address=None):
|
||||
return self.driver.plug_fixed_ip(port_id, subnet_id, ip_address)
|
||||
|
||||
def unplug_fixed_ip(self, port_id, subnet_id):
|
||||
return self.driver.unplug_fixed_ip(port_id, subnet_id)
|
||||
|
|
|
@ -967,10 +967,12 @@ class TestServerTestCase(base.TestCase):
|
|||
@mock.patch('subprocess.check_output')
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.'
|
||||
'plug.Plug._netns_interface_exists')
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.'
|
||||
'plug.Plug._netns_interface_by_mac')
|
||||
@mock.patch('os.path.isfile')
|
||||
def _test_plug_network(self, distro, mock_isfile, mock_int_exists,
|
||||
mock_check_output, mock_netns, mock_pyroute2,
|
||||
mock_os_chmod):
|
||||
def _test_plug_network(self, distro, mock_isfile, mock_int_by_mac,
|
||||
mock_int_exists, mock_check_output, mock_netns,
|
||||
mock_pyroute2, mock_os_chmod):
|
||||
mock_ipr = mock.MagicMock()
|
||||
mock_ipr_instance = mock.MagicMock()
|
||||
mock_ipr_instance.link_lookup.side_effect = [
|
||||
|
@ -992,21 +994,22 @@ class TestServerTestCase(base.TestCase):
|
|||
test_int_num = str(test_int_num)
|
||||
|
||||
# Interface already plugged
|
||||
mock_int_exists.return_value = True
|
||||
if distro == consts.UBUNTU:
|
||||
rv = self.ubuntu_app.post('/' + api_server.VERSION +
|
||||
"/plug/network",
|
||||
content_type='application/json',
|
||||
data=jsonutils.dumps(port_info))
|
||||
elif distro == consts.CENTOS:
|
||||
rv = self.centos_app.post('/' + api_server.VERSION +
|
||||
"/plug/network",
|
||||
content_type='application/json',
|
||||
data=jsonutils.dumps(port_info))
|
||||
self.assertEqual(409, rv.status_code)
|
||||
self.assertEqual(dict(message="Interface already exists"),
|
||||
jsonutils.loads(rv.data.decode('utf-8')))
|
||||
mock_int_exists.return_value = False
|
||||
# TODO(gthiemonge) FIXME
|
||||
# mock_int_exists.return_value = True
|
||||
# if distro == consts.UBUNTU:
|
||||
# rv = self.ubuntu_app.post('/' + api_server.VERSION +
|
||||
# "/plug/network",
|
||||
# content_type='application/json',
|
||||
# data=jsonutils.dumps(port_info))
|
||||
# elif distro == consts.CENTOS:
|
||||
# rv = self.centos_app.post('/' + api_server.VERSION +
|
||||
# "/plug/network",
|
||||
# content_type='application/json',
|
||||
# data=jsonutils.dumps(port_info))
|
||||
# self.assertEqual(409, rv.status_code)
|
||||
# self.assertEqual(dict(message="Interface already exists"),
|
||||
# jsonutils.loads(rv.data.decode('utf-8')))
|
||||
# mock_int_exists.return_value = False
|
||||
|
||||
# No interface at all
|
||||
file_name = '/sys/bus/pci/rescan'
|
||||
|
|
|
@ -96,6 +96,20 @@ class TestOSUtils(base.TestCase):
|
|||
package_name))
|
||||
self.assertEqual(centos_cmd, returned_centos_cmd)
|
||||
|
||||
@mock.patch('octavia.amphorae.backends.utils.interface_file.'
|
||||
'InterfaceFile')
|
||||
def test_write_interface_file(self, mock_interface_file):
|
||||
mock_interface = mock.MagicMock()
|
||||
mock_interface_file.return_value = mock_interface
|
||||
|
||||
self.ubuntu_os_util.write_interface_file('eth1',
|
||||
'1.2.3.4', 16)
|
||||
|
||||
mock_interface_file.assert_called_once_with(
|
||||
name='eth1',
|
||||
addresses=[{"address": "1.2.3.4", "prefixlen": 16}])
|
||||
mock_interface.write.assert_called_once()
|
||||
|
||||
@mock.patch('octavia.amphorae.backends.utils.interface_file.'
|
||||
'VIPInterfaceFile')
|
||||
def test_write_vip_interface_file(self, mock_vip_interface_file):
|
||||
|
@ -142,6 +156,7 @@ class TestOSUtils(base.TestCase):
|
|||
mtu=MTU,
|
||||
vrrp_ip=None,
|
||||
host_routes=host_routes,
|
||||
fixed_ips=None,
|
||||
topology="SINGLE")
|
||||
mock_vip_interface_file.return_value.write.assert_called_once()
|
||||
|
||||
|
@ -167,6 +182,7 @@ class TestOSUtils(base.TestCase):
|
|||
mtu=MTU,
|
||||
vrrp_ip=None,
|
||||
host_routes=host_routes,
|
||||
fixed_ips=None,
|
||||
topology="SINGLE")
|
||||
|
||||
@mock.patch('octavia.amphorae.backends.utils.interface_file.'
|
||||
|
|
|
@ -193,16 +193,167 @@ class TestPlug(base.TestCase):
|
|||
mock_webob.Response.assert_any_call(json={'message': 'Invalid VIP'},
|
||||
status=400)
|
||||
|
||||
@mock.patch("octavia.amphorae.backends.agent.api_server.osutils."
|
||||
"BaseOS.write_interface_file")
|
||||
def test_plug_lo(self, mock_write_interface):
|
||||
m = mock.mock_open()
|
||||
with mock.patch('os.open'), mock.patch.object(os, 'fdopen', m):
|
||||
self.test_plug.plug_lo()
|
||||
mock_write_interface.assert_called_once_with(interface='lo',
|
||||
ip_address='127.0.0.1',
|
||||
prefixlen=8)
|
||||
|
||||
@mock.patch('pyroute2.NetNS', create=True)
|
||||
def test__netns_interface_exists(self, mock_netns):
|
||||
|
||||
netns_handle = mock_netns.return_value.__enter__.return_value
|
||||
|
||||
netns_handle.get_links.return_value = [{
|
||||
'attrs': [['IFLA_ADDRESS', '123']]}]
|
||||
'attrs': [['IFLA_ADDRESS', '123'],
|
||||
['IFLA_IFNAME', 'eth0']]}]
|
||||
|
||||
# Interface is found in netns
|
||||
self.assertTrue(self.test_plug._netns_interface_exists('123'))
|
||||
|
||||
# Interface is not found in netns
|
||||
self.assertFalse(self.test_plug._netns_interface_exists('321'))
|
||||
|
||||
@mock.patch.object(plug, "webob")
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.plug.Plug.'
|
||||
'_netns_interface_exists', return_value=False)
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.plug.Plug.'
|
||||
'_interface_by_mac', return_value=FAKE_INTERFACE)
|
||||
@mock.patch('pyroute2.IPRoute', create=True)
|
||||
@mock.patch('pyroute2.netns.create', create=True)
|
||||
@mock.patch('pyroute2.NetNS', create=True)
|
||||
@mock.patch("octavia.amphorae.backends.agent.api_server.osutils."
|
||||
"BaseOS.write_port_interface_file")
|
||||
@mock.patch("octavia.amphorae.backends.agent.api_server.osutils."
|
||||
"BaseOS.bring_interface_up")
|
||||
def test_plug_network(self, mock_if_up, mock_write_port_interface,
|
||||
mock_netns, mock_netns_create, mock_iproute,
|
||||
mock_by_mac, mock_interface_exists, mock_webob):
|
||||
fixed_ips = [
|
||||
{'ip_address': FAKE_IP_IPV4,
|
||||
'subnet_cidr': FAKE_CIDR_IPV4,
|
||||
'gateway': FAKE_GATEWAY_IPV4,
|
||||
'host_routes': [
|
||||
{'destination': '10.1.0.0/16',
|
||||
'nexthop': '10.0.1.254'}]
|
||||
}]
|
||||
mtu = 1400
|
||||
m = mock.mock_open()
|
||||
with mock.patch('os.open'), mock.patch.object(os, 'fdopen', m):
|
||||
self.test_plug.plug_network(FAKE_MAC_ADDRESS, fixed_ips, 1400)
|
||||
|
||||
mock_write_port_interface.assert_called_once_with(
|
||||
interface='eth0', fixed_ips=fixed_ips, mtu=mtu)
|
||||
mock_if_up.assert_called_once_with('eth0', 'network')
|
||||
|
||||
mock_webob.Response.assert_any_call(
|
||||
json={'message': 'OK',
|
||||
'details': 'Plugged on interface eth0'},
|
||||
status=202)
|
||||
|
||||
@mock.patch.object(plug, "webob")
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.plug.Plug.'
|
||||
'_netns_interface_exists', return_value=True)
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.plug.Plug.'
|
||||
'_netns_interface_by_mac', return_value=FAKE_INTERFACE)
|
||||
@mock.patch('pyroute2.NetNS', create=True)
|
||||
@mock.patch("octavia.amphorae.backends.agent.api_server.osutils."
|
||||
"BaseOS.write_port_interface_file")
|
||||
@mock.patch("octavia.amphorae.backends.agent.api_server.osutils."
|
||||
"BaseOS.bring_interface_up")
|
||||
def test_plug_network_existing_interface(self, mock_if_up,
|
||||
mock_write_port_interface,
|
||||
mock_netns, mock_by_mac,
|
||||
mock_interface_exists,
|
||||
mock_webob):
|
||||
fixed_ips = [
|
||||
{'ip_address': FAKE_IP_IPV4,
|
||||
'subnet_cidr': FAKE_CIDR_IPV4,
|
||||
'gateway': FAKE_GATEWAY_IPV4,
|
||||
'host_routes': [
|
||||
{'destination': '10.1.0.0/16',
|
||||
'nexthop': '10.0.1.254'}]
|
||||
}, {'ip_address': FAKE_IP_IPV6,
|
||||
'subnet_cidr': FAKE_CIDR_IPV6,
|
||||
'gateway': FAKE_GATEWAY_IPV6,
|
||||
'host_routes': [
|
||||
{'destination': '2001:1::/64',
|
||||
'nexthop': '1001:1::ffff'}]
|
||||
}]
|
||||
mtu = 1400
|
||||
m = mock.mock_open()
|
||||
with mock.patch('os.open'), mock.patch.object(os, 'fdopen', m):
|
||||
self.test_plug.plug_network(FAKE_MAC_ADDRESS, fixed_ips, 1400)
|
||||
|
||||
mock_write_port_interface.assert_called_once_with(
|
||||
interface=FAKE_INTERFACE, fixed_ips=fixed_ips, mtu=mtu)
|
||||
mock_if_up.assert_called_once_with(FAKE_INTERFACE, 'network')
|
||||
|
||||
mock_webob.Response.assert_any_call(
|
||||
json={'message': 'OK',
|
||||
'details': 'Updated existing interface {}'.format(
|
||||
FAKE_INTERFACE)},
|
||||
status=202)
|
||||
|
||||
@mock.patch.object(plug, "webob")
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.plug.Plug.'
|
||||
'_netns_interface_exists', return_value=True)
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.plug.Plug.'
|
||||
'_netns_interface_by_mac', return_value=FAKE_INTERFACE)
|
||||
@mock.patch('pyroute2.NetNS', create=True)
|
||||
@mock.patch("octavia.amphorae.backends.agent.api_server.osutils."
|
||||
"BaseOS.write_vip_interface_file")
|
||||
@mock.patch("octavia.amphorae.backends.agent.api_server.osutils."
|
||||
"BaseOS.bring_interface_up")
|
||||
def test_plug_network_on_vip(
|
||||
self, mock_if_up, mock_write_vip_interface,
|
||||
mock_netns, mock_by_mac, mock_interface_exists, mock_webob):
|
||||
fixed_ips = [
|
||||
{'ip_address': FAKE_IP_IPV4,
|
||||
'subnet_cidr': FAKE_CIDR_IPV4,
|
||||
'gateway': FAKE_GATEWAY_IPV4,
|
||||
'host_routes': [
|
||||
{'destination': '10.1.0.0/16',
|
||||
'nexthop': '10.0.1.254'}]
|
||||
}, {'ip_address': FAKE_IP_IPV6,
|
||||
'subnet_cidr': FAKE_CIDR_IPV6,
|
||||
'gateway': FAKE_GATEWAY_IPV6,
|
||||
'host_routes': [
|
||||
{'destination': '2001:1::/64',
|
||||
'nexthop': '1001:1::ffff'}]
|
||||
}]
|
||||
mtu = 1400
|
||||
vip_net_info = {
|
||||
'vip': '10.2.1.1',
|
||||
'subnet_cidr': '10.2.0.0/16',
|
||||
'vrrp_ip': '10.2.1.2',
|
||||
'gateway': '10.2.255.254',
|
||||
'host_routes': []
|
||||
}
|
||||
|
||||
m = mock.mock_open()
|
||||
with mock.patch('os.open'), mock.patch.object(os, 'fdopen', m):
|
||||
self.test_plug.plug_network(FAKE_MAC_ADDRESS, fixed_ips, mtu=1400,
|
||||
vip_net_info=vip_net_info)
|
||||
|
||||
mock_write_vip_interface.assert_called_once_with(
|
||||
interface=FAKE_INTERFACE,
|
||||
vip=vip_net_info['vip'],
|
||||
ip_version=4,
|
||||
prefixlen=16,
|
||||
gateway=vip_net_info['gateway'],
|
||||
vrrp_ip=vip_net_info['vrrp_ip'],
|
||||
host_routes=[],
|
||||
fixed_ips=fixed_ips, mtu=mtu)
|
||||
|
||||
mock_if_up.assert_called_once_with(FAKE_INTERFACE, 'vip')
|
||||
|
||||
mock_webob.Response.assert_any_call(
|
||||
json={'message': 'OK',
|
||||
'details': 'Updated existing interface {}'.format(
|
||||
FAKE_INTERFACE)},
|
||||
status=202)
|
||||
|
|
|
@ -94,6 +94,7 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
|||
self.fixed_ip = mock.MagicMock()
|
||||
self.fixed_ip.ip_address = '198.51.100.5'
|
||||
self.fixed_ip.subnet.cidr = '198.51.100.0/24'
|
||||
self.fixed_ip.subnet.gateway_ip = FAKE_GATEWAY
|
||||
self.network = network_models.Network(mtu=FAKE_MTU)
|
||||
self.port = network_models.Port(mac_address=FAKE_MAC_ADDRESS,
|
||||
fixed_ips=[self.fixed_ip],
|
||||
|
@ -116,6 +117,9 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
|||
constants.REQ_READ_TIMEOUT: 2,
|
||||
constants.CONN_MAX_RETRIES: 3,
|
||||
constants.CONN_RETRY_INTERVAL: 4}
|
||||
self.amp_net_config = network_models.AmphoraNetworkConfig(
|
||||
vip_subnet=self.lb.vip.subnet_id
|
||||
)
|
||||
|
||||
@mock.patch('octavia.amphorae.drivers.haproxy.rest_api_driver.'
|
||||
'HaproxyAmphoraLoadBalancerDriver._process_secret')
|
||||
|
@ -589,6 +593,13 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
|||
amphorae_network_config.get().vip_subnet.cidr = FAKE_CIDR
|
||||
amphorae_network_config.get().vip_subnet.gateway_ip = FAKE_GATEWAY
|
||||
amphorae_network_config.get().vip_subnet.host_routes = self.host_routes
|
||||
amphorae_network_config.get().vip_subnet.to_dict.return_value = {
|
||||
'cidr': FAKE_CIDR,
|
||||
'gateway_ip': FAKE_GATEWAY,
|
||||
'host_routes': [
|
||||
hr.to_dict(recurse=True)
|
||||
for hr in self.host_routes]
|
||||
}
|
||||
amphorae_network_config.get().vrrp_port = self.port
|
||||
self.driver.post_vip_plug(self.amp, self.lb, amphorae_network_config)
|
||||
self.driver.clients[API_VERSION].plug_vip.assert_called_once_with(
|
||||
|
@ -599,7 +610,7 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
|||
port = network_models.Port(mac_address=FAKE_MAC_ADDRESS,
|
||||
fixed_ips=[],
|
||||
network=self.network)
|
||||
self.driver.post_network_plug(self.amp, port)
|
||||
self.driver.post_network_plug(self.amp, port, self.amp_net_config)
|
||||
self.driver.clients[API_VERSION].plug_network.assert_called_once_with(
|
||||
self.amp, dict(mac_address=FAKE_MAC_ADDRESS,
|
||||
fixed_ips=[],
|
||||
|
@ -608,12 +619,13 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
|||
self.driver.clients[API_VERSION].plug_network.reset_mock()
|
||||
|
||||
# Test fixed IP path
|
||||
self.driver.post_network_plug(self.amp, self.port)
|
||||
self.driver.post_network_plug(self.amp, self.port, self.amp_net_config)
|
||||
self.driver.clients[API_VERSION].plug_network.assert_called_once_with(
|
||||
self.amp, dict(mac_address=FAKE_MAC_ADDRESS,
|
||||
fixed_ips=[dict(ip_address='198.51.100.5',
|
||||
subnet_cidr='198.51.100.0/24',
|
||||
host_routes=[])],
|
||||
host_routes=[],
|
||||
gateway=FAKE_GATEWAY)],
|
||||
mtu=FAKE_MTU))
|
||||
|
||||
def test_post_network_plug_with_host_routes(self):
|
||||
|
@ -629,6 +641,7 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
|||
network_models.HostRoute(destination=DEST2,
|
||||
nexthop=NEXTHOP)]
|
||||
subnet = network_models.Subnet(id=SUBNET_ID, cidr=SUBNET_CIDR,
|
||||
gateway_ip=FAKE_GATEWAY,
|
||||
ip_version=4, host_routes=host_routes)
|
||||
fixed_ips = [
|
||||
network_models.FixedIP(subnet_id=subnet.id, ip_address=FIXED_IP1,
|
||||
|
@ -639,12 +652,14 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
|||
port = network_models.Port(mac_address=FAKE_MAC_ADDRESS,
|
||||
fixed_ips=fixed_ips,
|
||||
network=self.network)
|
||||
self.driver.post_network_plug(self.amp, port)
|
||||
self.driver.post_network_plug(self.amp, port, self.amp_net_config)
|
||||
expected_fixed_ips = [
|
||||
{'ip_address': FIXED_IP1, 'subnet_cidr': SUBNET_CIDR,
|
||||
'gateway': FAKE_GATEWAY,
|
||||
'host_routes': [{'destination': DEST1, 'nexthop': NEXTHOP},
|
||||
{'destination': DEST2, 'nexthop': NEXTHOP}]},
|
||||
{'ip_address': FIXED_IP2, 'subnet_cidr': SUBNET_CIDR,
|
||||
'gateway': FAKE_GATEWAY,
|
||||
'host_routes': [{'destination': DEST1, 'nexthop': NEXTHOP},
|
||||
{'destination': DEST2, 'nexthop': NEXTHOP}]}
|
||||
]
|
||||
|
|
|
@ -94,6 +94,7 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
|||
self.fixed_ip = mock.MagicMock()
|
||||
self.fixed_ip.ip_address = '198.51.100.5'
|
||||
self.fixed_ip.subnet.cidr = '198.51.100.0/24'
|
||||
self.fixed_ip.subnet.gateway_ip = FAKE_GATEWAY
|
||||
self.network = network_models.Network(mtu=FAKE_MTU)
|
||||
self.port = network_models.Port(mac_address=FAKE_MAC_ADDRESS,
|
||||
fixed_ips=[self.fixed_ip],
|
||||
|
@ -116,6 +117,11 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
|||
constants.REQ_READ_TIMEOUT: 2,
|
||||
constants.CONN_MAX_RETRIES: 3,
|
||||
constants.CONN_RETRY_INTERVAL: 4}
|
||||
self.amp_net_config = network_models.AmphoraNetworkConfig(
|
||||
vip_subnet=network_models.Subnet(
|
||||
id=self.lb.vip.subnet_id,
|
||||
cidr='10.1.0.0/16',
|
||||
host_routes=[]))
|
||||
|
||||
@mock.patch('octavia.amphorae.drivers.haproxy.rest_api_driver.'
|
||||
'HaproxyAmphoraLoadBalancerDriver._process_secret')
|
||||
|
@ -684,6 +690,13 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
|||
amphorae_network_config.get().vip_subnet.cidr = FAKE_CIDR
|
||||
amphorae_network_config.get().vip_subnet.gateway_ip = FAKE_GATEWAY
|
||||
amphorae_network_config.get().vip_subnet.host_routes = self.host_routes
|
||||
amphorae_network_config.get().vip_subnet.to_dict.return_value = {
|
||||
'cidr': FAKE_CIDR,
|
||||
'gateway_ip': FAKE_GATEWAY,
|
||||
'host_routes': [
|
||||
hr.to_dict(recurse=True)
|
||||
for hr in self.host_routes]
|
||||
}
|
||||
amphorae_network_config.get().vrrp_port = self.port
|
||||
self.driver.post_vip_plug(self.amp, self.lb, amphorae_network_config)
|
||||
self.driver.clients[API_VERSION].plug_vip.assert_called_once_with(
|
||||
|
@ -694,7 +707,7 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
|||
port = network_models.Port(mac_address=FAKE_MAC_ADDRESS,
|
||||
fixed_ips=[],
|
||||
network=self.network)
|
||||
self.driver.post_network_plug(self.amp, port)
|
||||
self.driver.post_network_plug(self.amp, port, self.amp_net_config)
|
||||
self.driver.clients[API_VERSION].plug_network.assert_called_once_with(
|
||||
self.amp, dict(mac_address=FAKE_MAC_ADDRESS,
|
||||
fixed_ips=[],
|
||||
|
@ -703,14 +716,40 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
|||
self.driver.clients[API_VERSION].plug_network.reset_mock()
|
||||
|
||||
# Test fixed IP path
|
||||
self.driver.post_network_plug(self.amp, self.port)
|
||||
self.driver.post_network_plug(self.amp, self.port, self.amp_net_config)
|
||||
self.driver.clients[API_VERSION].plug_network.assert_called_once_with(
|
||||
self.amp, dict(mac_address=FAKE_MAC_ADDRESS,
|
||||
fixed_ips=[dict(ip_address='198.51.100.5',
|
||||
subnet_cidr='198.51.100.0/24',
|
||||
host_routes=[])],
|
||||
host_routes=[],
|
||||
gateway=FAKE_GATEWAY)],
|
||||
mtu=FAKE_MTU))
|
||||
|
||||
self.driver.clients[API_VERSION].plug_network.reset_mock()
|
||||
|
||||
# Test member network on vip port
|
||||
port = network_models.Port(id=self.amp.vrrp_port_id,
|
||||
mac_address=FAKE_MAC_ADDRESS,
|
||||
fixed_ips=[self.fixed_ip],
|
||||
network=self.network)
|
||||
self.driver.post_network_plug(self.amp, port, self.amp_net_config)
|
||||
self.driver.clients[API_VERSION].plug_network.assert_called_once_with(
|
||||
self.amp, dict(mac_address=FAKE_MAC_ADDRESS,
|
||||
fixed_ips=[dict(ip_address='198.51.100.5',
|
||||
subnet_cidr='198.51.100.0/24',
|
||||
host_routes=[],
|
||||
gateway=FAKE_GATEWAY)],
|
||||
mtu=FAKE_MTU,
|
||||
vip_net_info=dict(
|
||||
vip=self.amp.ha_ip,
|
||||
subnet_cidr='10.1.0.0/16',
|
||||
mac_address=FAKE_MAC_ADDRESS,
|
||||
gateway=None,
|
||||
vrrp_ip=self.amp.vrrp_ip,
|
||||
host_routes=[],
|
||||
mtu=FAKE_MTU
|
||||
)))
|
||||
|
||||
def test_post_network_plug_with_host_routes(self):
|
||||
SUBNET_ID = 'SUBNET_ID'
|
||||
FIXED_IP1 = '192.0.2.2'
|
||||
|
@ -724,6 +763,7 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
|||
network_models.HostRoute(destination=DEST2,
|
||||
nexthop=NEXTHOP)]
|
||||
subnet = network_models.Subnet(id=SUBNET_ID, cidr=SUBNET_CIDR,
|
||||
gateway_ip=FAKE_GATEWAY,
|
||||
ip_version=4, host_routes=host_routes)
|
||||
fixed_ips = [
|
||||
network_models.FixedIP(subnet_id=subnet.id, ip_address=FIXED_IP1,
|
||||
|
@ -734,12 +774,14 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
|||
port = network_models.Port(mac_address=FAKE_MAC_ADDRESS,
|
||||
fixed_ips=fixed_ips,
|
||||
network=self.network)
|
||||
self.driver.post_network_plug(self.amp, port)
|
||||
self.driver.post_network_plug(self.amp, port, self.amp_net_config)
|
||||
expected_fixed_ips = [
|
||||
{'ip_address': FIXED_IP1, 'subnet_cidr': SUBNET_CIDR,
|
||||
'gateway': FAKE_GATEWAY,
|
||||
'host_routes': [{'destination': DEST1, 'nexthop': NEXTHOP},
|
||||
{'destination': DEST2, 'nexthop': NEXTHOP}]},
|
||||
{'ip_address': FIXED_IP2, 'subnet_cidr': SUBNET_CIDR,
|
||||
'gateway': FAKE_GATEWAY,
|
||||
'host_routes': [{'destination': DEST1, 'nexthop': NEXTHOP},
|
||||
{'destination': DEST2, 'nexthop': NEXTHOP}]}
|
||||
]
|
||||
|
|
|
@ -115,7 +115,9 @@ class TestNoopAmphoraLoadBalancerDriver(base.TestCase):
|
|||
self.amphora.id])
|
||||
|
||||
def test_post_network_plug(self):
|
||||
self.driver.post_network_plug(self.amphora, self.port)
|
||||
self.driver.post_network_plug(
|
||||
self.amphora, self.port,
|
||||
self.amphorae_net_configs[self.amphora.id])
|
||||
self.assertEqual((self.amphora.id, self.port.id, 'post_network_plug'),
|
||||
self.driver.driver.amphoraconfig[(
|
||||
self.amphora.id, self.port.id)])
|
||||
|
|
|
@ -24,16 +24,20 @@ from octavia.tests.common import sample_certs
|
|||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class AmphoraTuple(collections.namedtuple(
|
||||
'amphora', 'id, lb_network_ip, vrrp_ip, ha_ip, vrrp_port_id, '
|
||||
'ha_port_id, role, status, vrrp_interface,'
|
||||
'vrrp_priority, api_version')):
|
||||
def to_dict(self):
|
||||
return self._asdict()
|
||||
|
||||
|
||||
def sample_amphora_tuple(id='sample_amphora_id_1', lb_network_ip='10.0.1.1',
|
||||
vrrp_ip='10.1.1.1', ha_ip='192.168.10.1',
|
||||
vrrp_port_id='1234', ha_port_id='1234', role=None,
|
||||
status='ACTIVE', vrrp_interface=None,
|
||||
vrrp_priority=None, api_version='1.0'):
|
||||
in_amphora = collections.namedtuple(
|
||||
'amphora', 'id, lb_network_ip, vrrp_ip, ha_ip, vrrp_port_id, '
|
||||
'ha_port_id, role, status, vrrp_interface,'
|
||||
'vrrp_priority, api_version')
|
||||
return in_amphora(
|
||||
amp = AmphoraTuple(
|
||||
id=id,
|
||||
lb_network_ip=lb_network_ip,
|
||||
vrrp_ip=vrrp_ip,
|
||||
|
@ -45,6 +49,7 @@ def sample_amphora_tuple(id='sample_amphora_id_1', lb_network_ip='10.0.1.1',
|
|||
vrrp_interface=vrrp_interface,
|
||||
vrrp_priority=vrrp_priority,
|
||||
api_version=api_version)
|
||||
return amp
|
||||
|
||||
|
||||
RET_PERSISTENCE = {
|
||||
|
@ -648,9 +653,9 @@ def sample_vrrp_group_tuple():
|
|||
smtp_connect_timeout='')
|
||||
|
||||
|
||||
def sample_vip_tuple():
|
||||
vip = collections.namedtuple('vip', 'ip_address')
|
||||
return vip(ip_address='10.0.0.2')
|
||||
def sample_vip_tuple(ip_address='10.0.0.2', subnet_id='vip_subnet_uuid'):
|
||||
vip = collections.namedtuple('vip', ('ip_address', 'subnet_id'))
|
||||
return vip(ip_address=ip_address, subnet_id=subnet_id)
|
||||
|
||||
|
||||
def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
||||
|
|
|
@ -23,16 +23,20 @@ from octavia.tests.common import sample_certs
|
|||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class AmphoraTuple(collections.namedtuple(
|
||||
'amphora', 'id, lb_network_ip, vrrp_ip, ha_ip, vrrp_port_id, '
|
||||
'ha_port_id, role, status, vrrp_interface,'
|
||||
'vrrp_priority, api_version')):
|
||||
def to_dict(self):
|
||||
return self._asdict()
|
||||
|
||||
|
||||
def sample_amphora_tuple(id='sample_amphora_id_1', lb_network_ip='10.0.1.1',
|
||||
vrrp_ip='10.1.1.1', ha_ip='192.168.10.1',
|
||||
vrrp_port_id='1234', ha_port_id='1234', role=None,
|
||||
status='ACTIVE', vrrp_interface=None,
|
||||
vrrp_priority=None, api_version='0.5'):
|
||||
in_amphora = collections.namedtuple(
|
||||
'amphora', 'id, lb_network_ip, vrrp_ip, ha_ip, vrrp_port_id, '
|
||||
'ha_port_id, role, status, vrrp_interface,'
|
||||
'vrrp_priority, api_version')
|
||||
return in_amphora(
|
||||
return AmphoraTuple(
|
||||
id=id,
|
||||
lb_network_ip=lb_network_ip,
|
||||
vrrp_ip=vrrp_ip,
|
||||
|
@ -599,9 +603,9 @@ def sample_vrrp_group_tuple():
|
|||
smtp_connect_timeout='')
|
||||
|
||||
|
||||
def sample_vip_tuple():
|
||||
vip = collections.namedtuple('vip', 'ip_address')
|
||||
return vip(ip_address='10.0.0.2')
|
||||
def sample_vip_tuple(ip_address='10.0.0.2', subnet_id='vip_subnet_uuid'):
|
||||
vip = collections.namedtuple('vip', ('ip_address', 'subnet_id'))
|
||||
return vip(ip_address=ip_address, subnet_id=subnet_id)
|
||||
|
||||
|
||||
def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
||||
|
|
|
@ -238,7 +238,7 @@ class TestAmphoraFlows(base.TestCase):
|
|||
self.assertIn(constants.LOADBALANCER_ID, amp_flow.requires)
|
||||
self.assertIn(constants.VIP, amp_flow.requires)
|
||||
|
||||
self.assertIn(constants.ADDED_PORTS, amp_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, amp_flow.provides)
|
||||
self.assertIn(constants.AMP_VRRP_INT, amp_flow.provides)
|
||||
self.assertIn(constants.AMPHORA, amp_flow.provides)
|
||||
self.assertIn(constants.AMPHORA_ID, amp_flow.provides)
|
||||
|
@ -272,7 +272,7 @@ class TestAmphoraFlows(base.TestCase):
|
|||
self.assertIn(constants.LOADBALANCER_ID, amp_flow.requires)
|
||||
self.assertIn(constants.VIP, amp_flow.requires)
|
||||
|
||||
self.assertIn(constants.ADDED_PORTS, amp_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, amp_flow.provides)
|
||||
self.assertIn(constants.AMPHORA, amp_flow.provides)
|
||||
self.assertIn(constants.AMPHORA_ID, amp_flow.provides)
|
||||
self.assertIn(constants.AMPHORAE, amp_flow.provides)
|
||||
|
@ -430,7 +430,7 @@ class TestAmphoraFlows(base.TestCase):
|
|||
self.assertIn(constants.VIP, get_amp_flow.requires)
|
||||
self.assertIn(constants.VIP_SG_ID, get_amp_flow.requires)
|
||||
|
||||
self.assertIn(constants.ADDED_PORTS, get_amp_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, get_amp_flow.provides)
|
||||
self.assertIn(constants.AMPHORA, get_amp_flow.provides)
|
||||
self.assertIn(constants.AMPHORA_ID, get_amp_flow.provides)
|
||||
self.assertIn(constants.AMPHORAE_NETWORK_CONFIG, get_amp_flow.provides)
|
||||
|
@ -460,7 +460,7 @@ class TestAmphoraFlows(base.TestCase):
|
|||
self.assertIn(constants.VIP, get_amp_flow.requires)
|
||||
self.assertIn(constants.VIP_SG_ID, get_amp_flow.requires)
|
||||
|
||||
self.assertIn(constants.ADDED_PORTS, get_amp_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, get_amp_flow.provides)
|
||||
self.assertIn(constants.AMPHORA, get_amp_flow.provides)
|
||||
self.assertIn(constants.AMPHORA_ID, get_amp_flow.provides)
|
||||
self.assertIn(constants.AMPHORAE_NETWORK_CONFIG, get_amp_flow.provides)
|
||||
|
|
|
@ -183,22 +183,28 @@ class TestLoadBalancerFlows(base.TestCase):
|
|||
self.assertIsInstance(create_flow, flow.Flow)
|
||||
self.assertIn(constants.LOADBALANCER_ID, create_flow.requires)
|
||||
self.assertIn(constants.UPDATE_DICT, create_flow.requires)
|
||||
self.assertIn(constants.BUILD_TYPE_PRIORITY, create_flow.requires)
|
||||
self.assertIn(constants.FLAVOR, create_flow.requires)
|
||||
self.assertIn(constants.AMPHORAE_NETWORK_CONFIG, create_flow.requires)
|
||||
self.assertIn(constants.AVAILABILITY_ZONE, create_flow.requires)
|
||||
self.assertIn(constants.SERVER_GROUP_ID, create_flow.requires)
|
||||
|
||||
self.assertIn(constants.LISTENERS, create_flow.provides)
|
||||
self.assertIn(constants.SUBNET, create_flow.provides)
|
||||
self.assertIn(constants.AMPHORA, create_flow.provides)
|
||||
self.assertIn(constants.AMPHORA_ID, create_flow.provides)
|
||||
self.assertIn(constants.COMPUTE_ID, create_flow.provides)
|
||||
self.assertIn(constants.COMPUTE_OBJ, create_flow.provides)
|
||||
self.assertIn(constants.LOADBALANCER, create_flow.provides)
|
||||
self.assertIn(constants.DELTAS, create_flow.provides)
|
||||
self.assertIn(constants.ADDED_PORTS, create_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, create_flow.provides)
|
||||
self.assertIn(constants.VIP, create_flow.provides)
|
||||
self.assertIn(constants.AMP_DATA, create_flow.provides)
|
||||
self.assertIn(constants.SERVER_PEM, create_flow.provides)
|
||||
self.assertIn(constants.AMPHORA_NETWORK_CONFIG, create_flow.provides)
|
||||
|
||||
self.assertEqual(6, len(create_flow.requires))
|
||||
self.assertEqual(13, len(create_flow.provides),
|
||||
create_flow.provides)
|
||||
self.assertEqual(7, len(create_flow.requires))
|
||||
self.assertEqual(13, len(create_flow.provides))
|
||||
|
||||
def test_get_create_load_balancer_flows_active_standby_listeners(
|
||||
self, mock_get_net_driver):
|
||||
|
@ -218,7 +224,7 @@ class TestLoadBalancerFlows(base.TestCase):
|
|||
self.assertIn(constants.COMPUTE_OBJ, create_flow.provides)
|
||||
self.assertIn(constants.LOADBALANCER, create_flow.provides)
|
||||
self.assertIn(constants.DELTAS, create_flow.provides)
|
||||
self.assertIn(constants.ADDED_PORTS, create_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, create_flow.provides)
|
||||
self.assertIn(constants.VIP, create_flow.provides)
|
||||
self.assertIn(constants.AMP_DATA, create_flow.provides)
|
||||
self.assertIn(constants.AMPHORAE_NETWORK_CONFIG,
|
||||
|
@ -243,7 +249,7 @@ class TestLoadBalancerFlows(base.TestCase):
|
|||
self.assertIn(constants.LOADBALANCER, failover_flow.requires)
|
||||
self.assertIn(constants.LOADBALANCER_ID, failover_flow.requires)
|
||||
|
||||
self.assertIn(constants.ADDED_PORTS, failover_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, failover_flow.provides)
|
||||
self.assertIn(constants.AMPHORA, failover_flow.provides)
|
||||
self.assertIn(constants.AMPHORA_ID, failover_flow.provides)
|
||||
self.assertIn(constants.AMPHORAE_NETWORK_CONFIG,
|
||||
|
@ -312,7 +318,7 @@ class TestLoadBalancerFlows(base.TestCase):
|
|||
self.assertIn(constants.LOADBALANCER, failover_flow.requires)
|
||||
self.assertIn(constants.LOADBALANCER_ID, failover_flow.requires)
|
||||
|
||||
self.assertIn(constants.ADDED_PORTS, failover_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, failover_flow.provides)
|
||||
self.assertIn(constants.AMP_VRRP_INT, failover_flow.provides)
|
||||
self.assertIn(constants.AMPHORA, failover_flow.provides)
|
||||
self.assertIn(constants.AMPHORA_ID, failover_flow.provides)
|
||||
|
|
|
@ -37,6 +37,7 @@ class TestMemberFlows(base.TestCase):
|
|||
|
||||
self.assertIsInstance(member_flow, flow.Flow)
|
||||
|
||||
self.assertIn(constants.MEMBER, member_flow.requires)
|
||||
self.assertIn(constants.LISTENERS, member_flow.requires)
|
||||
self.assertIn(constants.LOADBALANCER, member_flow.requires)
|
||||
self.assertIn(constants.POOL, member_flow.requires)
|
||||
|
@ -44,10 +45,11 @@ class TestMemberFlows(base.TestCase):
|
|||
self.assertIn(constants.AVAILABILITY_ZONE, member_flow.requires)
|
||||
|
||||
self.assertIn(constants.DELTAS, member_flow.provides)
|
||||
self.assertIn(constants.ADDED_PORTS, member_flow.provides)
|
||||
self.assertIn(constants.AMPHORAE_NETWORK_CONFIG, member_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, member_flow.provides)
|
||||
|
||||
self.assertEqual(5, len(member_flow.requires))
|
||||
self.assertEqual(2, len(member_flow.provides))
|
||||
self.assertEqual(6, len(member_flow.requires))
|
||||
self.assertEqual(3, len(member_flow.provides))
|
||||
|
||||
def test_get_delete_member_flow(self, mock_get_net_driver):
|
||||
|
||||
|
@ -58,10 +60,16 @@ class TestMemberFlows(base.TestCase):
|
|||
self.assertIn(constants.MEMBER, member_flow.requires)
|
||||
self.assertIn(constants.LISTENERS, member_flow.requires)
|
||||
self.assertIn(constants.LOADBALANCER, member_flow.requires)
|
||||
self.assertIn(constants.LOADBALANCER_ID, member_flow.requires)
|
||||
self.assertIn(constants.POOL, member_flow.requires)
|
||||
self.assertIn(constants.AVAILABILITY_ZONE, member_flow.requires)
|
||||
|
||||
self.assertEqual(4, len(member_flow.requires))
|
||||
self.assertEqual(0, len(member_flow.provides))
|
||||
self.assertIn(constants.AMPHORAE_NETWORK_CONFIG, member_flow.provides)
|
||||
self.assertIn(constants.DELTAS, member_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, member_flow.provides)
|
||||
|
||||
self.assertEqual(6, len(member_flow.requires))
|
||||
self.assertEqual(3, len(member_flow.provides))
|
||||
|
||||
def test_get_update_member_flow(self, mock_get_net_driver):
|
||||
|
||||
|
@ -91,7 +99,8 @@ class TestMemberFlows(base.TestCase):
|
|||
self.assertIn(constants.AVAILABILITY_ZONE, member_flow.requires)
|
||||
|
||||
self.assertIn(constants.DELTAS, member_flow.provides)
|
||||
self.assertIn(constants.ADDED_PORTS, member_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, member_flow.provides)
|
||||
self.assertIn(constants.AMPHORAE_NETWORK_CONFIG, member_flow.provides)
|
||||
|
||||
self.assertEqual(4, len(member_flow.requires))
|
||||
self.assertEqual(2, len(member_flow.provides))
|
||||
self.assertEqual(5, len(member_flow.requires))
|
||||
self.assertEqual(3, len(member_flow.provides))
|
||||
|
|
|
@ -50,6 +50,9 @@ _vip_mock = mock.MagicMock()
|
|||
_load_balancer_mock.vip = _vip_mock
|
||||
_LB_mock = mock.MagicMock()
|
||||
_amphorae_mock = [_amphora_mock]
|
||||
_amphora_network_config_mock = mock.MagicMock()
|
||||
_amphorae_network_config_mock = {
|
||||
_amphora_mock.id: _amphora_network_config_mock}
|
||||
_network_mock = mock.MagicMock()
|
||||
_port_mock = mock.MagicMock()
|
||||
_ports_mock = [_port_mock]
|
||||
|
@ -379,10 +382,12 @@ class TestAmphoraDriverTasks(base.TestCase):
|
|||
|
||||
amphora_post_network_plug_obj = (amphora_driver_tasks.
|
||||
AmphoraPostNetworkPlug())
|
||||
amphora_post_network_plug_obj.execute(_amphora_mock, _ports_mock)
|
||||
amphora_post_network_plug_obj.execute(_amphora_mock, _ports_mock,
|
||||
_amphora_network_config_mock)
|
||||
|
||||
(mock_driver.post_network_plug.
|
||||
assert_called_once_with)(_amphora_mock, _port_mock)
|
||||
assert_called_once_with)(_amphora_mock, _port_mock,
|
||||
_amphora_network_config_mock)
|
||||
|
||||
# Test revert
|
||||
amp = amphora_post_network_plug_obj.revert(None, _amphora_mock)
|
||||
|
@ -428,17 +433,20 @@ class TestAmphoraDriverTasks(base.TestCase):
|
|||
port_mock = mock.Mock()
|
||||
_deltas_mock = {_amphora_mock.id: [port_mock]}
|
||||
|
||||
amphora_post_network_plug_obj.execute(_LB_mock, _deltas_mock)
|
||||
amphora_post_network_plug_obj.execute(_LB_mock, _deltas_mock,
|
||||
_amphorae_network_config_mock)
|
||||
|
||||
(mock_driver.post_network_plug.
|
||||
assert_called_once_with(_amphora_mock, port_mock))
|
||||
assert_called_once_with(_amphora_mock, port_mock,
|
||||
_amphora_network_config_mock))
|
||||
|
||||
# Test with no ports to plug
|
||||
mock_driver.post_network_plug.reset_mock()
|
||||
|
||||
_deltas_mock = {'0': [port_mock]}
|
||||
|
||||
amphora_post_network_plug_obj.execute(_LB_mock, _deltas_mock)
|
||||
amphora_post_network_plug_obj.execute(_LB_mock, _deltas_mock,
|
||||
_amphora_network_config_mock)
|
||||
mock_driver.post_network_plug.assert_not_called()
|
||||
|
||||
# Test revert
|
||||
|
|
|
@ -34,6 +34,8 @@ COMPUTE_ID = uuidutils.generate_uuid()
|
|||
PORT_ID = uuidutils.generate_uuid()
|
||||
SUBNET_ID = uuidutils.generate_uuid()
|
||||
NETWORK_ID = uuidutils.generate_uuid()
|
||||
MGMT_NETWORK_ID = uuidutils.generate_uuid()
|
||||
MGMT_SUBNET_ID = uuidutils.generate_uuid()
|
||||
SG_ID = uuidutils.generate_uuid()
|
||||
IP_ADDRESS = "172.24.41.1"
|
||||
VIP = o_data_models.Vip(port_id=t_constants.MOCK_PORT_ID,
|
||||
|
@ -76,23 +78,27 @@ class TestNetworkTasks(base.TestCase):
|
|||
self.load_balancer_mock = mock.MagicMock()
|
||||
self.vip_mock = mock.MagicMock()
|
||||
self.vip_mock.subnet_id = SUBNET_ID
|
||||
self.vip_mock.network_id = NETWORK_ID
|
||||
self.load_balancer_mock.vip = self.vip_mock
|
||||
self.load_balancer_mock.amphorae = []
|
||||
self.amphora_mock.id = AMPHORA_ID
|
||||
self.amphora_mock.compute_id = COMPUTE_ID
|
||||
self.amphora_mock.status = constants.AMPHORA_ALLOCATED
|
||||
self.boot_net_id = NETWORK_ID
|
||||
self.mgmt_net_id = MGMT_NETWORK_ID
|
||||
self.mgmt_subnet_id = MGMT_SUBNET_ID
|
||||
conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
|
||||
conf.config(group="controller_worker",
|
||||
amp_boot_network_list=[self.boot_net_id])
|
||||
amp_boot_network_list=[MGMT_NETWORK_ID])
|
||||
conf.config(group="networking", max_retries=1)
|
||||
super().setUp()
|
||||
|
||||
def test_calculate_amphora_delta(self, mock_get_net_driver):
|
||||
VRRP_PORT_ID = uuidutils.generate_uuid()
|
||||
VIP_NETWORK_ID = uuidutils.generate_uuid()
|
||||
VIP_SUBNET_ID = uuidutils.generate_uuid()
|
||||
DELETE_NETWORK_ID = uuidutils.generate_uuid()
|
||||
MEMBER_NETWORK_ID = uuidutils.generate_uuid()
|
||||
MEMBER_SUBNET_ID = uuidutils.generate_uuid()
|
||||
VRRP_PORT_ID = uuidutils.generate_uuid()
|
||||
mock_driver = mock.MagicMock()
|
||||
mock_get_net_driver.return_value = mock_driver
|
||||
member_mock = mock.MagicMock()
|
||||
|
@ -101,23 +107,55 @@ class TestNetworkTasks(base.TestCase):
|
|||
pool_mock.members = [member_mock]
|
||||
lb_mock = mock.MagicMock()
|
||||
lb_mock.pools = [pool_mock]
|
||||
lb_mock.vip = mock.MagicMock()
|
||||
lb_mock.vip.subnet_id = VIP_SUBNET_ID
|
||||
lb_mock.vip.network_id = VIP_NETWORK_ID
|
||||
amphora_mock = mock.MagicMock()
|
||||
amphora_mock.id = AMPHORA_ID
|
||||
amphora_mock.compute_id = COMPUTE_ID
|
||||
amphora_mock.vrrp_port_id = VRRP_PORT_ID
|
||||
vrrp_port_mock = mock.MagicMock()
|
||||
vrrp_port_mock.network_id = self.boot_net_id
|
||||
mock_subnet = mock.MagicMock()
|
||||
mock_subnet.network_id = MEMBER_NETWORK_ID
|
||||
nic1_delete_mock = mock.MagicMock()
|
||||
nic1_delete_mock.network_id = DELETE_NETWORK_ID
|
||||
nic2_keep_mock = mock.MagicMock()
|
||||
nic2_keep_mock.network_id = self.boot_net_id
|
||||
|
||||
mock_driver.get_port.return_value = vrrp_port_mock
|
||||
mock_driver.get_subnet.return_value = mock_subnet
|
||||
mock_driver.get_plugged_networks.return_value = [nic1_delete_mock,
|
||||
nic2_keep_mock]
|
||||
mgmt_subnet = data_models.Subnet(
|
||||
id=MGMT_SUBNET_ID,
|
||||
network_id=MGMT_NETWORK_ID)
|
||||
mgmt_net = data_models.Network(
|
||||
id=MGMT_NETWORK_ID,
|
||||
subnets=[mgmt_subnet.id])
|
||||
mgmt_interface = data_models.Interface(
|
||||
network_id=mgmt_net.id,
|
||||
fixed_ips=[
|
||||
data_models.FixedIP(
|
||||
subnet_id=mgmt_subnet.id)])
|
||||
|
||||
vrrp_subnet = data_models.Subnet(
|
||||
id=VIP_SUBNET_ID,
|
||||
network_id=VIP_NETWORK_ID)
|
||||
vrrp_port = data_models.Port(
|
||||
id=VRRP_PORT_ID,
|
||||
network_id=VIP_NETWORK_ID,
|
||||
fixed_ips=[
|
||||
data_models.FixedIP(
|
||||
subnet=vrrp_subnet,
|
||||
subnet_id=vrrp_subnet.id)])
|
||||
vrrp_interface = data_models.Interface(
|
||||
network_id=VIP_NETWORK_ID,
|
||||
fixed_ips=vrrp_port.fixed_ips)
|
||||
|
||||
member_subnet = data_models.Subnet(
|
||||
id=MEMBER_SUBNET_ID,
|
||||
network_id=MEMBER_NETWORK_ID)
|
||||
|
||||
to_be_deleted_interface = data_models.Interface(
|
||||
id=mock.Mock(),
|
||||
network_id=DELETE_NETWORK_ID)
|
||||
|
||||
mock_driver.get_port.return_value = vrrp_port
|
||||
mock_driver.get_subnet.return_value = member_subnet
|
||||
mock_driver.get_network.return_value = mgmt_net
|
||||
mock_driver.get_plugged_networks.return_value = [
|
||||
mgmt_interface,
|
||||
vrrp_interface,
|
||||
to_be_deleted_interface]
|
||||
|
||||
calc_amp_delta = network_tasks.CalculateAmphoraDelta()
|
||||
|
||||
|
@ -130,15 +168,21 @@ class TestNetworkTasks(base.TestCase):
|
|||
self.assertEqual(MEMBER_NETWORK_ID, result.add_nics[0].network_id)
|
||||
self.assertEqual(1, len(result.delete_nics))
|
||||
self.assertEqual(DELETE_NETWORK_ID, result.delete_nics[0].network_id)
|
||||
mock_driver.get_port.assert_called_once_with(VRRP_PORT_ID)
|
||||
mock_driver.get_subnet.assert_called_once_with(MEMBER_SUBNET_ID)
|
||||
mock_driver.get_plugged_networks.assert_called_once_with(COMPUTE_ID)
|
||||
|
||||
# Test with vrrp_port_id
|
||||
mock_driver.reset_mock()
|
||||
mock_driver.get_port.return_value = vrrp_port
|
||||
mock_driver.get_subnet.return_value = member_subnet
|
||||
mock_driver.get_network.return_value = mgmt_net
|
||||
mock_driver.get_plugged_networks.return_value = [
|
||||
mgmt_interface,
|
||||
vrrp_interface,
|
||||
to_be_deleted_interface]
|
||||
|
||||
result = calc_amp_delta.execute(lb_mock, amphora_mock, {},
|
||||
vrrp_port=vrrp_port_mock)
|
||||
vrrp_port=vrrp_port)
|
||||
|
||||
self.assertEqual(AMPHORA_ID, result.amphora_id)
|
||||
self.assertEqual(COMPUTE_ID, result.compute_id)
|
||||
|
@ -146,7 +190,6 @@ class TestNetworkTasks(base.TestCase):
|
|||
self.assertEqual(MEMBER_NETWORK_ID, result.add_nics[0].network_id)
|
||||
self.assertEqual(1, len(result.delete_nics))
|
||||
self.assertEqual(DELETE_NETWORK_ID, result.delete_nics[0].network_id)
|
||||
mock_driver.get_port.assert_not_called()
|
||||
mock_driver.get_subnet.assert_called_once_with(MEMBER_SUBNET_ID)
|
||||
mock_driver.get_plugged_networks.assert_called_once_with(COMPUTE_ID)
|
||||
|
||||
|
@ -158,105 +201,443 @@ class TestNetworkTasks(base.TestCase):
|
|||
amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[],
|
||||
delete_nics=[])}
|
||||
delete_nics=[],
|
||||
add_subnets=[],
|
||||
delete_subnets=[],
|
||||
)}
|
||||
|
||||
mgmt_subnet = data_models.Subnet(
|
||||
id=self.mgmt_subnet_id, network_id=self.mgmt_net_id)
|
||||
mgmt_net = data_models.Network(
|
||||
id=self.mgmt_net_id,
|
||||
subnets=[mgmt_subnet.id])
|
||||
mgmt_ip_address = mock.MagicMock()
|
||||
mgmt_interface = data_models.Interface(
|
||||
network_id=self.mgmt_net_id,
|
||||
fixed_ips=[
|
||||
data_models.FixedIP(
|
||||
subnet=mgmt_subnet,
|
||||
subnet_id=self.mgmt_subnet_id,
|
||||
ip_address=mgmt_ip_address
|
||||
)
|
||||
])
|
||||
vrrp_subnet = data_models.Subnet(
|
||||
id=self.vip_mock.subnet_id, network_id=self.vip_mock.network_id,
|
||||
name='vrrp_subnet')
|
||||
member_vip_subnet = data_models.Subnet(
|
||||
id=uuidutils.generate_uuid(), network_id=self.vip_mock.network_id,
|
||||
name='member_vip_subnet')
|
||||
vip_net = data_models.Network(
|
||||
id=self.vip_mock.network_id,
|
||||
subnets=[member_vip_subnet, vrrp_subnet],
|
||||
name='flat_network')
|
||||
vrrp_port = data_models.Port(
|
||||
id=uuidutils.generate_uuid(),
|
||||
network_id=vip_net.id, network=vip_net,
|
||||
fixed_ips=[
|
||||
data_models.FixedIP(
|
||||
subnet=vrrp_subnet, subnet_id=vrrp_subnet.id,
|
||||
ip_address=t_constants.MOCK_IP_ADDRESS)
|
||||
],
|
||||
name='vrrp_port')
|
||||
|
||||
member_private_net_id = uuidutils.generate_uuid()
|
||||
member_private_subnet = data_models.Subnet(
|
||||
id=uuidutils.generate_uuid(), network_id=member_private_net_id,
|
||||
name='member_private_subnet')
|
||||
member_private_subnet2 = data_models.Subnet(
|
||||
id=uuidutils.generate_uuid(), network_id=member_private_net_id,
|
||||
name='member_private_subnet2')
|
||||
member_private_net = data_models.Network(
|
||||
id=member_private_subnet.network_id,
|
||||
subnets=[member_private_subnet, member_private_subnet2],
|
||||
name='member_private_net')
|
||||
member_private_subnet_port = data_models.Port(
|
||||
id=uuidutils.generate_uuid(),
|
||||
network_id=member_private_net.id, network=member_private_net,
|
||||
fixed_ips=[
|
||||
data_models.FixedIP(
|
||||
subnet=member_private_subnet,
|
||||
subnet_id=member_private_subnet.id,
|
||||
ip_address=t_constants.MOCK_IP_ADDRESS2)
|
||||
],
|
||||
name='member_private_net_port')
|
||||
member_private_subnet2_port = data_models.Port(
|
||||
id=uuidutils.generate_uuid(),
|
||||
network_id=member_private_net.id, network=member_private_net,
|
||||
fixed_ips=[
|
||||
data_models.FixedIP(
|
||||
subnet=member_private_subnet2,
|
||||
subnet_id=member_private_subnet2.id,
|
||||
ip_address=t_constants.MOCK_IP_ADDRESS2)
|
||||
],
|
||||
name='member_private_net_port')
|
||||
|
||||
# Pretend the VIP is on the member network, so already plugged
|
||||
mock_driver.get_plugged_networks.return_value = [
|
||||
mgmt_interface,
|
||||
data_models.Interface(
|
||||
network_id=vip_net.id, port_id=vrrp_port.id,
|
||||
fixed_ips=vrrp_port.fixed_ips)]
|
||||
mock_driver.get_port.return_value = vrrp_port
|
||||
mock_driver.get_subnet.return_value = vrrp_subnet
|
||||
mock_driver.get_network.return_value = mgmt_net
|
||||
|
||||
calc_delta = network_tasks.CalculateDelta()
|
||||
|
||||
self.assertEqual(EMPTY,
|
||||
calc_delta.execute(self.load_balancer_mock, {}))
|
||||
# Test with no amps or anything at all
|
||||
self.assertEqual(EMPTY, calc_delta.execute(
|
||||
self.load_balancer_mock, {}))
|
||||
|
||||
# Test with one amp and no pools, nothing plugged
|
||||
# Test with one amp and no pools, only the base network plugged
|
||||
# Delta should be empty
|
||||
mock_driver.reset_mock()
|
||||
|
||||
self.amphora_mock.load_balancer = self.load_balancer_mock
|
||||
self.load_balancer_mock.amphorae = [self.amphora_mock]
|
||||
self.load_balancer_mock.pools = []
|
||||
|
||||
self.assertEqual(empty_deltas,
|
||||
calc_delta.execute(self.load_balancer_mock, {}))
|
||||
mock_driver.get_plugged_networks.assert_called_once_with(COMPUTE_ID)
|
||||
|
||||
# Pool mock should be configured explicitly for each test
|
||||
pool_mock = mock.MagicMock()
|
||||
self.load_balancer_mock.pools = [pool_mock]
|
||||
|
||||
# Test with one amp and one pool but no members, nothing plugged
|
||||
# Delta should be empty
|
||||
mock_driver.reset_mock()
|
||||
pool_mock = mock.MagicMock()
|
||||
pool_mock.members = []
|
||||
self.load_balancer_mock.pools = [pool_mock]
|
||||
self.assertEqual(empty_deltas,
|
||||
calc_delta.execute(self.load_balancer_mock, {}))
|
||||
|
||||
# Test with one amp and one pool and one member, nothing plugged
|
||||
# Delta should be one additional subnet to plug
|
||||
# Test with one amp/pool and one member (on a distinct member subnet)
|
||||
# Dummy AZ is provided
|
||||
# Only the base network is already plugged
|
||||
# Delta should be one additional network/subnet to plug
|
||||
mock_driver.reset_mock()
|
||||
member_mock = mock.MagicMock()
|
||||
member_mock.subnet_id = 1
|
||||
member_mock.subnet_id = member_private_subnet.id
|
||||
member2_mock = mock.MagicMock()
|
||||
member2_mock.subnet_id = member_private_subnet2.id
|
||||
pool_mock.members = [member_mock]
|
||||
mock_driver.get_subnet.return_value = data_models.Subnet(id=2,
|
||||
network_id=3)
|
||||
az = {
|
||||
constants.COMPUTE_ZONE: 'foo'
|
||||
}
|
||||
mock_driver.get_subnet.return_value = data_models.Subnet(
|
||||
id=2, network_id=3)
|
||||
|
||||
ndm = data_models.Delta(amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[
|
||||
data_models.Interface(network_id=2)],
|
||||
delete_nics=[])
|
||||
ndm = data_models.Delta(
|
||||
amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[
|
||||
data_models.Interface(
|
||||
network_id=3,
|
||||
fixed_ips=[
|
||||
data_models.FixedIP(
|
||||
subnet_id=member_private_subnet.id)])],
|
||||
delete_nics=[],
|
||||
add_subnets=[{
|
||||
'subnet_id': member_private_subnet.id,
|
||||
'network_id': 3,
|
||||
'port_id': None}],
|
||||
delete_subnets=[])
|
||||
self.assertEqual({self.amphora_mock.id: ndm},
|
||||
calc_delta.execute(self.load_balancer_mock, {}))
|
||||
calc_delta.execute(self.load_balancer_mock, az))
|
||||
|
||||
vrrp_port_call = mock.call(self.amphora_mock.vrrp_port_id)
|
||||
mock_driver.get_port.assert_has_calls([vrrp_port_call])
|
||||
self.assertEqual(1, mock_driver.get_port.call_count)
|
||||
mock_driver.get_subnet.assert_called_once_with(
|
||||
member_mock.subnet_id)
|
||||
|
||||
member_subnet_call = mock.call(member_mock.subnet_id)
|
||||
mock_driver.get_subnet.assert_has_calls([member_subnet_call])
|
||||
self.assertEqual(1, mock_driver.get_subnet.call_count)
|
||||
|
||||
# Test with one amp and one pool and one member, already plugged
|
||||
# Test with one amp/pool and one member (not plugged) that is being
|
||||
# deleted
|
||||
# Only the base network is already plugged
|
||||
# Delta should be empty
|
||||
mock_driver.reset_mock()
|
||||
member_mock = mock.MagicMock()
|
||||
member_mock.subnet_id = 1
|
||||
member_mock.subnet_id = member_private_subnet.id
|
||||
member_mock.provisioning_status = constants.PENDING_DELETE
|
||||
pool_mock.members = [member_mock]
|
||||
mock_driver.get_plugged_networks.return_value = [
|
||||
data_models.Interface(network_id=2)]
|
||||
|
||||
self.assertEqual(empty_deltas,
|
||||
calc_delta.execute(self.load_balancer_mock, {}))
|
||||
|
||||
# Test with one amp and one pool and one member, wrong network plugged
|
||||
# Delta should be one network to add and one to remove
|
||||
# Test with one amp/pool and one member (without any subnets)
|
||||
# Only the base network is already plugged
|
||||
# No delta
|
||||
mock_driver.reset_mock()
|
||||
member_mock = mock.MagicMock()
|
||||
member_mock.subnet_id = 1
|
||||
member_mock.subnet_id = None
|
||||
pool_mock.members = [member_mock]
|
||||
mock_driver.get_plugged_networks.return_value = [
|
||||
data_models.Interface(network_id=3)]
|
||||
|
||||
ndm = data_models.Delta(amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[
|
||||
data_models.Interface(network_id=2)],
|
||||
delete_nics=[
|
||||
data_models.Interface(network_id=3)])
|
||||
self.assertEqual({self.amphora_mock.id: ndm},
|
||||
self.assertEqual(empty_deltas,
|
||||
calc_delta.execute(self.load_balancer_mock, {}))
|
||||
|
||||
# Test with one amp and one pool and one member
|
||||
# Management network is defined in AZ metadata
|
||||
# Base network AND member network/subnet already plugged
|
||||
# Delta should be empty
|
||||
mock_driver.reset_mock()
|
||||
member_mock = mock.MagicMock()
|
||||
member_mock.subnet_id = member_private_subnet.id
|
||||
pool_mock.members = [member_mock]
|
||||
|
||||
mgmt2_subnet_id = uuidutils.generate_uuid()
|
||||
mgmt2_net_id = uuidutils.generate_uuid()
|
||||
mgmt2_subnet = data_models.Subnet(
|
||||
id=mgmt2_subnet_id,
|
||||
network_id=mgmt2_net_id)
|
||||
mgmt2_net = data_models.Network(
|
||||
id=mgmt2_net_id,
|
||||
subnets=[mgmt2_subnet.id]
|
||||
)
|
||||
mgmt2_interface = data_models.Interface(
|
||||
network_id=mgmt2_net_id,
|
||||
fixed_ips=[
|
||||
data_models.FixedIP(
|
||||
subnet=mgmt2_subnet,
|
||||
subnet_id=mgmt2_subnet_id,
|
||||
)
|
||||
])
|
||||
mock_driver.get_network.return_value = mgmt2_net
|
||||
az = {
|
||||
constants.MANAGEMENT_NETWORK: mgmt2_net_id,
|
||||
}
|
||||
mock_driver.get_subnet.return_value = member_private_subnet
|
||||
mock_driver.get_plugged_networks.return_value = [
|
||||
mgmt2_interface,
|
||||
data_models.Interface(
|
||||
network_id=vrrp_subnet.network_id,
|
||||
fixed_ips=vrrp_port.fixed_ips),
|
||||
data_models.Interface(
|
||||
network_id=member_private_subnet.network_id,
|
||||
fixed_ips=member_private_subnet_port.fixed_ips)]
|
||||
|
||||
self.assertEqual(empty_deltas,
|
||||
calc_delta.execute(self.load_balancer_mock, az))
|
||||
|
||||
# Test with one amp and one pool and one member, wrong network plugged
|
||||
# Delta should be one network/subnet to add and one to remove
|
||||
mock_driver.reset_mock()
|
||||
mock_driver.get_network.return_value = mgmt_net
|
||||
member_mock = mock.MagicMock()
|
||||
member_mock.subnet_id = member_private_subnet.id
|
||||
pool_mock.members = [member_mock]
|
||||
az = {
|
||||
constants.COMPUTE_ZONE: 'foo'
|
||||
}
|
||||
mock_driver.get_subnet.return_value = member_private_subnet
|
||||
mock_driver.get_plugged_networks.return_value = [
|
||||
mgmt_interface,
|
||||
data_models.Interface(
|
||||
network_id=vrrp_subnet.network_id,
|
||||
fixed_ips=vrrp_port.fixed_ips),
|
||||
data_models.Interface(
|
||||
network_id='bad_net',
|
||||
fixed_ips=[data_models.FixedIP(subnet_id='bad_subnet')])]
|
||||
|
||||
ndm = data_models.Delta(
|
||||
amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[data_models.Interface(
|
||||
network_id=member_private_net.id,
|
||||
fixed_ips=[data_models.FixedIP(
|
||||
subnet_id=member_private_subnet.id)])],
|
||||
delete_nics=[data_models.Interface(network_id='bad_net')],
|
||||
add_subnets=[{
|
||||
'subnet_id': member_private_subnet.id,
|
||||
'network_id': member_private_net.id,
|
||||
'port_id': None
|
||||
}],
|
||||
delete_subnets=[{
|
||||
'subnet_id': 'bad_subnet',
|
||||
'network_id': 'bad_net',
|
||||
'port_id': None
|
||||
}])
|
||||
self.assertEqual({self.amphora_mock.id: ndm},
|
||||
calc_delta.execute(self.load_balancer_mock, az))
|
||||
|
||||
# Test with one amp and one pool and no members, one network plugged
|
||||
# Delta should be one network to remove
|
||||
mock_driver.reset_mock()
|
||||
pool_mock.members = []
|
||||
mock_driver.get_subnet.side_effect = [
|
||||
vrrp_subnet]
|
||||
mock_driver.get_plugged_networks.return_value = [
|
||||
data_models.Interface(network_id=2)]
|
||||
mgmt_interface,
|
||||
data_models.Interface(
|
||||
network_id=vrrp_subnet.network_id,
|
||||
fixed_ips=vrrp_port.fixed_ips),
|
||||
data_models.Interface(
|
||||
network_id='bad_net',
|
||||
fixed_ips=[data_models.FixedIP(subnet_id='bad_subnet')])]
|
||||
|
||||
ndm = data_models.Delta(amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[],
|
||||
delete_nics=[
|
||||
data_models.Interface(network_id=2)])
|
||||
ndm = data_models.Delta(
|
||||
amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[],
|
||||
delete_nics=[data_models.Interface(network_id='bad_net')],
|
||||
add_subnets=[],
|
||||
delete_subnets=[{
|
||||
'subnet_id': 'bad_subnet',
|
||||
'network_id': 'bad_net',
|
||||
'port_id': None
|
||||
}])
|
||||
self.assertEqual({self.amphora_mock.id: ndm},
|
||||
calc_delta.execute(self.load_balancer_mock, {}))
|
||||
|
||||
# Add a new member on a new subnet, an interface with another subnet of
|
||||
# the same network is already plugged
|
||||
# Delta should be one new subnet
|
||||
mock_driver.reset_mock()
|
||||
pool_mock.members = [member_mock, member2_mock]
|
||||
mock_driver.get_subnet.side_effect = [
|
||||
vrrp_subnet,
|
||||
member_private_subnet,
|
||||
member_private_subnet2]
|
||||
mock_driver.get_plugged_networks.return_value = [
|
||||
mgmt_interface,
|
||||
data_models.Interface(
|
||||
network_id=vrrp_subnet.network_id,
|
||||
fixed_ips=vrrp_port.fixed_ips),
|
||||
data_models.Interface(
|
||||
network_id=member_private_net_id,
|
||||
port_id=member_private_subnet_port.id,
|
||||
fixed_ips=member_private_subnet_port.fixed_ips)]
|
||||
|
||||
ndm = data_models.Delta(
|
||||
amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[],
|
||||
delete_nics=[],
|
||||
add_subnets=[{
|
||||
'subnet_id': member_private_subnet2.id,
|
||||
'network_id': member_private_net_id,
|
||||
'port_id': member_private_subnet_port.id
|
||||
}],
|
||||
delete_subnets=[]
|
||||
)
|
||||
self.assertEqual({self.amphora_mock.id: ndm},
|
||||
calc_delta.execute(self.load_balancer_mock, {}))
|
||||
|
||||
# a new member on a new subnet on an existing network, a delete member2
|
||||
# on another subnet of the same network
|
||||
# Delta should be one new subnet, one deleted subnet, no interface
|
||||
# change
|
||||
mock_driver.reset_mock()
|
||||
pool_mock.members = [member_mock]
|
||||
mock_driver.get_subnet.return_value = member_private_subnet
|
||||
mock_driver.get_plugged_networks.return_value = [
|
||||
mgmt_interface,
|
||||
data_models.Interface(
|
||||
network_id=vrrp_subnet.network_id,
|
||||
fixed_ips=vrrp_port.fixed_ips),
|
||||
data_models.Interface(
|
||||
network_id=member_private_net_id,
|
||||
port_id=member_private_subnet2_port.id,
|
||||
fixed_ips=member_private_subnet2_port.fixed_ips)]
|
||||
|
||||
ndm = data_models.Delta(
|
||||
amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[],
|
||||
delete_nics=[],
|
||||
add_subnets=[{
|
||||
'subnet_id': member_private_subnet.id,
|
||||
'network_id': member_private_net_id,
|
||||
'port_id': member_private_subnet2_port.id}],
|
||||
delete_subnets=[{
|
||||
'subnet_id': member_private_subnet2.id,
|
||||
'network_id': member_private_net_id,
|
||||
'port_id': member_private_subnet2_port.id}]
|
||||
)
|
||||
self.assertEqual({self.amphora_mock.id: ndm},
|
||||
calc_delta.execute(self.load_balancer_mock, {}))
|
||||
|
||||
# member on subnet on the same network as the vip subnet
|
||||
mock_driver.reset_mock()
|
||||
member_mock.subnet_id = member_vip_subnet.id
|
||||
pool_mock.members = [member_mock]
|
||||
mock_driver.get_subnet.side_effect = [
|
||||
vrrp_subnet,
|
||||
member_vip_subnet]
|
||||
mock_driver.get_plugged_networks.return_value = [
|
||||
mgmt_interface,
|
||||
data_models.Interface(
|
||||
network_id=vrrp_subnet.network_id,
|
||||
port_id=vrrp_port.id,
|
||||
fixed_ips=vrrp_port.fixed_ips),
|
||||
data_models.Interface(
|
||||
network_id=member_private_net_id,
|
||||
port_id=member_private_subnet_port.id,
|
||||
fixed_ips=member_private_subnet_port.fixed_ips)]
|
||||
|
||||
ndm = data_models.Delta(
|
||||
amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[],
|
||||
delete_nics=[
|
||||
data_models.Interface(
|
||||
network_id=member_private_net_id,
|
||||
port_id=member_private_subnet_port.id)],
|
||||
add_subnets=[{
|
||||
'subnet_id': member_vip_subnet.id,
|
||||
'network_id': vip_net.id,
|
||||
'port_id': vrrp_port.id}],
|
||||
delete_subnets=[{
|
||||
'subnet_id': member_private_subnet.id,
|
||||
'network_id': member_private_net_id,
|
||||
'port_id': member_private_subnet_port.id}]
|
||||
)
|
||||
self.assertEqual({self.amphora_mock.id: ndm},
|
||||
calc_delta.execute(self.load_balancer_mock, {}))
|
||||
|
||||
def test_calculate_delta_ipv6_ipv4_subnets(self, mock_get_net_driver):
|
||||
mock_driver = mock.MagicMock()
|
||||
mock_get_net_driver.return_value = mock_driver
|
||||
|
||||
# Pool mock should be configured explicitly for each test
|
||||
pool_mock = mock.MagicMock()
|
||||
self.load_balancer_mock.pools = [pool_mock]
|
||||
self.amphora_mock.load_balancer = self.load_balancer_mock
|
||||
self.load_balancer_mock.amphorae = [self.amphora_mock]
|
||||
|
||||
# Test with one amp and one pool and one new member (in the VIP net)
|
||||
# Delta should be one additional subnet to plug to the existing port
|
||||
vrrp_subnet = data_models.Subnet(
|
||||
id=self.vip_mock.subnet_id, network_id=self.vip_mock.network_id)
|
||||
member_subnet = data_models.Subnet(
|
||||
id=uuidutils.generate_uuid(), network_id=self.vip_mock.network_id)
|
||||
flat_network = data_models.Network(
|
||||
id=self.vip_mock.network_id, subnets=[member_subnet, vrrp_subnet])
|
||||
vrrp_port = data_models.Port(
|
||||
id=uuidutils.generate_uuid(),
|
||||
network_id=flat_network.id, network=flat_network,
|
||||
fixed_ips=[
|
||||
data_models.FixedIP(
|
||||
subnet=vrrp_subnet, subnet_id=vrrp_subnet.id,
|
||||
ip_address=t_constants.MOCK_IP_ADDRESS)
|
||||
])
|
||||
mock_driver.get_subnet.return_value = member_subnet
|
||||
member_mock = mock.MagicMock()
|
||||
member_mock.subnet_id = member_subnet.id
|
||||
pool_mock.members = [member_mock]
|
||||
# Pretend the VIP is on the member network, so already plugged
|
||||
mock_driver.get_plugged_networks.return_value = [
|
||||
data_models.Interface(
|
||||
network_id=flat_network.id, port_id=vrrp_port.id,
|
||||
fixed_ips=vrrp_port.fixed_ips)]
|
||||
mock_driver.get_port.return_value = vrrp_port
|
||||
|
||||
calc_delta = network_tasks.CalculateDelta()
|
||||
deltas = calc_delta.execute(self.load_balancer_mock, {})
|
||||
|
||||
expected_delta = {self.amphora_mock.id: data_models.Delta(
|
||||
amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[],
|
||||
delete_nics=[],
|
||||
add_subnets=[member_subnet.id],
|
||||
delete_subnets=[])}
|
||||
self.assertEqual(expected_delta, deltas)
|
||||
|
||||
def test_get_plumbed_networks(self, mock_get_net_driver):
|
||||
mock_driver = mock.MagicMock()
|
||||
mock_get_net_driver.return_value = mock_driver
|
||||
|
@ -401,8 +782,12 @@ class TestNetworkTasks(base.TestCase):
|
|||
mock_get_net_driver.return_value = mock_net_driver
|
||||
|
||||
nic1 = mock.MagicMock()
|
||||
nic1.fixed_ips = [data_models.FixedIP(
|
||||
subnet_id=uuidutils.generate_uuid())]
|
||||
nic1.network_id = uuidutils.generate_uuid()
|
||||
nic2 = mock.MagicMock()
|
||||
nic2.fixed_ips = [data_models.FixedIP(
|
||||
subnet_id=uuidutils.generate_uuid())]
|
||||
nic2.network_id = uuidutils.generate_uuid()
|
||||
interface1 = mock.MagicMock()
|
||||
interface1.port_id = uuidutils.generate_uuid()
|
||||
|
@ -417,7 +802,9 @@ class TestNetworkTasks(base.TestCase):
|
|||
delta = data_models.Delta(amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[nic1],
|
||||
delete_nics=[nic2, nic2, nic2])
|
||||
delete_nics=[nic2, nic2, nic2],
|
||||
add_subnets=[],
|
||||
delete_subnets=[])
|
||||
|
||||
mock_net_driver.plug_network.return_value = interface1
|
||||
mock_net_driver.get_port.return_value = port1
|
||||
|
@ -463,82 +850,313 @@ class TestNetworkTasks(base.TestCase):
|
|||
mock_driver = mock.MagicMock()
|
||||
mock_get_net_driver.return_value = mock_driver
|
||||
|
||||
def _interface(network_id):
|
||||
return [data_models.Interface(network_id=network_id)]
|
||||
self.load_balancer_mock.amphorae = [self.amphora_mock]
|
||||
|
||||
subnet1 = uuidutils.generate_uuid()
|
||||
network1 = uuidutils.generate_uuid()
|
||||
port1 = uuidutils.generate_uuid()
|
||||
subnet2 = uuidutils.generate_uuid()
|
||||
|
||||
def _interface(network_id, port_id=None, subnet_id=None):
|
||||
return data_models.Interface(
|
||||
network_id=network_id,
|
||||
port_id=port_id,
|
||||
fixed_ips=[
|
||||
data_models.FixedIP(
|
||||
subnet_id=subnet_id)])
|
||||
|
||||
net = network_tasks.HandleNetworkDeltas()
|
||||
|
||||
net.execute({})
|
||||
net.execute({}, self.load_balancer_mock)
|
||||
self.assertFalse(mock_driver.plug_network.called)
|
||||
|
||||
delta = data_models.Delta(amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[],
|
||||
delete_nics=[])
|
||||
net.execute({self.amphora_mock.id: delta})
|
||||
delete_nics=[],
|
||||
add_subnets=[],
|
||||
delete_subnets=[])
|
||||
net.execute({self.amphora_mock.id: delta}, self.load_balancer_mock)
|
||||
self.assertFalse(mock_driver.plug_network.called)
|
||||
|
||||
# Adding a subnet on a new network
|
||||
port = data_models.Port(
|
||||
id=port1,
|
||||
network_id=network1,
|
||||
fixed_ips=[
|
||||
data_models.FixedIP(subnet_id=subnet1)])
|
||||
mock_driver.get_port.return_value = port
|
||||
mock_driver.plug_fixed_ip.return_value = port
|
||||
mock_driver.get_network.return_value = data_models.Network(
|
||||
id=network1)
|
||||
mock_driver.get_subnet.return_value = data_models.Subnet(
|
||||
id=subnet1,
|
||||
network_id=network1)
|
||||
add_nics = [_interface(network1, subnet_id=subnet1)]
|
||||
add_subnets = [{
|
||||
'subnet_id': subnet1,
|
||||
'network_id': network1,
|
||||
'port_id': None}]
|
||||
|
||||
delta = data_models.Delta(amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=_interface(1),
|
||||
delete_nics=[])
|
||||
net.execute({self.amphora_mock.id: delta})
|
||||
mock_driver.plug_network.assert_called_once_with(COMPUTE_ID, 1)
|
||||
add_nics=add_nics,
|
||||
delete_nics=[],
|
||||
add_subnets=add_subnets,
|
||||
delete_subnets=[])
|
||||
updated_ports = net.execute({self.amphora_mock.id: delta},
|
||||
self.load_balancer_mock)
|
||||
mock_driver.plug_network.assert_called_once_with(
|
||||
self.amphora_mock.compute_id, network1)
|
||||
mock_driver.unplug_network.assert_not_called()
|
||||
|
||||
self.assertEqual(1, len(updated_ports))
|
||||
|
||||
updated_port = updated_ports[self.amphora_mock.id][0]
|
||||
self.assertEqual(port1, updated_port.id)
|
||||
self.assertEqual(network1, updated_port.network_id)
|
||||
self.assertEqual(1, len(updated_port.fixed_ips))
|
||||
self.assertEqual(subnet1, updated_port.fixed_ips[0].subnet_id)
|
||||
|
||||
# revert
|
||||
net.execute({self.amphora_mock.id: delta})
|
||||
self.assertFalse(mock_driver.unplug_network.called)
|
||||
net.revert(None, {self.amphora_mock.id: delta},
|
||||
self.load_balancer_mock)
|
||||
mock_driver.unplug_network.assert_called_once_with(
|
||||
self.amphora_mock.compute_id, network1)
|
||||
|
||||
# Adding a subnet on an existing network/port
|
||||
mock_driver.reset_mock()
|
||||
port = data_models.Port(
|
||||
id=port1,
|
||||
network_id=network1,
|
||||
fixed_ips=[
|
||||
data_models.FixedIP(subnet_id=subnet2),
|
||||
data_models.FixedIP(subnet_id=subnet1)])
|
||||
mock_driver.plug_fixed_ip.return_value = port
|
||||
mock_driver.get_network.return_value = data_models.Network(
|
||||
id=network1)
|
||||
mock_driver.get_subnet.side_effect = [
|
||||
data_models.Subnet(
|
||||
id=subnet2,
|
||||
network_id=network1),
|
||||
data_models.Subnet(
|
||||
id=subnet1,
|
||||
network_id=network1)]
|
||||
add_nics = [_interface(network1)]
|
||||
add_subnets = [{
|
||||
'subnet_id': subnet1,
|
||||
'network_id': network1,
|
||||
'port_id': port1}]
|
||||
|
||||
delta = data_models.Delta(amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[],
|
||||
delete_nics=[])
|
||||
net.execute({self.amphora_mock.id: delta})
|
||||
self.assertFalse(mock_driver.unplug_network.called)
|
||||
delete_nics=[],
|
||||
add_subnets=add_subnets,
|
||||
delete_subnets=[])
|
||||
updated_ports = net.execute({self.amphora_mock.id: delta},
|
||||
self.load_balancer_mock)
|
||||
mock_driver.plug_network.assert_not_called()
|
||||
mock_driver.unplug_network.assert_not_called()
|
||||
mock_driver.get_port.assert_not_called()
|
||||
mock_driver.plug_fixed_ip.assert_called_once_with(port_id=port1,
|
||||
subnet_id=subnet1)
|
||||
self.assertEqual(1, len(updated_ports))
|
||||
|
||||
updated_port = updated_ports[self.amphora_mock.id][0]
|
||||
self.assertEqual(port1, updated_port.id)
|
||||
self.assertEqual(network1, updated_port.network_id)
|
||||
self.assertEqual(2, len(updated_port.fixed_ips))
|
||||
self.assertEqual(subnet2, updated_port.fixed_ips[0].subnet_id)
|
||||
self.assertEqual(subnet1, updated_port.fixed_ips[1].subnet_id)
|
||||
|
||||
# Deleting a subnet
|
||||
mock_driver.reset_mock()
|
||||
delete_subnets = [{
|
||||
'subnet_id': subnet1,
|
||||
'network_id': network1,
|
||||
'port_id': port1}]
|
||||
mock_driver.get_subnet.side_effect = [
|
||||
data_models.Subnet(
|
||||
id=subnet2,
|
||||
network_id=network1)]
|
||||
mock_driver.unplug_fixed_ip.return_value = data_models.Port(
|
||||
id=port1,
|
||||
network_id=network1,
|
||||
fixed_ips=[
|
||||
data_models.FixedIP(subnet_id=subnet2)])
|
||||
|
||||
delta = data_models.Delta(amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=_interface(1),
|
||||
delete_nics=[])
|
||||
add_nics=[],
|
||||
delete_nics=[],
|
||||
add_subnets=[],
|
||||
delete_subnets=delete_subnets)
|
||||
updated_ports = net.execute({self.amphora_mock.id: delta},
|
||||
self.load_balancer_mock)
|
||||
mock_driver.delete_port.assert_not_called()
|
||||
mock_driver.plug_network.assert_not_called()
|
||||
mock_driver.plug_fixed_ip.assert_not_called()
|
||||
self.assertEqual(1, len(updated_ports))
|
||||
self.assertEqual(1, len(updated_ports[self.amphora_mock.id]))
|
||||
|
||||
updated_port = updated_ports[self.amphora_mock.id][0]
|
||||
self.assertEqual(port1, updated_port.id)
|
||||
self.assertEqual(network1, updated_port.network_id)
|
||||
self.assertEqual(1, len(updated_port.fixed_ips))
|
||||
self.assertEqual(subnet2, updated_port.fixed_ips[0].subnet_id)
|
||||
|
||||
# Deleting a subnet, but neutron doesn't unplug it
|
||||
# Delta are empty because there's nothing to update
|
||||
mock_driver.reset_mock()
|
||||
mock_driver.unplug_network.side_effect = net_base.NetworkNotFound
|
||||
delete_subnets = [{
|
||||
'subnet_id': subnet1,
|
||||
'network_id': network1,
|
||||
'port_id': port1}]
|
||||
mock_driver.get_subnet.side_effect = [
|
||||
data_models.Subnet(
|
||||
id=subnet2,
|
||||
network_id=network1),
|
||||
data_models.Subnet(
|
||||
id=subnet2,
|
||||
network_id=network1)]
|
||||
mock_driver.unplug_fixed_ip.return_value = data_models.Port(
|
||||
id=port1,
|
||||
network_id=network1,
|
||||
fixed_ips=[
|
||||
data_models.FixedIP(subnet_id=subnet1),
|
||||
data_models.FixedIP(subnet_id=subnet2)])
|
||||
|
||||
delta = data_models.Delta(amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[],
|
||||
delete_nics=[],
|
||||
add_subnets=[],
|
||||
delete_subnets=[])
|
||||
net.execute({self.amphora_mock.id: delta},
|
||||
self.load_balancer_mock)
|
||||
mock_driver.delete_port.assert_not_called()
|
||||
mock_driver.plug_network.assert_not_called()
|
||||
mock_driver.plug_fixed_ip.assert_not_called()
|
||||
|
||||
# Deleting a subnet and a network
|
||||
mock_driver.reset_mock()
|
||||
mock_driver.get_subnet.side_effect = [
|
||||
data_models.Subnet(
|
||||
id=subnet2,
|
||||
network_id=network1),
|
||||
data_models.Subnet(
|
||||
id=subnet1,
|
||||
network_id=network1)]
|
||||
delete_nics = [_interface(network1, port_id=port1)]
|
||||
delete_subnets = [{
|
||||
'subnet_id': subnet1,
|
||||
'network_id': network1,
|
||||
'port_id': port1}]
|
||||
|
||||
delta = data_models.Delta(amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[],
|
||||
delete_nics=delete_nics,
|
||||
add_subnets=[],
|
||||
delete_subnets=delete_subnets)
|
||||
updated_ports = net.execute({self.amphora_mock.id: delta},
|
||||
self.load_balancer_mock)
|
||||
mock_driver.delete_port.assert_called_once_with(port1)
|
||||
mock_driver.plug_network.assert_not_called()
|
||||
mock_driver.plug_fixed_ip.assert_not_called()
|
||||
self.assertEqual(1, len(updated_ports))
|
||||
self.assertEqual(0, len(updated_ports[self.amphora_mock.id]))
|
||||
|
||||
# No delta, no actions
|
||||
mock_driver.reset_mock()
|
||||
delta = data_models.Delta(amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[],
|
||||
delete_nics=[],
|
||||
add_subnets=[],
|
||||
delete_subnets=[])
|
||||
net.execute({self.amphora_mock.id: delta}, self.load_balancer_mock)
|
||||
mock_driver.plug_network.assert_not_called()
|
||||
mock_driver.plug_fixed_ip.assert_not_called()
|
||||
mock_driver.unplug_network.assert_not_called()
|
||||
|
||||
delta = data_models.Delta(amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[_interface(1, port_id=12)],
|
||||
delete_nics=[],
|
||||
add_subnets=[],
|
||||
delete_subnets=[])
|
||||
mock_driver.reset_mock()
|
||||
mock_driver.unplug_network.side_effect = TestException('test')
|
||||
self.assertRaises(TestException, net.revert, mock.ANY,
|
||||
{self.amphora_mock.id: delta})
|
||||
mock_driver.unplug_network.assert_called_once_with(COMPUTE_ID, 1)
|
||||
net.revert(None, {self.amphora_mock.id: delta},
|
||||
self.load_balancer_mock)
|
||||
mock_driver.unplug_network.assert_called_once_with(
|
||||
self.amphora_mock.compute_id, 1)
|
||||
|
||||
mock_driver.reset_mock()
|
||||
net.execute({})
|
||||
mock_driver.delete_port.side_effect = TestException('test')
|
||||
net.revert(None, {self.amphora_mock.id: delta},
|
||||
self.load_balancer_mock)
|
||||
mock_driver.unplug_network.assert_called_once_with(
|
||||
self.amphora_mock.compute_id, 1)
|
||||
mock_driver.delete_port.assert_called_once_with(12)
|
||||
|
||||
mock_driver.reset_mock()
|
||||
net.execute({}, self.load_balancer_mock)
|
||||
self.assertFalse(mock_driver.unplug_network.called)
|
||||
|
||||
delta = data_models.Delta(amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[],
|
||||
delete_nics=[])
|
||||
net.execute({self.amphora_mock.id: delta})
|
||||
delete_nics=[],
|
||||
add_subnets=[],
|
||||
delete_subnets=[])
|
||||
net.execute({self.amphora_mock.id: delta}, self.load_balancer_mock)
|
||||
self.assertFalse(mock_driver.unplug_network.called)
|
||||
|
||||
delta = data_models.Delta(amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[],
|
||||
delete_nics=_interface(1))
|
||||
net.execute({self.amphora_mock.id: delta})
|
||||
delete_nics=[_interface(1)],
|
||||
add_subnets=[],
|
||||
delete_subnets=[])
|
||||
net.execute({self.amphora_mock.id: delta}, self.load_balancer_mock)
|
||||
mock_driver.unplug_network.assert_called_once_with(COMPUTE_ID, 1)
|
||||
|
||||
mock_driver.reset_mock()
|
||||
mock_driver.unplug_network.side_effect = net_base.NetworkNotFound
|
||||
net.execute({self.amphora_mock.id: delta})
|
||||
net.execute({self.amphora_mock.id: delta}, self.load_balancer_mock)
|
||||
mock_driver.unplug_network.assert_called_once_with(COMPUTE_ID, 1)
|
||||
|
||||
# Do a test with a general exception in case behavior changes
|
||||
mock_driver.reset_mock()
|
||||
mock_driver.unplug_network.side_effect = Exception()
|
||||
net.execute({self.amphora_mock.id: delta})
|
||||
net.execute({self.amphora_mock.id: delta}, self.load_balancer_mock)
|
||||
mock_driver.unplug_network.assert_called_once_with(COMPUTE_ID, 1)
|
||||
|
||||
# Do a test with a general exception in case behavior changes
|
||||
delta = data_models.Delta(amphora_id=self.amphora_mock.id,
|
||||
compute_id=self.amphora_mock.compute_id,
|
||||
add_nics=[],
|
||||
delete_nics=[_interface(1, port_id=12)],
|
||||
add_subnets=[],
|
||||
delete_subnets=[])
|
||||
mock_driver.reset_mock()
|
||||
mock_driver.delete_port.side_effect = Exception()
|
||||
net.execute({self.amphora_mock.id: delta}, self.load_balancer_mock)
|
||||
mock_driver.unplug_network.assert_called_once_with(COMPUTE_ID, 1)
|
||||
mock_driver.delete_port.assert_called_once_with(12)
|
||||
|
||||
mock_driver.unplug_network.reset_mock()
|
||||
net.revert(
|
||||
failure.Failure.from_exception(Exception('boom')), None, None)
|
||||
mock_driver.unplug_network.assert_not_called()
|
||||
|
||||
mock_driver.unplug_network.reset_mock()
|
||||
net.revert(None, None, None)
|
||||
mock_driver.unplug_network.assert_not_called()
|
||||
|
||||
def test_plug_vip(self, mock_get_net_driver):
|
||||
mock_driver = mock.MagicMock()
|
||||
mock_get_net_driver.return_value = mock_driver
|
||||
|
|
|
@ -731,6 +731,7 @@ class TestControllerWorker(base.TestCase):
|
|||
store={constants.MEMBER: _member_mock,
|
||||
constants.LISTENERS: [_listener_mock],
|
||||
constants.LOADBALANCER: _load_balancer_mock,
|
||||
constants.LOADBALANCER_ID: _load_balancer_mock.id,
|
||||
constants.POOL: _pool_mock,
|
||||
constants.AVAILABILITY_ZONE: {}}))
|
||||
|
||||
|
@ -769,6 +770,8 @@ class TestControllerWorker(base.TestCase):
|
|||
[_listener_mock],
|
||||
constants.LOADBALANCER:
|
||||
_load_balancer_mock,
|
||||
constants.LOADBALANCER_ID:
|
||||
_load_balancer_mock.id,
|
||||
constants.POOL:
|
||||
_pool_mock,
|
||||
constants.AVAILABILITY_ZONE: {}}))
|
||||
|
|
|
@ -281,7 +281,7 @@ class TestAmphoraFlows(base.TestCase):
|
|||
self.assertIn(constants.LOADBALANCER_ID, amp_flow.requires)
|
||||
self.assertIn(constants.VIP, amp_flow.requires)
|
||||
|
||||
self.assertIn(constants.ADDED_PORTS, amp_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, amp_flow.provides)
|
||||
self.assertIn(constants.AMP_VRRP_INT, amp_flow.provides)
|
||||
self.assertIn(constants.AMPHORA, amp_flow.provides)
|
||||
self.assertIn(constants.AMPHORA_ID, amp_flow.provides)
|
||||
|
@ -316,7 +316,7 @@ class TestAmphoraFlows(base.TestCase):
|
|||
self.assertIn(constants.LOADBALANCER_ID, amp_flow.requires)
|
||||
self.assertIn(constants.VIP, amp_flow.requires)
|
||||
|
||||
self.assertIn(constants.ADDED_PORTS, amp_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, amp_flow.provides)
|
||||
self.assertIn(constants.AMPHORA, amp_flow.provides)
|
||||
self.assertIn(constants.AMPHORA_ID, amp_flow.provides)
|
||||
self.assertIn(constants.AMPHORAE, amp_flow.provides)
|
||||
|
|
|
@ -210,8 +210,14 @@ class TestLoadBalancerFlows(base.TestCase):
|
|||
self.assertIsInstance(create_flow, flow.Flow)
|
||||
self.assertIn(constants.LOADBALANCER_ID, create_flow.requires)
|
||||
self.assertIn(constants.UPDATE_DICT, create_flow.requires)
|
||||
self.assertIn(constants.BUILD_TYPE_PRIORITY, create_flow.requires)
|
||||
self.assertIn(constants.FLAVOR, create_flow.requires)
|
||||
self.assertIn(constants.AMPHORAE_NETWORK_CONFIG, create_flow.requires)
|
||||
self.assertIn(constants.AVAILABILITY_ZONE, create_flow.requires)
|
||||
self.assertIn(constants.SERVER_GROUP_ID, create_flow.requires)
|
||||
|
||||
self.assertIn(constants.LISTENERS, create_flow.provides)
|
||||
self.assertIn(constants.SUBNET, create_flow.provides)
|
||||
self.assertIn(constants.AMPHORA, create_flow.provides)
|
||||
self.assertIn(constants.AMPHORA_ID, create_flow.provides)
|
||||
self.assertIn(constants.AMPHORA_NETWORK_CONFIG, create_flow.provides)
|
||||
|
@ -220,12 +226,11 @@ class TestLoadBalancerFlows(base.TestCase):
|
|||
self.assertIn(constants.COMPUTE_OBJ, create_flow.provides)
|
||||
self.assertIn(constants.LOADBALANCER, create_flow.provides)
|
||||
self.assertIn(constants.DELTAS, create_flow.provides)
|
||||
self.assertIn(constants.ADDED_PORTS, create_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, create_flow.provides)
|
||||
self.assertIn(constants.SERVER_PEM, create_flow.provides)
|
||||
self.assertIn(constants.SUBNET, create_flow.provides)
|
||||
self.assertIn(constants.VIP, create_flow.provides)
|
||||
|
||||
self.assertEqual(6, len(create_flow.requires))
|
||||
self.assertEqual(7, len(create_flow.requires))
|
||||
self.assertEqual(13, len(create_flow.provides),
|
||||
create_flow.provides)
|
||||
|
||||
|
@ -244,7 +249,7 @@ class TestLoadBalancerFlows(base.TestCase):
|
|||
self.assertIn(constants.SERVER_GROUP_ID, create_flow.requires)
|
||||
self.assertIn(constants.UPDATE_DICT, create_flow.requires)
|
||||
|
||||
self.assertIn(constants.ADDED_PORTS, create_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, create_flow.provides)
|
||||
self.assertIn(constants.AMP_DATA, create_flow.provides)
|
||||
self.assertIn(constants.AMP_VRRP_INT, create_flow.provides)
|
||||
self.assertIn(constants.AMPHORA, create_flow.provides)
|
||||
|
@ -280,7 +285,7 @@ class TestLoadBalancerFlows(base.TestCase):
|
|||
self.assertIn(constants.LOADBALANCER, failover_flow.requires)
|
||||
self.assertIn(constants.LOADBALANCER_ID, failover_flow.requires)
|
||||
|
||||
self.assertIn(constants.ADDED_PORTS, failover_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, failover_flow.provides)
|
||||
self.assertIn(constants.AMPHORA, failover_flow.provides)
|
||||
self.assertIn(constants.AMPHORA_ID, failover_flow.provides)
|
||||
self.assertIn(constants.AMPHORAE_NETWORK_CONFIG,
|
||||
|
@ -343,7 +348,7 @@ class TestLoadBalancerFlows(base.TestCase):
|
|||
self.assertIn(constants.LOADBALANCER, failover_flow.requires)
|
||||
self.assertIn(constants.LOADBALANCER_ID, failover_flow.requires)
|
||||
|
||||
self.assertIn(constants.ADDED_PORTS, failover_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, failover_flow.provides)
|
||||
self.assertIn(constants.AMPHORA, failover_flow.provides)
|
||||
self.assertIn(constants.AMPHORA_ID, failover_flow.provides)
|
||||
self.assertIn(constants.AMPHORAE_NETWORK_CONFIG,
|
||||
|
|
|
@ -37,18 +37,19 @@ class TestMemberFlows(base.TestCase):
|
|||
|
||||
self.assertIsInstance(member_flow, flow.Flow)
|
||||
|
||||
self.assertIn(constants.MEMBER, member_flow.requires)
|
||||
self.assertIn(constants.LISTENERS, member_flow.requires)
|
||||
self.assertIn(constants.LOADBALANCER, member_flow.requires)
|
||||
self.assertIn(constants.LOADBALANCER_ID, member_flow.requires)
|
||||
self.assertIn(constants.POOL_ID, member_flow.requires)
|
||||
self.assertIn(constants.MEMBER, member_flow.requires)
|
||||
self.assertIn(constants.AVAILABILITY_ZONE, member_flow.requires)
|
||||
|
||||
self.assertIn(constants.DELTAS, member_flow.provides)
|
||||
self.assertIn(constants.ADDED_PORTS, member_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, member_flow.provides)
|
||||
self.assertIn(constants.AMPHORAE_NETWORK_CONFIG, member_flow.provides)
|
||||
|
||||
self.assertEqual(6, len(member_flow.requires))
|
||||
self.assertEqual(2, len(member_flow.provides))
|
||||
self.assertEqual(3, len(member_flow.provides))
|
||||
|
||||
def test_get_delete_member_flow(self, mock_get_net_driver):
|
||||
|
||||
|
@ -62,9 +63,14 @@ class TestMemberFlows(base.TestCase):
|
|||
self.assertIn(constants.LOADBALANCER_ID, member_flow.requires)
|
||||
self.assertIn(constants.POOL_ID, member_flow.requires)
|
||||
self.assertIn(constants.PROJECT_ID, member_flow.requires)
|
||||
self.assertIn(constants.AVAILABILITY_ZONE, member_flow.requires)
|
||||
|
||||
self.assertEqual(6, len(member_flow.requires))
|
||||
self.assertEqual(0, len(member_flow.provides))
|
||||
self.assertIn(constants.DELTAS, member_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, member_flow.provides)
|
||||
self.assertIn(constants.AMPHORAE_NETWORK_CONFIG, member_flow.provides)
|
||||
|
||||
self.assertEqual(7, len(member_flow.requires))
|
||||
self.assertEqual(3, len(member_flow.provides))
|
||||
|
||||
def test_get_update_member_flow(self, mock_get_net_driver):
|
||||
|
||||
|
@ -96,7 +102,8 @@ class TestMemberFlows(base.TestCase):
|
|||
self.assertIn(constants.AVAILABILITY_ZONE, member_flow.requires)
|
||||
|
||||
self.assertIn(constants.DELTAS, member_flow.provides)
|
||||
self.assertIn(constants.ADDED_PORTS, member_flow.provides)
|
||||
self.assertIn(constants.UPDATED_PORTS, member_flow.provides)
|
||||
self.assertIn(constants.AMPHORAE_NETWORK_CONFIG, member_flow.provides)
|
||||
|
||||
self.assertEqual(5, len(member_flow.requires))
|
||||
self.assertEqual(2, len(member_flow.provides))
|
||||
self.assertEqual(3, len(member_flow.provides))
|
||||
|
|
|
@ -58,6 +58,9 @@ _LB_mock = {
|
|||
constants.LOADBALANCER_ID: LB_ID,
|
||||
}
|
||||
_amphorae_mock = [_db_amphora_mock]
|
||||
_amphora_network_config_mock = mock.MagicMock()
|
||||
_amphorae_network_config_mock = {
|
||||
_amphora_mock[constants.ID]: _amphora_network_config_mock}
|
||||
_network_mock = mock.MagicMock()
|
||||
_session_mock = mock.MagicMock()
|
||||
|
||||
|
@ -68,7 +71,7 @@ _session_mock = mock.MagicMock()
|
|||
@mock.patch('octavia.db.repositories.ListenerRepository.get',
|
||||
return_value=_listener_mock)
|
||||
@mock.patch('octavia.db.api.get_session', return_value=_session_mock)
|
||||
@mock.patch('octavia.controller.worker.v2.tasks.amphora_driver_tasks.LOG')
|
||||
@mock.patch('octavia.controller.worker.v1.tasks.amphora_driver_tasks.LOG')
|
||||
@mock.patch('oslo_utils.uuidutils.generate_uuid', return_value=AMP_ID)
|
||||
@mock.patch('stevedore.driver.DriverManager.driver')
|
||||
class TestAmphoraDriverTasks(base.TestCase):
|
||||
|
@ -385,11 +388,13 @@ class TestAmphoraDriverTasks(base.TestCase):
|
|||
port_mock = {constants.NETWORK: mock.MagicMock(),
|
||||
constants.FIXED_IPS: fixed_ips,
|
||||
constants.ID: uuidutils.generate_uuid()}
|
||||
amphora_post_network_plug_obj.execute(_amphora_mock, [port_mock])
|
||||
amphora_post_network_plug_obj.execute(_amphora_mock, [port_mock],
|
||||
_amphora_network_config_mock)
|
||||
|
||||
(mock_driver.post_network_plug.
|
||||
assert_called_once_with)(_db_amphora_mock,
|
||||
network_data_models.Port(**port_mock))
|
||||
network_data_models.Port(**port_mock),
|
||||
_amphora_network_config_mock)
|
||||
|
||||
# Test revert
|
||||
amp = amphora_post_network_plug_obj.revert(None, _amphora_mock)
|
||||
|
@ -434,11 +439,13 @@ class TestAmphoraDriverTasks(base.TestCase):
|
|||
port_mock = {constants.NETWORK: mock.MagicMock(),
|
||||
constants.FIXED_IPS: fixed_ips,
|
||||
constants.ID: uuidutils.generate_uuid()}
|
||||
amphora_post_network_plug_obj.execute(_amphora_mock, [port_mock])
|
||||
amphora_post_network_plug_obj.execute(_amphora_mock, [port_mock],
|
||||
_amphora_network_config_mock)
|
||||
|
||||
(mock_driver.post_network_plug.
|
||||
assert_called_once_with)(_db_amphora_mock,
|
||||
network_data_models.Port(**port_mock))
|
||||
network_data_models.Port(**port_mock),
|
||||
_amphora_network_config_mock)
|
||||
|
||||
call_args = mock_driver.post_network_plug.call_args[0]
|
||||
port_arg = call_args[1]
|
||||
|
@ -472,18 +479,21 @@ class TestAmphoraDriverTasks(base.TestCase):
|
|||
constants.ID: uuidutils.generate_uuid()}
|
||||
_deltas_mock = {_db_amphora_mock.id: [port_mock]}
|
||||
|
||||
amphora_post_network_plug_obj.execute(_LB_mock, _deltas_mock)
|
||||
amphora_post_network_plug_obj.execute(_LB_mock, _deltas_mock,
|
||||
_amphorae_network_config_mock)
|
||||
|
||||
(mock_driver.post_network_plug.
|
||||
assert_called_once_with(_db_amphora_mock,
|
||||
network_data_models.Port(**port_mock)))
|
||||
network_data_models.Port(**port_mock),
|
||||
_amphora_network_config_mock))
|
||||
|
||||
# Test with no ports to plug
|
||||
mock_driver.post_network_plug.reset_mock()
|
||||
|
||||
_deltas_mock = {'0': [port_mock]}
|
||||
|
||||
amphora_post_network_plug_obj.execute(_LB_mock, _deltas_mock)
|
||||
amphora_post_network_plug_obj.execute(_LB_mock, _deltas_mock,
|
||||
_amphora_network_config_mock)
|
||||
mock_driver.post_network_plug.assert_not_called()
|
||||
|
||||
# Test revert
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -563,3 +563,144 @@ class TestBaseNeutronNetworkDriver(base.TestCase):
|
|||
self.assertEqual(t_constants.MOCK_NETWORK_ID, ip_avail.network_id)
|
||||
self.assertEqual(t_constants.MOCK_SUBNET_IP_AVAILABILITY,
|
||||
ip_avail.subnet_ip_availability)
|
||||
|
||||
def test_plug_fixed_ip(self):
|
||||
show_port = self.driver.neutron_client.show_port
|
||||
show_port.return_value = {
|
||||
'id': t_constants.MOCK_PORT_ID,
|
||||
'fixed_ips': [
|
||||
{
|
||||
'subnet_id': t_constants.MOCK_SUBNET_ID,
|
||||
'ip_address': t_constants.MOCK_IP_ADDRESS,
|
||||
'subnet': None
|
||||
}]
|
||||
}
|
||||
|
||||
self.driver.plug_fixed_ip(t_constants.MOCK_PORT_ID,
|
||||
t_constants.MOCK_SUBNET_ID2,
|
||||
t_constants.MOCK_IP_ADDRESS2)
|
||||
|
||||
expected_body = {
|
||||
'port': {
|
||||
'fixed_ips': [
|
||||
{
|
||||
'subnet_id': t_constants.MOCK_SUBNET_ID,
|
||||
'ip_address': t_constants.MOCK_IP_ADDRESS,
|
||||
'subnet': None
|
||||
}, {
|
||||
'subnet_id': t_constants.MOCK_SUBNET_ID2,
|
||||
'ip_address': t_constants.MOCK_IP_ADDRESS2
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
self.driver.neutron_client.update_port.assert_called_once_with(
|
||||
t_constants.MOCK_PORT_ID,
|
||||
expected_body)
|
||||
|
||||
def test_plug_fixed_ip_no_ip_address(self):
|
||||
show_port = self.driver.neutron_client.show_port
|
||||
show_port.return_value = {
|
||||
'id': t_constants.MOCK_PORT_ID,
|
||||
'fixed_ips': [
|
||||
{
|
||||
'subnet_id': t_constants.MOCK_SUBNET_ID,
|
||||
'ip_address': t_constants.MOCK_IP_ADDRESS,
|
||||
'subnet': None
|
||||
}]
|
||||
}
|
||||
|
||||
self.driver.plug_fixed_ip(t_constants.MOCK_PORT_ID,
|
||||
t_constants.MOCK_SUBNET_ID2)
|
||||
|
||||
expected_body = {
|
||||
'port': {
|
||||
'fixed_ips': [
|
||||
{
|
||||
'subnet_id': t_constants.MOCK_SUBNET_ID,
|
||||
'ip_address': t_constants.MOCK_IP_ADDRESS,
|
||||
'subnet': None
|
||||
}, {
|
||||
'subnet_id': t_constants.MOCK_SUBNET_ID2,
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
self.driver.neutron_client.update_port.assert_called_once_with(
|
||||
t_constants.MOCK_PORT_ID,
|
||||
expected_body)
|
||||
|
||||
def test_plug_fixed_ip_exception(self):
|
||||
show_port = self.driver.neutron_client.show_port
|
||||
show_port.return_value = {
|
||||
'id': t_constants.MOCK_PORT_ID,
|
||||
'fixed_ips': [
|
||||
{
|
||||
'subnet_id': t_constants.MOCK_SUBNET_ID,
|
||||
'ip_address': t_constants.MOCK_IP_ADDRESS,
|
||||
'subnet': None
|
||||
}]
|
||||
}
|
||||
|
||||
self.driver.neutron_client.update_port.side_effect = Exception
|
||||
|
||||
self.assertRaises(network_base.NetworkException,
|
||||
self.driver.plug_fixed_ip,
|
||||
t_constants.MOCK_PORT_ID,
|
||||
t_constants.MOCK_SUBNET_ID2)
|
||||
|
||||
def test_unplug_fixed_ip(self):
|
||||
show_port = self.driver.neutron_client.show_port
|
||||
show_port.return_value = {
|
||||
'id': t_constants.MOCK_PORT_ID,
|
||||
'fixed_ips': [
|
||||
{
|
||||
'subnet_id': t_constants.MOCK_SUBNET_ID,
|
||||
'ip_address': t_constants.MOCK_IP_ADDRESS,
|
||||
'subnet': None
|
||||
}, {
|
||||
'subnet_id': t_constants.MOCK_SUBNET_ID2,
|
||||
'ip_address': t_constants.MOCK_IP_ADDRESS2,
|
||||
'subnet': None
|
||||
}]
|
||||
}
|
||||
|
||||
self.driver.unplug_fixed_ip(t_constants.MOCK_PORT_ID,
|
||||
t_constants.MOCK_SUBNET_ID)
|
||||
|
||||
expected_body = {
|
||||
'port': {
|
||||
'fixed_ips': [
|
||||
{
|
||||
'subnet_id': t_constants.MOCK_SUBNET_ID2,
|
||||
'ip_address': t_constants.MOCK_IP_ADDRESS2,
|
||||
'subnet': None
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
self.driver.neutron_client.update_port.assert_called_once_with(
|
||||
t_constants.MOCK_PORT_ID,
|
||||
expected_body)
|
||||
|
||||
def test_unplug_fixed_ip_exception(self):
|
||||
show_port = self.driver.neutron_client.show_port
|
||||
show_port.return_value = {
|
||||
'id': t_constants.MOCK_PORT_ID,
|
||||
'fixed_ips': [
|
||||
{
|
||||
'subnet_id': t_constants.MOCK_SUBNET_ID,
|
||||
'ip_address': t_constants.MOCK_IP_ADDRESS,
|
||||
'subnet': None
|
||||
}]
|
||||
}
|
||||
|
||||
self.driver.neutron_client.update_port.side_effect = Exception
|
||||
|
||||
self.assertRaises(network_base.NetworkException,
|
||||
self.driver.unplug_fixed_ip,
|
||||
t_constants.MOCK_PORT_ID,
|
||||
t_constants.MOCK_SUBNET_ID)
|
||||
|
|
|
@ -28,6 +28,7 @@ class TestNoopNetworkDriver(base.TestCase):
|
|||
FAKE_UUID_4 = uuidutils.generate_uuid()
|
||||
FAKE_UUID_5 = uuidutils.generate_uuid()
|
||||
FAKE_UUID_6 = uuidutils.generate_uuid()
|
||||
FAKE_UUID_7 = uuidutils.generate_uuid()
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
@ -49,6 +50,7 @@ class TestNoopNetworkDriver(base.TestCase):
|
|||
self.vip.port_id = uuidutils.generate_uuid()
|
||||
self.amphora_id = self.FAKE_UUID_1
|
||||
self.compute_id = self.FAKE_UUID_2
|
||||
self.compute2_id = self.FAKE_UUID_2
|
||||
self.subnet_id = self.FAKE_UUID_3
|
||||
self.subnet_name = 'subnet1'
|
||||
self.qos_policy_id = self.FAKE_UUID_5
|
||||
|
@ -56,12 +58,14 @@ class TestNoopNetworkDriver(base.TestCase):
|
|||
|
||||
self.amphora1 = models.Amphora()
|
||||
self.amphora1.id = uuidutils.generate_uuid()
|
||||
self.amphora1.compute_id = self.compute_id
|
||||
self.amphora1.vrrp_port_id = uuidutils.generate_uuid()
|
||||
self.amphora1.ha_port_id = uuidutils.generate_uuid()
|
||||
self.amphora1.vrrp_ip = '10.0.1.10'
|
||||
self.amphora1.ha_ip = '10.0.1.11'
|
||||
self.amphora2 = models.Amphora()
|
||||
self.amphora2.id = uuidutils.generate_uuid()
|
||||
self.amphora2.compute_id = self.compute2_id
|
||||
self.amphora2.vrrp_port_id = uuidutils.generate_uuid()
|
||||
self.amphora2.ha_port_id = uuidutils.generate_uuid()
|
||||
self.amphora2.vrrp_ip = '10.0.2.10'
|
||||
|
@ -69,6 +73,7 @@ class TestNoopNetworkDriver(base.TestCase):
|
|||
self.load_balancer.amphorae = [self.amphora1, self.amphora2]
|
||||
self.load_balancer.vip = self.vip
|
||||
self.subnet = mock.MagicMock()
|
||||
self.subnet.id = self.subnet_id
|
||||
|
||||
def test_allocate_vip(self):
|
||||
self.driver.allocate_vip(self.load_balancer)
|
||||
|
@ -105,28 +110,54 @@ class TestNoopNetworkDriver(base.TestCase):
|
|||
self.load_balancer.id, self.vip.ip_address)])
|
||||
|
||||
def test_plug_network(self):
|
||||
self.driver.plug_network(self.amphora_id, self.network_id,
|
||||
self.ip_address)
|
||||
self.assertEqual((self.amphora_id, self.network_id, self.ip_address,
|
||||
self.driver.plug_network(self.compute_id, self.network_id,
|
||||
self.subnet_id)
|
||||
self.assertEqual((self.compute_id, self.network_id, self.subnet_id,
|
||||
'plug_network'),
|
||||
self.driver.driver.networkconfigconfig[(
|
||||
self.amphora_id, self.network_id,
|
||||
self.ip_address)])
|
||||
self.compute_id, self.network_id)])
|
||||
|
||||
def test_unplug_network(self):
|
||||
self.driver.unplug_network(self.amphora_id, self.network_id,
|
||||
ip_address=self.ip_address)
|
||||
self.assertEqual((self.amphora_id, self.network_id, self.ip_address,
|
||||
'unplug_network'),
|
||||
self.driver.unplug_network(self.compute_id, self.network_id)
|
||||
self.assertEqual((self.compute_id, self.network_id, 'unplug_network'),
|
||||
self.driver.driver.networkconfigconfig[(
|
||||
self.amphora_id, self.network_id,
|
||||
self.ip_address)])
|
||||
self.compute_id, self.network_id)])
|
||||
|
||||
def test_get_plugged_networks(self):
|
||||
self.driver.get_plugged_networks(self.amphora_id)
|
||||
self.assertEqual((self.amphora_id, 'get_plugged_networks'),
|
||||
self.driver.get_plugged_networks(self.compute_id)
|
||||
self.assertEqual((self.compute_id, 'get_plugged_networks'),
|
||||
self.driver.driver.networkconfigconfig[(
|
||||
self.amphora_id)])
|
||||
self.compute_id)])
|
||||
|
||||
def test_plug_unplug_and_get_plugged_networks(self):
|
||||
amphora = mock.MagicMock()
|
||||
amphora.compute_id = uuidutils.generate_uuid()
|
||||
network = self.driver.plug_network(amphora.compute_id,
|
||||
self.network_id,
|
||||
self.subnet_id)
|
||||
self.assertEqual(
|
||||
network,
|
||||
network_models.Interface(
|
||||
id=mock.ANY,
|
||||
compute_id=amphora.compute_id,
|
||||
network_id=self.network_id,
|
||||
fixed_ips=[],
|
||||
port_id=mock.ANY
|
||||
))
|
||||
networks = self.driver.get_plugged_networks(amphora.compute_id)
|
||||
self.assertEqual(
|
||||
networks,
|
||||
[network_models.Interface(
|
||||
id=mock.ANY,
|
||||
compute_id=amphora.compute_id,
|
||||
network_id=self.network_id,
|
||||
fixed_ips=[],
|
||||
port_id=mock.ANY
|
||||
)])
|
||||
self.driver.unplug_network(amphora.compute_id,
|
||||
self.network_id)
|
||||
networks = self.driver.get_plugged_networks(amphora.compute_id)
|
||||
self.assertEqual([], networks)
|
||||
|
||||
def test_update_vip(self):
|
||||
self.driver.update_vip(self.load_balancer)
|
||||
|
@ -293,3 +324,12 @@ class TestNoopNetworkDriver(base.TestCase):
|
|||
self.assertEqual(SUBNET_ID, result.fixed_ips[1].subnet_id)
|
||||
self.assertEqual(QOS_POLICY_ID, result.qos_policy_id)
|
||||
self.assertFalse(result.admin_state_up)
|
||||
|
||||
def test_plug_fixed_ip(self):
|
||||
self.driver.plug_fixed_ip(self.port_id, self.subnet_id,
|
||||
self.ip_address)
|
||||
self.assertEqual(
|
||||
(self.port_id, self.subnet_id, self.ip_address, 'plug_fixed_ip'),
|
||||
self.driver.driver.networkconfigconfig[
|
||||
self.port_id, self.subnet_id]
|
||||
)
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
fixes:
|
||||
- |
|
||||
Fix a bug when adding a member on a subnet that belongs to a network with
|
||||
multiple subnets, an incorrect subnet may have been plugged in the amphora.
|
||||
- |
|
||||
Fix a bug when deleting the last member plugged on a network, the port that
|
||||
was no longer used was not deleted.
|
Loading…
Reference in New Issue