Add nova_boot_from_context_provider_networks_ping workload

This patch adds a workload which creates provider networks as part
of Rally context, and boots VMs on the provider networks in round
robin order.

Co-authored-by: Jaison Raju <jraju@redhat.com>
Change-Id: I00999c81eaf78bbd72933df524bf55cf452d40fc
This commit is contained in:
Sanjay Chari 2022-07-29 14:37:53 +05:30
parent c00ff2d45a
commit 68f7a46722
4 changed files with 306 additions and 0 deletions

View File

@ -530,6 +530,19 @@ workloads:
iface_name: "ens7f0"
iface_mac: "3c:fd:fe:c1:8c:70"
file: rally/rally-plugins/netcreate-boot/provider_netcreate_nova_boot_ping.yml
- name: nova-boot-from-context-provider-networks-ping
# Creates provider networks as part of rally context. Number of VMs booted is equal to times.
# VMs are booted on the provider networks in round robin order.
enabled: true
num_provider_networks: 8
image_name: cirro5
flavor_name: m1.tiny-cirros
provider_phys_net: "provider"
iface_name: "ens7f0"
iface_mac: "3c:fd:fe:c1:8c:70"
cidr_prefix: "172.31"
ping_timeout: 30
file: rally/rally-plugins/netcreate-boot/nova_boot_from_context_provider_networks_ping.yml
- name: plugin-workloads
enabled: false

View File

@ -0,0 +1,86 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
import os
import subprocess
from rally_openstack.common import consts
from rally_openstack.task.scenarios.vm import utils as vm_utils
from rally_openstack.task.scenarios.neutron import utils as neutron_utils
from rally.task import atomic
from rally.task import scenario
from rally.task import types
from rally.task import validation
LOG = logging.getLogger(__name__)
@types.convert(image={"type": "glance_image"}, flavor={"type": "nova_flavor"})
@validation.add("image_valid_on_flavor", flavor_param="flavor", image_param="image")
@validation.add("required_services", services=[consts.Service.NEUTRON, consts.Service.NOVA])
@validation.add("required_platform", platform="openstack", admin=True)
@scenario.configure(context={"cleanup@openstack": ["neutron", "nova"], "keypair@openstack": {},
"allow_ssh@openstack": None},
name="BrowbeatPlugin.nova_boot_from_context_provider_networks_ping",
platform="openstack")
class NovaBootFromContextProviderNetworksPing(vm_utils.VMScenario,
neutron_utils.NeutronScenario):
def run(self, image, flavor, num_provider_networks, ping_timeout, **kwargs):
network_id = self.context["provider_networks"][((self.context["iteration"]-1)
% num_provider_networks)]["id"]
network = self._show_provider_network(network_id)
subnet = self.context["provider_subnets"][network_id]
kwargs["nics"] = [{'net-id': network_id}]
server = self._boot_server(image, flavor, **kwargs)
# ping server
internal_network = list(server.networks)[0]
server_ip = server.addresses[internal_network][0]["addr"]
server_mac = server.addresses[internal_network][0]["OS-EXT-IPS-MAC:mac_addr"]
gateway = subnet['gateway_ip']
vlan = network['network']['provider:segmentation_id']
dir_path = os.path.dirname(os.path.realpath(__file__))
file_path = os.path.join(dir_path, "scapy_icmp.py")
with atomic.ActionTimer(self, "nova.wait_for_custom_ping"):
cmd = ["sudo", file_path, server_ip, server_mac, gateway, self.context["iface_mac"],
self.context["iface_name"], str(vlan)]
proc = subprocess.Popen(cmd, start_new_session=True)
try:
proc.wait(timeout=ping_timeout)
except subprocess.TimeoutExpired:
pgid = os.getpgid(proc.pid)
procout = subprocess.check_output(['sudo', 'kill', str(pgid)]).decode("utf-8")
if not procout:
LOG.info("{} process group terminated successfully".format(pgid))
else:
LOG.info("{} process group did not terminate successfully. Stdout : {}".format(
pgid, procout))
raise Exception("Rally tired waiting {} seconds for ping to {}".format(
ping_timeout, server_ip))
if proc.returncode == 0:
LOG.info("Ping to {} is successful".format(server_ip))
else:
raise Exception("Ping to {} has failed".format(server_ip))
@atomic.action_timer("neutron.show_network")
def _show_provider_network(self, provider_network_id):
"""Fetches information of a certain provider network.
:param provider_network: provider network object
"""
return self.admin_clients("neutron").show_network(provider_network_id)

View File

@ -0,0 +1,46 @@
{% set flavor_name = flavor_name or "m1.xtiny" %}
{% set image_name = image_name or "cirros" %}
{% set num_provider_networks = num_provider_networks or 1 %}
{% set ping_timeout = ping_timeout or 30 %}
{% 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 %}
---
BrowbeatPlugin.nova_boot_from_context_provider_networks_ping:
-
args:
flavor:
name: "{{flavor_name}}"
image:
name: "{{image_name}}"
num_provider_networks: {{num_provider_networks}}
ping_timeout: {{ping_timeout}}
runner:
type: "constant"
times: {{times}}
concurrency: {{concurrency}}
context:
users:
tenants: 1
users_per_tenant: 1
quotas:
neutron:
network: -1
port: -1
subnet: -1
floatingip: -1
nova:
instances: -1
cores: -1
ram: -1
create_provider_networks:
num_provider_networks: {{ num_provider_networks }}
iface_name: '{{ iface_name }}'
iface_mac: '{{ iface_mac }}'
provider_phys_net: '{{ provider_phys_net }}'
cidr_prefix: '{{ cidr_prefix }}'
sla:
max_avg_duration: {{sla_max_avg_duration}}
max_seconds_per_iteration: {{sla_max_seconds}}
failure_rate:
max: {{sla_max_failure}}

View File

@ -0,0 +1,161 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from rally.task import context
from rally.common import logging
from rally.common import utils
from rally import consts
from rally_openstack import osclients
from rally_openstack.wrappers import network as network_wrapper
LOG = logging.getLogger(__name__)
@context.configure(name="create_provider_networks", order=1000)
class CreateProviderNetworksContext(context.Context):
"""This plugin creates provider networks with specified option."""
CONFIG_SCHEMA = {
"type": "object",
"$schema": consts.JSON_SCHEMA,
"additionalProperties": False,
"properties": {
"num_provider_networks": {
"type": "integer",
"minimum": 0
},
"iface_name": {
"type": "string"
},
"iface_mac": {
"type": "string"
},
"provider_phys_net": {
"type": "string"
},
"cidr_prefix": {
"type": "string"
}
}
}
def _create_subnet(self, tenant_id, network_id, network_number):
"""Create subnet for provider network
:param tenant_id: ID of tenant
:param network_id: ID of provider network
:param network_number: int, number for CIDR of subnet
:returns: subnet object
"""
subnet_args = {
"subnet": {
"tenant_id": tenant_id,
"network_id": network_id,
"name": self.net_wrapper.owner.generate_random_name(),
"ip_version": 4,
"cidr": "{}.{}.0/23".format(self.cidr_prefix, network_number),
"gateway_ip": "{}.{}.1".format(self.cidr_prefix, network_number),
"allocation_pools": [{"start": "{}.{}.2".format(self.cidr_prefix, network_number),
"end": "{}.{}.254".format(
self.cidr_prefix, network_number+1)}]
}
}
return self.net_wrapper.client.create_subnet(subnet_args)["subnet"]
def setup(self):
"""This method is called before the task starts."""
self.net_wrapper = network_wrapper.wrap(
osclients.Clients(self.context["admin"]["credential"]),
self,
config=self.config,
)
self.context["provider_networks"] = []
self.context["provider_subnets"] = {}
self.num_provider_networks = self.config.get("num_provider_networks", 16)
self.context["iface_name"] = self.config.get("iface_name", "ens7f0")
self.context["iface_mac"] = self.config.get("iface_mac", " ")
self.provider_phys_net = self.config.get("provider_phys_net", "datacentre")
self.cidr_prefix = self.config.get("cidr_prefix", "172.31")
num_provider_networks_created = 0
while num_provider_networks_created < self.num_provider_networks:
has_error_occured = False
for user, tenant_id in utils.iterate_per_tenants(
self.context.get("users", [])
):
try:
kwargs = {
"network_create_args": {
"provider:network_type": "vlan",
"provider:physical_network": self.provider_phys_net
}
}
self.context["provider_networks"].append(
self.net_wrapper.create_network(tenant_id, **kwargs)
)
LOG.debug(
"Provider network with id '%s' created as part of context"
% self.context["provider_networks"][-1]["id"]
)
num_provider_networks_created += 1
except Exception as e:
msg = "Can't create provider network {} as part of context: {}".format(
num_provider_networks_created, e
)
LOG.exception(msg)
has_error_occured = True
break
try:
subnet = self._create_subnet(tenant_id,
self.context["provider_networks"][-1]["id"],
(num_provider_networks_created - 1) * 2)
self.context["provider_subnets"][
self.context["provider_networks"][-1]["id"]] = subnet
LOG.debug(
"Provider subnet with id '%s' created as part of context"
% subnet["id"]
)
except Exception as e:
msg = "Can't create provider subnet {} as part of context: {}".format(
num_provider_networks_created, e
)
LOG.exception(msg)
has_error_occured = True
break
if has_error_occured:
break
def cleanup(self):
"""This method is called after the task finishes."""
for i in range(self.num_provider_networks):
try:
provider_net = self.context["provider_networks"][i]
provider_net_id = provider_net["id"]
provider_subnet = self.context["provider_subnets"][provider_net_id]
provider_subnet_id = provider_subnet["id"]
self.net_wrapper._delete_subnet(provider_subnet_id)
LOG.debug(
"Provider subnet with id '%s' deleted from context"
% provider_subnet_id
)
self.net_wrapper.delete_network(provider_net)
LOG.debug(
"Provider network with id '%s' deleted from context"
% provider_net_id
)
except Exception as e:
msg = "Can't delete provider network {} from context: {}".format(
provider_net_id, e
)
LOG.warning(msg)