Swap floating IPs between servers dynamic workload

This patch introduces the following changes.
1. ping_subport_fip_from_jumphost has been changed to ping_fip_from_jumphost,
and moved to dynamic_utils.py, so it can be used in VM dynamic scenarios as
well.
2. Swap floating IPs between servers dynamic workload has been introduced in
vm.py.
3. Docstrings have been added for all functions in dynamic_utils.py, and security
group functions have been moved from NovaUtils to NeutronUtils, as they are more
appropriate there.

Change-Id: I9cd5afa3b2238c95d4f758abd95168f3942d3621
This commit is contained in:
Sanjay Chari 2021-08-25 13:45:46 +05:30
parent 520fc64cd6
commit 90769f6e02
6 changed files with 163 additions and 58 deletions

View File

@ -585,8 +585,8 @@ workloads:
# workloads can be 'all', a single workload(Eg. : create_delete_servers),
# or a comma separated string(Eg. : create_delete_servers,migrate_servers).
# Currently supported workloads : create_delete_servers, migrate_servers
# create_loadbalancers, delete_loadbalancers, delete_members_random_lb,
# pod_fip_simulation, add_subports_to_random_trunks,
# swap_floating_ips_between_servers, create_loadbalancers, delete_loadbalancers,
# delete_members_random_lb, pod_fip_simulation, add_subports_to_random_trunks,
# 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,

View File

@ -9,6 +9,7 @@ Functions:
- _create_router: Create neutron router.
- get_servers_migration_list: Generate list of servers to migrate between computes.
- migrate_servers_with_fip: Migrate servers between computes
- swap_floating_ips_between_servers: Swap floating IPs between 2 servers
- create_loadbalancers: Create 'N' loadbalancers
- delete_loadbalancers: Deletes 'M' loadbalancers randomly from 'N' loadbalancers
- create_clients: Create 'N' clients
@ -20,10 +21,11 @@ Functions:
- 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
- _wait_for_ping_failure: Wait for ping failure to floating IP of server
- 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
- ping_subport_fip_from_jumphost: Ping subport floating ip from jumphost
- assign_ping_fip_from_jumphost: Assign floating IP to port(optional), and ping floating ip from jumphost
- create_subnets_and_subports: Create N subnets and subports
- add_subports_to_trunk_and_vm: Add subports to trunk and create vlan interfaces for subport inside trunk VM
- simulate_subport_connection: Simulate connection from jumphost to random subport of trunk VM

View File

@ -14,6 +14,8 @@ import logging
import time
from rally.common import cfg
from rally.common import sshutils
from rally_openstack.scenarios.vm import utils as vm_utils
from rally_openstack.scenarios.neutron import utils as neutron_utils
from rally.task import atomic
@ -30,10 +32,16 @@ logging.getLogger("paramiko").setLevel(logging.WARNING)
class NovaUtils(vm_utils.VMScenario):
def log_info(self, msg):
"""Log information with iteration number
:param msg: str, message to log
"""
log_msg = " DYNAMIC_WORKLOADS ITER: {} {} ".format(self.context["iteration"], msg)
LOG.info(log_msg)
def log_error(self, msg):
"""Log error with iteration number
:param msg: str, message to log
"""
log_msg = " DYNAMIC_WORKLOADS ITER: {} {} ".format(self.context["iteration"], msg)
LOG.error(log_msg)
@ -76,26 +84,44 @@ class NovaUtils(vm_utils.VMScenario):
else:
break
def _create_sec_group_rule(self, security_group, protocol):
security_group_rule_args = {}
security_group_rule_args["security_group_id"] = security_group["security_group"]["id"]
security_group_rule_args["direction"] = "ingress"
security_group_rule_args["remote_ip_prefix"] = "0.0.0.0/0"
security_group_rule_args["protocol"] = protocol
if protocol == "tcp":
security_group_rule_args["port_range_min"] = 22
security_group_rule_args["port_range_max"] = 22
self.clients("neutron").create_security_group_rule(
{"security_group_rule": security_group_rule_args})
def assign_ping_fip_from_jumphost(self, jumphost_fip, jumphost_user,
fip, port_id, success_on_ping_failure=False):
"""Ping floating ip from jumphost
:param jumphost_fip: floating ip of jumphost
:param jumphost_user: str, ssh user for jumphost
:param fip: floating ip of port
:param port_id: id of port to ping from jumphost
:param success_on_ping_failure: bool, flag to ping till failure/success
"""
keypair = self.context["user"]["keypair"]
if not(success_on_ping_failure):
fip_update_dict = {"port_id": port_id}
self.clients("neutron").update_floatingip(
fip["id"], {"floatingip": fip_update_dict}
)
def create_sec_group_with_icmp_ssh(self):
security_group_args = {}
security_group_args["name"] = self.generate_random_name()
security_group = self.clients("neutron").create_security_group(
{"security_group": security_group_args})
self._create_sec_group_rule(security_group, "icmp")
self._create_sec_group_rule(security_group, "tcp")
return security_group["security_group"]
address = fip["floating_ip_address"]
jumphost_ssh = sshutils.SSH(jumphost_user, jumphost_fip, pkey=keypair["private"])
self._wait_for_ssh(jumphost_ssh)
cmd = f"ping -c1 -w1 {address}"
if success_on_ping_failure:
self._run_command_until_failure(jumphost_ssh, cmd)
else:
self._run_command_with_attempts(jumphost_ssh, cmd)
@atomic.action_timer("vm.wait_for_ping_failure")
def _wait_for_ping_failure(self, server_ip):
"""Wait for ping failure to floating IP of server
:param server_ip: floating IP of server
"""
server = vm_utils.Host(server_ip)
utils.wait_for_status(
server,
ready_statuses=[vm_utils.Host.ICMP_DOWN_STATUS],
update_resource=vm_utils.Host.update_status,
timeout=CONF.openstack.vm_ping_timeout,
check_interval=CONF.openstack.vm_ping_poll_interval
)
def _boot_server_with_tag(self, image, flavor, tag,
auto_assign_nic=False, **kwargs):
@ -201,10 +227,16 @@ class NovaUtils(vm_utils.VMScenario):
class NeutronUtils(neutron_utils.NeutronScenario):
def log_info(self, msg):
"""Log information with iteration number
:param msg: str, message to log
"""
log_msg = " DYNAMIC_WORKLOADS ITER: {} {} ".format(self.context["iteration"], msg)
LOG.info(log_msg)
def log_error(self, msg):
"""Log error with iteration number
:param msg: str, message to log
"""
log_msg = " DYNAMIC_WORKLOADS ITER: {} {} ".format(self.context["iteration"], msg)
LOG.error(log_msg)
@ -241,6 +273,34 @@ class NeutronUtils(neutron_utils.NeutronScenario):
)
return port_fip
def _create_sec_group_rule(self, security_group, protocol):
"""Create rule for security group
:param security_group: security group object to create rule
:param protocol: str, protocol of rule to create
"""
security_group_rule_args = {}
security_group_rule_args["security_group_id"] = security_group["security_group"]["id"]
security_group_rule_args["direction"] = "ingress"
security_group_rule_args["remote_ip_prefix"] = "0.0.0.0/0"
security_group_rule_args["protocol"] = protocol
if protocol == "tcp":
security_group_rule_args["port_range_min"] = 22
security_group_rule_args["port_range_max"] = 22
self.clients("neutron").create_security_group_rule(
{"security_group_rule": security_group_rule_args})
def create_sec_group_with_icmp_ssh(self):
"""Create security group with icmp and ssh rules
:returns: security group dict
"""
security_group_args = {}
security_group_args["name"] = self.generate_random_name()
security_group = self.clients("neutron").create_security_group(
{"security_group": security_group_args})
self._create_sec_group_rule(security_group, "icmp")
self._create_sec_group_rule(security_group, "tcp")
return security_group["security_group"]
class LockUtils:
def acquire_lock(self, object_id):

View File

@ -74,6 +74,9 @@ class DynamicWorkload(vm.VMDynamicScenario, trunk.TrunkDynamicScenario,
network_create_args, subnet_create_args, **kwargs)
self.migrate_servers_with_fip(num_vms_to_migrate)
if workloads == "all" or "swap_floating_ips_between_servers" in workloads_list:
self.swap_floating_ips_between_servers()
if workloads == "all" or "pod_fip_simulation" in workloads_list:
self.pod_fip_simulation(ext_net_id, trunk_image, trunk_flavor, smallest_image,
smallest_flavor, num_initial_subports, num_trunk_vms)

View File

@ -75,30 +75,6 @@ class TrunkDynamicScenario(
self._wait_for_ssh(source_ssh)
self._run_command_with_attempts(source_ssh, script)
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 dest_vm: floating ip of destination 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
"""
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}"
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
:param trunk_id: id of trunk on which subport is present
@ -120,8 +96,8 @@ class TrunkDynamicScenario(
" with fip: {}".format(subport_for_route["port"], subport_fip, trunk["trunk"],
vm_fip, jump_fip)
self.log_info(msg)
self.ping_subport_fip_from_jumphost(jump_fip, self.jumphost_user, subport_fip,
subport_for_route["port"])
self.assign_ping_fip_from_jumphost(jump_fip, self.jumphost_user, subport_fip,
subport_for_route["port"]["id"])
# We delete the route from vm to jumphost through the randomly
# chosen subport after simulate subport connection is executed,
# as additional subports can be tested for connection in the
@ -467,16 +443,16 @@ class TrunkDynamicScenario(
msg = "Ping until failure after dissociating subports' floating IPs, before swapping"
self.log_info(msg)
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)
self.assign_ping_fip_from_jumphost(jumphost1_fip, self.jumphost_user, subport1_fip,
subport1["port"]["id"], True)
self.assign_ping_fip_from_jumphost(jumphost2_fip, self.jumphost_user, subport2_fip,
subport2["port"]["id"], True)
self.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.assign_ping_fip_from_jumphost(jumphost1_fip, self.jumphost_user, subport2_fip,
subport1["port"]["id"])
self.assign_ping_fip_from_jumphost(jumphost2_fip, self.jumphost_user, subport1_fip,
subport2["port"]["id"])
self.delete_route_from_vm_to_jumphost(trunk_vm1_fip, jumphost1_fip, self.trunk_vm_user,
subport1_number_for_route,

View File

@ -81,11 +81,13 @@ class VMDynamicScenario(dynamic_utils.NovaUtils,
network = self._create_network(network_create_args or {})
subnet = self._create_subnet(network, subnet_create_args or {})
self._add_interface_router(subnet["subnet"], router["router"])
for i in range(num_vms):
keypair = self.context["user"]["keypair"]
for _ in range(num_vms):
kwargs["nics"] = [{"net-id": network["network"]["id"]}]
guest = self._boot_server_with_fip_and_tag(
image, flavor, "migrate_or_swap",
True, ext_net_name, **kwargs
True, ext_net_name, key_name=keypair["name"], **kwargs
)
self._wait_for_ping(guest[1]["ip"])
@ -133,3 +135,65 @@ class VMDynamicScenario(dynamic_utils.NovaUtils,
if num_migrated == 0:
self.log_info("""No servers which are not under lock, so
cannot migrate any servers.""")
def swap_floating_ips_between_servers(self):
"""Swap floating IPs between servers
"""
eligible_servers = self._get_servers_by_tag("migrate_or_swap")
servers_for_swapping = []
for server in eligible_servers:
if not self.acquire_lock(server.id):
continue
servers_for_swapping.append(server)
if len(servers_for_swapping) == 2:
break
if len(servers_for_swapping) < 2:
self.log_info("""Number of unlocked servers not sufficient
for swapping floating IPs between servers""")
return
kwargs = {"floating_ip_address": list(servers_for_swapping[0].addresses.values())
[0][1]['addr']}
server1_fip = self._list_floating_ips(**kwargs)["floatingips"][0]
kwargs = {"floating_ip_address": list(servers_for_swapping[1].addresses.values())
[0][1]['addr']}
server2_fip = self._list_floating_ips(**kwargs)["floatingips"][0]
server1_port = server1_fip["port_id"]
server2_port = server2_fip["port_id"]
fip_update_dict = {"port_id": None}
self.clients("neutron").update_floatingip(
server1_fip["id"], {"floatingip": fip_update_dict})
self.clients("neutron").update_floatingip(
server2_fip["id"], {"floatingip": fip_update_dict})
self.log_info("""Ping until failure after dissociating servers' floating IPs,
before swapping""")
self.log_info("Ping server 1 {} until failure".format(server1_fip["floating_ip_address"]))
self._wait_for_ping_failure(server1_fip["floating_ip_address"])
self.log_info("Ping server 2 {} until failure".format(server2_fip["floating_ip_address"]))
self._wait_for_ping_failure(server2_fip["floating_ip_address"])
# Swap floating IPs between server1 and server2
fip_update_dict = {"port_id": server2_port}
self.clients("neutron").update_floatingip(
server1_fip["id"], {"floatingip": fip_update_dict}
)
fip_update_dict = {"port_id": server1_port}
self.clients("neutron").update_floatingip(
server2_fip["id"], {"floatingip": fip_update_dict}
)
self.log_info("Ping until success by swapping servers' floating IPs")
self.log_info("Ping server 1 {} until success".format(server1_fip["floating_ip_address"]))
self._wait_for_ping(server1_fip["floating_ip_address"])
self.log_info("Ping server 2 {} until success".format(server2_fip["floating_ip_address"]))
self._wait_for_ping(server2_fip["floating_ip_address"])
# Release locks from servers
self.release_lock(servers_for_swapping[0].id)
self.release_lock(servers_for_swapping[1].id)