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:
parent
520fc64cd6
commit
90769f6e02
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue