Swap floating IPs between 2 random trunk subports dynamic workload

This patch introduces the following changes.
1. 3 new functions have been added in dynamic_utils.py. These functions are used
in trunk dynamic scenarios.
2. Floating IPs are created and associated to subports when required, and dissociated
and deleted after the task is completed.
3. The swap floating IPs between 2 random trunk subports dynamic workload has been added
in trunk.py.

Change-Id: I47ab98a5baf02fbdd22e2b13750d322c734ee6bb
This commit is contained in:
Sanjay Chari 2021-08-18 15:07:07 +05:30
parent 76bff93a95
commit a0beb38489
5 changed files with 140 additions and 23 deletions

View File

@ -586,8 +586,8 @@ workloads:
# Currently supported workloads : create_delete_servers, migrate_servers
# create_loadbalancers, delete_loadbalancers, delete_members_random_lb,
# pod_fip_simulation, add_subports_to_random_trunks,
# delete_subports_from_random_trunks, provider_netcreate_nova_boot_ping,
# provider_net_nova_boot_ping, provider_net_nova_delete
# delete_subports_from_random_trunks, swap_floating_ips_between_random_subports,
# provider_netcreate_nova_boot_ping, provider_net_nova_boot_ping, provider_net_nova_delete
# Note: Octavia and Provider scenarios are not included in 'all' by default,
# and have to be included separately.
workloads: all

View File

@ -18,6 +18,7 @@ Functions:
- check_connection: Check the connection of LB
- build_jump_host: Builds Jump host
- _run_command_with_attempts: Run command over ssh connection with multiple attempts
- _run_command_until_failure: Run command over ssh connection until failure
- add_route_from_vm_to_jumphost: Add route from trunk vm to jumphost via trunk subport
- delete_route_from_vm_to_jumphost: Delete route from trunk vm to jumphost via trunk subport
- get_jumphost_by_trunk: Get jumphost details for a given trunk
@ -29,9 +30,12 @@ Functions:
- pod_fip_simulation: Simulate pods with floating ips using subports on trunks and VMs
- add_subports_to_random_trunks: Add 'N' subports to 'M' randomly chosen trunks
- delete_subports_from_random_trunks: Delete 'N' subports from 'M' randomly chosen trunks
- swap_floating_ips_between_random_subports: Swap floating IPs between 2 randomly chosen subports from 2 randomly chosen trunks
- _boot_server_with_tag: Boot a server with a tag
- _boot_server_with_fip_and_tag: Boot server prepared for SSH actions, with tag
- _get_servers_by_tag: Retrieve list of servers based on tag
- dissociate_and_delete_floating_ip: Dissociate and delete floating IP of port
- create_floating_ip_and_associate_to_port: Create and associate floating IP for port
- provider_netcreate_nova_boot_ping: Creates a provider Network and Boots VM and ping
- provider_net_nova_boot_ping: Boots a VM and ping on random existing provider network
- provider_net_nova_delete: Delete all VM's and provider network

View File

@ -50,6 +50,20 @@ class NovaUtils(vm_utils.VMScenario):
else:
LOG.info("Command executed successfully: %(command)s" % {"command": cmd})
def _run_command_until_failure(self, ssh_connection, cmd, timeout=2):
"""Run command over ssh connection until failure
:param ssh_connection: ssh connection to run command
:param cmd: command to run
:param timeout: int, maximum time to wait for command to complete
"""
while True:
status, out, err = ssh_connection.execute(cmd)
LOG.info("cmd: {}, status:{}".format(cmd, status))
if status == 0:
time.sleep(timeout)
else:
break
def _boot_server_with_tag(self, image, flavor, tag,
auto_assign_nic=False, **kwargs):
"""Boot a server with a tag.
@ -153,3 +167,26 @@ class NeutronUtils(neutron_utils.NeutronScenario):
return self.admin_clients("neutron").create_router(
{"router": router_create_args}
)
def dissociate_and_delete_floating_ip(self, fip_id):
"""Dissociate and delete floating IP of port
:param fip_id: id of floating IP of subport
"""
fip_update_dict = {"port_id": None}
self.clients("neutron").update_floatingip(
fip_id, {"floatingip": fip_update_dict}
)
self.clients("neutron").delete_floatingip(fip_id)
def create_floating_ip_and_associate_to_port(self, port, ext_net_name):
"""Create and associate floating IP for port
:param port: port object to create floating IP
:param ext_net_name: name of external network to create floating IP
:returns: floating IP for port
"""
port_fip = self._create_floatingip(ext_net_name)["floatingip"]
fip_update_dict = {"port_id": port["port"]["id"]}
self.clients("neutron").update_floatingip(
port_fip["id"], {"floatingip": fip_update_dict}
)
return port_fip

View File

@ -77,6 +77,9 @@ class DynamicWorkload(vm.VMDynamicScenario, trunk.TrunkDynamicScenario,
if workloads == "all" or "delete_subports_from_random_trunks" in workloads_list:
self.delete_subports_from_random_trunks(num_delete_subports_trunks, num_delete_subports)
if workloads == "all" or "swap_floating_ips_between_random_subports" in workloads_list:
self.swap_floating_ips_between_random_subports()
if "create_loadbalancers" in workloads_list:
self.create_loadbalancers(octavia_image, octavia_flavor, user, num_lbs, user_data_file,
num_pools, num_clients, ext_net_id, router_create_args,

View File

@ -15,7 +15,6 @@ import random
from rally.common import logging
from rally.common import sshutils
from rally_openstack.scenarios.neutron import utils as neutron_utils
import dynamic_utils
LOG = logging.getLogger(__name__)
@ -36,11 +35,14 @@ LOG = logging.getLogger(__name__)
# We can't use cirros image as it doesn't support vlans
# smallest flavor for centos is m1.tiny-centos (RAM 192, disk 8, vcpu 1)
#
# We also have a scenario to add subports to random trunks in this test.
# We have 3 other scenarios apart from the subport connection simulation mentioned
# above.
# 1. Add subports to random trunks
# 2. Delete subports from random trunks
# 3. Swap floating IPs between 2 random subports from 2 randomly chosen trunks
class TrunkDynamicScenario(
dynamic_utils.NovaUtils, neutron_utils.NeutronScenario
dynamic_utils.NovaUtils, dynamic_utils.NeutronUtils
):
def add_route_from_vm_to_jumphost(self, local_vm, dest_vm, local_vm_user,
subport_number, gateway):
@ -74,26 +76,29 @@ class TrunkDynamicScenario(
self._wait_for_ssh(source_ssh)
self._run_command_with_attempts(source_ssh, script)
def ping_subport_fip_from_jumphost(self, local_vm, dest_vm, local_vm_user,
dest_vm_user, fip, port):
def ping_subport_fip_from_jumphost(self, dest_vm, dest_vm_user,
fip, port, success_on_ping_failure=False):
"""Ping subport floating ip from jumphost
:param local_vm: floating ip of local VM
:param dest_vm: floating ip of destination VM
:param local_vm_user: str, ssh user for local VM
:param dest_vm_user: str, ssh user for destination VM
:param fip: floating ip of subport
:param port: subport to ping from jumphost
:param success_on_ping_failure: bool, flag to ping till failure/success
"""
fip_update_dict = {"port_id": port["id"]}
self.clients("neutron").update_floatingip(
fip["id"], {"floatingip": fip_update_dict}
)
if not(success_on_ping_failure):
fip_update_dict = {"port_id": port["id"]}
self.clients("neutron").update_floatingip(
fip["id"], {"floatingip": fip_update_dict}
)
address = fip["floating_ip_address"]
dest_ssh = sshutils.SSH(dest_vm_user, dest_vm, pkey=self.keypair["private"])
self._wait_for_ssh(dest_ssh)
cmd = f"ping -c1 -w1 {address}"
self._run_command_with_attempts(dest_ssh, cmd)
if success_on_ping_failure:
self._run_command_until_failure(dest_ssh, cmd)
else:
self._run_command_with_attempts(dest_ssh, cmd)
def simulate_subport_connection(self, trunk_id, vm_fip, jump_fip):
"""Simulate connection from jumphost to random subport of trunk VM
@ -112,8 +117,7 @@ class TrunkDynamicScenario(
subport_number_for_route,
subnet_for_route["subnet"]["gateway_ip"])
subport_fip = self._create_floatingip(self.ext_net_name)["floatingip"]
self.ping_subport_fip_from_jumphost(vm_fip, jump_fip, self.trunk_vm_user,
self.jumphost_user, subport_fip,
self.ping_subport_fip_from_jumphost(jump_fip, self.jumphost_user, subport_fip,
subport_for_route["port"])
# We delete the route from vm to jumphost through the randomly
# chosen subport after simulate subport connection is executed,
@ -123,12 +127,9 @@ class TrunkDynamicScenario(
self.delete_route_from_vm_to_jumphost(vm_fip, jump_fip, self.trunk_vm_user,
subport_number_for_route,
subnet_for_route["subnet"]["gateway_ip"])
# Dissociate floating IP as the same subport can be used again
# later.
fip_update_dict = {"port_id": None}
self.clients("neutron").update_floatingip(
subport_fip["id"], {"floatingip": fip_update_dict}
)
# Dissociate and delete floating IP as the same subport can be used
# again later.
self.dissociate_and_delete_floating_ip(subport_fip["id"])
def get_server_by_trunk(self, trunk):
"""Get server details for a given trunk
@ -360,3 +361,75 @@ class TrunkDynamicScenario(
# was valid at the beginning of the loop.
if len(self.clients("neutron").show_trunk(trunk["id"])["trunk"]["sub_ports"]) > 0:
self.simulate_subport_connection(trunk["id"], trunk_server_fip, jump_fip)
def swap_floating_ips_between_random_subports(self):
"""Swap floating IPs between 2 randomly chosen subports from 2 randomly chosen trunks
"""
trunks = [trunk for trunk in self._list_trunks() if len(trunk["sub_ports"]) > 0]
if len(trunks) < 2:
LOG.info("""Number of eligible trunks not sufficient
for swapping floating IPs between trunk subports""")
return
trunks_for_swapping = random.sample(trunks, 2)
jumphost1_fip = self.get_jumphost_by_trunk(trunks_for_swapping[0])
jumphost2_fip = self.get_jumphost_by_trunk(trunks_for_swapping[1])
trunk_vm1_fip = self.get_server_by_trunk(trunks_for_swapping[0])
trunk_vm2_fip = self.get_server_by_trunk(trunks_for_swapping[1])
subport1_count = len(trunks_for_swapping[0]["sub_ports"])
subport1_number_for_route = random.randint(1, subport1_count)
subport1 = self.clients("neutron").show_port(
trunks_for_swapping[0]["sub_ports"][subport1_number_for_route-1]["port_id"])
subnet1 = self.clients("neutron").show_subnet(
subport1["port"]["fixed_ips"][0]["subnet_id"])
self.add_route_from_vm_to_jumphost(trunk_vm1_fip, jumphost1_fip, self.trunk_vm_user,
subport1_number_for_route,
subnet1["subnet"]["gateway_ip"])
subport2_count = len(trunks_for_swapping[1]["sub_ports"])
subport2_number_for_route = random.randint(1, subport2_count)
subport2 = self.clients("neutron").show_port(
trunks_for_swapping[1]["sub_ports"][subport2_number_for_route-1]["port_id"])
subnet2 = self.clients("neutron").show_subnet(
subport2["port"]["fixed_ips"][0]["subnet_id"])
self.add_route_from_vm_to_jumphost(trunk_vm2_fip, jumphost2_fip, self.trunk_vm_user,
subport2_number_for_route,
subnet2["subnet"]["gateway_ip"])
subport1_fip = self.create_floating_ip_and_associate_to_port(subport1, self.ext_net_name)
subport2_fip = self.create_floating_ip_and_associate_to_port(subport2, self.ext_net_name)
fip_update_dict = {"port_id": None}
self.clients("neutron").update_floatingip(
subport1_fip["id"], {"floatingip": fip_update_dict})
self.clients("neutron").update_floatingip(
subport2_fip["id"], {"floatingip": fip_update_dict})
LOG.info("Ping until failure after dissociating subports' floating IPs, before swapping")
self.ping_subport_fip_from_jumphost(jumphost1_fip, self.jumphost_user, subport1_fip,
subport1["port"], True)
self.ping_subport_fip_from_jumphost(jumphost2_fip, self.jumphost_user, subport2_fip,
subport2["port"], True)
LOG.info("Ping until success by swapping subports' floating IPs")
self.ping_subport_fip_from_jumphost(jumphost1_fip, self.jumphost_user, subport2_fip,
subport1["port"])
self.ping_subport_fip_from_jumphost(jumphost2_fip, self.jumphost_user, subport1_fip,
subport2["port"])
self.delete_route_from_vm_to_jumphost(trunk_vm1_fip, jumphost1_fip, self.trunk_vm_user,
subport1_number_for_route,
subnet1["subnet"]["gateway_ip"])
self.delete_route_from_vm_to_jumphost(trunk_vm2_fip, jumphost2_fip, self.trunk_vm_user,
subport2_number_for_route,
subnet2["subnet"]["gateway_ip"])
# Dissociate and delete floating IPs as the same subports can be used
# again later.
self.dissociate_and_delete_floating_ip(subport1_fip["id"])
self.dissociate_and_delete_floating_ip(subport2_fip["id"])