diff --git a/browbeat-config.yaml b/browbeat-config.yaml index 3dbc2ccdb..4a3134c5b 100644 --- a/browbeat-config.yaml +++ b/browbeat-config.yaml @@ -575,11 +575,13 @@ workloads: num_trunk_vms: 1 num_add_subports_trunks: 1 num_add_subports: 1 + num_delete_subports_trunks: 1 + num_delete_subports: 1 # 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, pod_fip_simulation, add_subports_to_random_trunks - # delete_loadbalancers,delete_members_random_lb + # create_loadbalancers, pod_fip_simulation, add_subports_to_random_trunks, + # delete_subports_from_random_trunks, delete_loadbalancers, delete_members_random_lb # Note: Octavia scenarios are not included in 'all' by default, and have # to be included separately. workloads: all diff --git a/rally/rally-plugins/dynamic-workloads/README.rst b/rally/rally-plugins/dynamic-workloads/README.rst index 67eb1fb38..ddf940d33 100644 --- a/rally/rally-plugins/dynamic-workloads/README.rst +++ b/rally/rally-plugins/dynamic-workloads/README.rst @@ -28,6 +28,7 @@ Functions: - get_server_by_trunk: Get server details for a given trunk - 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 - _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 diff --git a/rally/rally-plugins/dynamic-workloads/dynamic_workload.py b/rally/rally-plugins/dynamic-workloads/dynamic_workload.py index 7ef3adfe2..c349c5f3b 100644 --- a/rally/rally-plugins/dynamic-workloads/dynamic_workload.py +++ b/rally/rally-plugins/dynamic-workloads/dynamic_workload.py @@ -47,9 +47,9 @@ class DynamicWorkload(vm.VMDynamicScenario, trunk.TrunkDynamicScenario, def run( self, smallest_image, smallest_flavor, ext_net_id, num_vms_to_create_for_migration, num_vms_to_migrate, trunk_image, trunk_flavor, num_initial_subports, num_trunk_vms, - num_add_subports, num_add_subports_trunks, octavia_image, octavia_flavor, user, - user_data_file, num_lbs, num_pools, num_clients,delete_num_lbs, - delete_num_members, num_create_delete_vms, workloads="all", + num_add_subports, num_add_subports_trunks, num_delete_subports, num_delete_subports_trunks, + octavia_image, octavia_flavor, user, user_data_file, num_lbs, num_pools, + num_clients, delete_num_lbs, delete_num_members, num_create_delete_vms, workloads="all", router_create_args=None, network_create_args=None, subnet_create_args=None, **kwargs): @@ -72,6 +72,9 @@ class DynamicWorkload(vm.VMDynamicScenario, trunk.TrunkDynamicScenario, if workloads == "all" or "add_subports_to_random_trunks" in workloads_list: self.add_subports_to_random_trunks(num_add_subports_trunks, num_add_subports) + 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 "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, diff --git a/rally/rally-plugins/dynamic-workloads/dynamic_workload.yml b/rally/rally-plugins/dynamic-workloads/dynamic_workload.yml index 9c264e865..4ef2ca6b8 100644 --- a/rally/rally-plugins/dynamic-workloads/dynamic_workload.yml +++ b/rally/rally-plugins/dynamic-workloads/dynamic_workload.yml @@ -19,6 +19,8 @@ {% set num_trunk_vms = num_trunk_vms or 1 %} {% set num_add_subports_trunks = num_add_subports_trunks or 1 %} {% set num_add_subports = num_add_subports or 1 %} +{% set num_delete_subports_trunks = num_delete_subports_trunks or 1 %} +{% set num_delete_subports = num_delete_subports or 1 %} {% set sla_max_avg_duration = sla_max_avg_duration or 60 %} {% set sla_max_failure = sla_max_failure or 0 %} {% set sla_max_seconds = sla_max_seconds or 60 %} @@ -50,6 +52,8 @@ BrowbeatPlugin.dynamic_workload: num_trunk_vms: {{num_trunk_vms}} num_add_subports_trunks: {{num_add_subports_trunks}} num_add_subports: {{num_add_subports}} + num_delete_subports_trunks: {{num_delete_subports_trunks}} + num_delete_subports: {{num_delete_subports}} network_create_args: {} router_create_args: {} subnet_create_args: {} diff --git a/rally/rally-plugins/dynamic-workloads/trunk.py b/rally/rally-plugins/dynamic-workloads/trunk.py index ca62e5e31..0e3e23f33 100644 --- a/rally/rally-plugins/dynamic-workloads/trunk.py +++ b/rally/rally-plugins/dynamic-workloads/trunk.py @@ -108,19 +108,19 @@ class TrunkDynamicScenario( trunk["trunk"]["sub_ports"][subport_number_for_route-1]["port_id"]) subnet_for_route = self.clients("neutron").show_subnet( subport_for_route["port"]["fixed_ips"][0]["subnet_id"]) - self.add_route_from_vm_to_jumphost(vm_fip, jump_fip, "centos", + self.add_route_from_vm_to_jumphost(vm_fip, jump_fip, self.trunk_vm_user, 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, "centos", "cirros", - subport_fip, + self.ping_subport_fip_from_jumphost(vm_fip, jump_fip, self.trunk_vm_user, + 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, # as additional subports can be tested for connection in the # add_subports_random_trunks function, and we would not want the # existing route created here to be used for those subports. - self.delete_route_from_vm_to_jumphost(vm_fip, jump_fip, "centos", + 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 @@ -144,7 +144,8 @@ class TrunkDynamicScenario( :param trunk: dict, trunk details :returns: floating ip of jumphost """ - jumphost_fip = trunk["description"][9:] + if trunk["description"].startswith("jumphost:"): + jumphost_fip = trunk["description"][9:] return jumphost_fip def create_subnets_and_subports(self, subport_count): @@ -178,18 +179,19 @@ class TrunkDynamicScenario( """ # Inside VM, subports are simulated (implemented) using vlan interfaces # Later we ping these vlan interfaces - for seg_id, p in enumerate(subports, start=start_seg_id): + for seg_id, subport in enumerate(subports, + start=start_seg_id): subport_payload = [ { - "port_id": p["port"]["id"], + "port_id": subport["port"]["id"], "segmentation_type": "vlan", "segmentation_id": seg_id, } ] self._add_subports_to_trunk(trunk_id, subport_payload) - mac = p["port"]["mac_address"] - address = p["port"]["fixed_ips"][0]["ip_address"] + mac = subport["port"]["mac_address"] + address = subport["port"]["fixed_ips"][0]["ip_address"] # Note: Manually assign ip as calling dnsmasq will also add # default route which will break floating ip for the VM cmd = f"sudo ip link add link eth0 name eth0.{seg_id} type vlan id {seg_id}" @@ -218,6 +220,9 @@ class TrunkDynamicScenario( "name" ] + self.trunk_vm_user = "centos" + self.jumphost_user = "cirros" + router_create_args = {} router_create_args["name"] = self.generate_random_name() router_create_args["tenant_id"] = self.context["tenant"]["id"] @@ -262,7 +267,8 @@ class TrunkDynamicScenario( subnets, subports = self.create_subnets_and_subports(subport_count) - vm_ssh = sshutils.SSH("centos", vm_fip, pkey=self.keypair["private"]) + vm_ssh = sshutils.SSH(self.trunk_vm_user, + vm_fip, pkey=self.keypair["private"]) self._wait_for_ssh(vm_ssh) self.add_subports_to_trunk_and_vm(subports, trunk["trunk"]["id"], vm_ssh, 1) @@ -287,7 +293,7 @@ class TrunkDynamicScenario( jump_fip = self.get_jumphost_by_trunk(trunk) vm_ssh = sshutils.SSH( - "centos", trunk_server_fip, pkey=self.keypair["private"] + self.trunk_vm_user, trunk_server_fip, pkey=self.keypair["private"] ) self._wait_for_ssh(vm_ssh) @@ -295,3 +301,62 @@ class TrunkDynamicScenario( vm_ssh, len(trunk["sub_ports"])+1) self.simulate_subport_connection(trunk["id"], trunk_server_fip, jump_fip) + + def delete_subports_from_random_trunks(self, num_trunks, subport_count): + """Delete <> subports from <> randomly chosen trunks + :param num_trunks: int, number of trunks to be randomly chosen + :param subport_count: int, number of subports to add to each trunk + """ + trunks = self._list_trunks() + + eligible_trunks = [trunk for trunk in trunks if len(trunk['sub_ports']) >= subport_count] + num_trunks = min(num_trunks, len(trunks)) + random.shuffle(eligible_trunks) + + if len(eligible_trunks) >= num_trunks: + trunks_to_delete_subports = [eligible_trunks[i] for i in range(num_trunks)] + else: + trunks_to_delete_subports = sorted(trunks, + key=lambda k:-len(k['sub_ports']))[:num_trunks] + subport_count = len(trunks_to_delete_subports[-1]['sub_ports']) + + for trunk in trunks_to_delete_subports: + trunk_server_fip = self.get_server_by_trunk(trunk) + jump_fip = self.get_jumphost_by_trunk(trunk) + + vm_ssh = sshutils.SSH(self.trunk_vm_user, + trunk_server_fip, pkey=self.keypair["private"]) + self._wait_for_ssh(vm_ssh) + + trunk_subports = trunk['sub_ports'] + num_trunk_subports = len(trunk_subports) + + # We delete subports from trunks starting from the last subport, + # instead of randomly. This is because deleting random subports + # might cause a lot of conflict with the add_subports_to_random_ + # trunks function. + for subport_number in range(num_trunk_subports-1, + num_trunk_subports-1-subport_count, -1): + subport_details = trunk_subports[subport_number] + subport_to_delete = self.clients("neutron").show_port(subport_details["port_id"]) + subport_payload = [ + { + "port_id": subport_to_delete["port"]["id"], + "segmentation_type": "vlan", + "segmentation_id": subport_number+1, + } + ] + + cmd = f"sudo ip link delete eth0.{subport_number+1}" + self._run_command_with_attempts(vm_ssh,cmd) + self.clients("neutron").trunk_remove_subports(trunk["id"], + {"sub_ports": subport_payload}) + self.clients("neutron").delete_port(subport_to_delete["port"]["id"]) + + # Check the number of subports present in trunk after deletion, + # and simulate subport connection if it is > 0. We use the + # show_trunk function here to get updated information about the + # trunk, as the trunk loop variable will have whatever information + # 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)