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:
parent
c00ff2d45a
commit
68f7a46722
@ -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
|
||||
|
@ -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)
|
@ -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}}
|
161
rally/rally-plugins/netcreate-boot/rally_context.py
Normal file
161
rally/rally-plugins/netcreate-boot/rally_context.py
Normal 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)
|
Loading…
Reference in New Issue
Block a user