![Sanjay Chari](/assets/img/avatar_default.png)
This patch adds a workload which boots VMs with the following specifications. 1. On non-NFV compute nodes : 1 port in a tenant network, 1 port in a provider network 2. On DPDK compute nodes: 1 SR-IOV/tenant network port, 1 DPDK port 3. On OvS Hardware Offload compute nodes: 1 SR-IOV/tenant network port, 1 Hardware Offload port Change-Id: I76d468c333f919219db9525f0df2ac911f1a719f
309 lines
14 KiB
Python
309 lines
14 KiB
Python
# 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.common import osclients
|
|
from rally_openstack.common.wrappers import network as network_wrapper
|
|
|
|
import yaml
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
@context.configure(name="create_nfv_azs_and_networks", order=1100)
|
|
class CreateNFVAZsandNetworksContext(context.Context):
|
|
"""This plugin creates availability zones with host aggregates and networks
|
|
for non-NFV, SR-IOV with DPDK and SR-IOV with hardware offload.
|
|
"""
|
|
|
|
CONFIG_SCHEMA = {
|
|
"type": "object",
|
|
"$schema": consts.JSON_SCHEMA,
|
|
"additionalProperties": True,
|
|
"properties": {
|
|
"boot_dpdk_vms": {
|
|
"type": "string",
|
|
"default": "False"
|
|
},
|
|
"boot_hw_offload_vms": {
|
|
"type": "string",
|
|
"default": "False"
|
|
},
|
|
"dpdk_hosts_group": {
|
|
"type": "string",
|
|
"default": "ComputeOvsDpdkSriov"
|
|
},
|
|
"hw_offload_hosts_group": {
|
|
"type": "string",
|
|
"default": "ComputeSriovOffload"
|
|
},
|
|
"tripleo_inventory_file": {
|
|
"type": "string",
|
|
"default": "/home/stack/browbeat/ansible/hosts.yml"
|
|
}
|
|
}
|
|
}
|
|
|
|
def _create_subnet(self, tenant_id, network_id, network_number):
|
|
"""Create subnet for network
|
|
|
|
:param tenant_id: ID of tenant
|
|
:param network_id: ID of 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": "172.{}.0.0/16".format(network_number),
|
|
"enable_dhcp": True,
|
|
"gateway_ip": "172.{}.0.1".format(network_number),
|
|
"allocation_pools": [{"start": "172.{}.0.2".format(network_number),
|
|
"end": "172.{}.254.254".format(network_number)}]
|
|
}
|
|
}
|
|
return self.net_wrapper.client.create_subnet(subnet_args)["subnet"]
|
|
|
|
def _create_networks_and_subnets(self, tenant_id):
|
|
self.net_wrapper = network_wrapper.wrap(
|
|
osclients.Clients(self.context["admin"]["credential"]),
|
|
self,
|
|
config=self.config,
|
|
)
|
|
|
|
net_kwargs = {
|
|
"network_create_args": {
|
|
"provider:network_type": "vlan",
|
|
"provider:physical_network": self.config["provider_phys_nets"]["vanilla"],
|
|
"provider:segmentation_id": self.network_vlan_number,
|
|
}
|
|
}
|
|
vanilla_network = self.net_wrapper.create_network(tenant_id, **net_kwargs)
|
|
|
|
self.context["vanilla_networks"][tenant_id] = vanilla_network
|
|
self.context["vanilla_subnets"][tenant_id] = self._create_subnet(
|
|
tenant_id, vanilla_network["id"],
|
|
self.network_vlan_number-950)
|
|
self.network_vlan_number += 1
|
|
|
|
if self.context["boot_dpdk_vms"]:
|
|
net_kwargs = {
|
|
"network_create_args": {
|
|
"provider:network_type": "vlan",
|
|
"provider:physical_network": self.config["provider_phys_nets"]["dpdk"],
|
|
"provider:segmentation_id": self.network_vlan_number,
|
|
}
|
|
}
|
|
|
|
dpdk_network = self.net_wrapper.create_network(tenant_id, **net_kwargs)
|
|
self.context["nfv_networks"].setdefault("dpdk", {})
|
|
self.context["nfv_networks"]["dpdk"][tenant_id] = dpdk_network
|
|
self.context["nfv_subnets"].setdefault("dpdk", {})
|
|
self.context["nfv_subnets"]["dpdk"][tenant_id] = self._create_subnet(
|
|
tenant_id, dpdk_network["id"],
|
|
self.network_vlan_number-950)
|
|
self.network_vlan_number += 1
|
|
|
|
net_kwargs = {
|
|
"network_create_args": {
|
|
"provider:network_type": "vlan",
|
|
"provider:physical_network": self.config["provider_phys_nets"]["sriov"],
|
|
"provider:segmentation_id": self.network_vlan_number,
|
|
}
|
|
}
|
|
sriov_network = self.net_wrapper.create_network(tenant_id, **net_kwargs)
|
|
|
|
self.context["nfv_networks"].setdefault("sriov", {})
|
|
self.context["nfv_networks"]["sriov"][tenant_id] = sriov_network
|
|
self.context["nfv_subnets"].setdefault("sriov", {})
|
|
self.context["nfv_subnets"]["sriov"][tenant_id] = self._create_subnet(
|
|
tenant_id, sriov_network["id"],
|
|
self.network_vlan_number-950)
|
|
self.network_vlan_number += 1
|
|
|
|
if self.context["boot_hw_offload_vms"]:
|
|
net_kwargs = {
|
|
"network_create_args": {
|
|
"provider:network_type": "vlan",
|
|
"provider:physical_network": self.config["provider_phys_nets"]["hw_offload"],
|
|
"provider:segmentation_id": self.network_vlan_number,
|
|
}
|
|
}
|
|
hw_offload_network = self.net_wrapper.create_network(tenant_id, **net_kwargs)
|
|
|
|
self.context["nfv_networks"].setdefault("hw_offload", {})
|
|
self.context["nfv_networks"]["hw_offload"][tenant_id] = hw_offload_network
|
|
self.context["nfv_subnets"].setdefault("hw_offload", {})
|
|
self.context["nfv_subnets"]["hw_offload"][tenant_id] = self._create_subnet(
|
|
tenant_id, hw_offload_network["id"],
|
|
self.network_vlan_number-950)
|
|
self.network_vlan_number += 1
|
|
|
|
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.nova_wrapper = osclients.Nova(self.context["admin"]["credential"]).create_client()
|
|
self.context["nfv_networks"] = {}
|
|
self.context["nfv_subnets"] = {}
|
|
self.context["vanilla_networks"] = {}
|
|
self.context["vanilla_subnets"] = {}
|
|
# This has been made a string value so that upper case/lower case
|
|
# variations can be considered.
|
|
self.context["boot_dpdk_vms"] = self.config.get("boot_dpdk_vms", "False") in [
|
|
"True", "true"]
|
|
self.context["boot_hw_offload_vms"] = self.config.get("boot_hw_offload_vms",
|
|
"False") in [
|
|
"True", "true"]
|
|
self.dpdk_hosts_group = self.config.get("dpdk_hosts_group",
|
|
"ComputeOvsDpdk")
|
|
self.hw_offload_hosts_group = self.config.get("hw_offload_hosts_group",
|
|
"ComputeSriovOffload")
|
|
self.network_vlan_number = 1001
|
|
|
|
tripleo_inventory_file_path = self.config.get("tripleo_inventory_file",
|
|
"/home/stack/browbeat/ansible/hosts.yml")
|
|
with open(tripleo_inventory_file_path, "r") as tripleo_inventory_file:
|
|
self.tripleo_inventory = yaml.safe_load(tripleo_inventory_file)
|
|
|
|
dpdk_and_hw_offload_hosts = []
|
|
|
|
if self.context["boot_dpdk_vms"]:
|
|
self.dpdk_aggregate = self.nova_wrapper.aggregates.create(
|
|
"dpdk_aggregate", "az_dpdk")
|
|
dpdk_hosts = self.tripleo_inventory[self.dpdk_hosts_group]["hosts"]
|
|
self.context["num_dpdk_compute_hosts"] = len(dpdk_hosts)
|
|
for host_details in dpdk_hosts.values():
|
|
self.nova_wrapper.aggregates.add_host(self.dpdk_aggregate.id,
|
|
host_details["canonical_hostname"])
|
|
dpdk_and_hw_offload_hosts.append(host_details["canonical_hostname"])
|
|
|
|
if self.context["boot_hw_offload_vms"]:
|
|
self.hw_offload_aggregate = self.nova_wrapper.aggregates.create(
|
|
"hw_offload_aggregate", "az_hw_offload")
|
|
hw_offload_hosts = self.tripleo_inventory[
|
|
self.hw_offload_hosts_group]["hosts"]
|
|
self.context["num_hw_offload_compute_hosts"] = len(hw_offload_hosts)
|
|
for host_details in hw_offload_hosts.values():
|
|
self.nova_wrapper.aggregates.add_host(self.hw_offload_aggregate.id,
|
|
host_details["canonical_hostname"])
|
|
dpdk_and_hw_offload_hosts.append(host_details["canonical_hostname"])
|
|
|
|
self.vanilla_compute_aggregate = self.nova_wrapper.aggregates.create(
|
|
"vanilla_compute_aggregate", "az_vanilla_compute")
|
|
|
|
self.vanilla_compute_hosts = set()
|
|
for hostsgroup in self.tripleo_inventory:
|
|
if "hosts" in self.tripleo_inventory[hostsgroup] and "Compute" in hostsgroup:
|
|
for host_details in self.tripleo_inventory[hostsgroup]["hosts"].values():
|
|
if ("canonical_hostname" in host_details and
|
|
host_details["canonical_hostname"] not in dpdk_and_hw_offload_hosts):
|
|
self.nova_wrapper.aggregates.add_host(
|
|
self.vanilla_compute_aggregate.id,
|
|
host_details["canonical_hostname"])
|
|
self.vanilla_compute_hosts.add(host_details["canonical_hostname"])
|
|
self.context["num_vanilla_compute_hosts"] = len(self.vanilla_compute_hosts)
|
|
|
|
for _, tenant_id in utils.iterate_per_tenants(
|
|
self.context.get("users", [])
|
|
):
|
|
self._create_networks_and_subnets(tenant_id)
|
|
|
|
def cleanup(self):
|
|
"""This method is called after the task finishes."""
|
|
for hostname in self.vanilla_compute_hosts:
|
|
self.nova_wrapper.aggregates.remove_host(self.vanilla_compute_aggregate.id,
|
|
hostname)
|
|
self.nova_wrapper.aggregates.delete(self.vanilla_compute_aggregate.id)
|
|
|
|
if self.context["boot_dpdk_vms"]:
|
|
dpdk_hosts = self.tripleo_inventory[self.dpdk_hosts_group]["hosts"]
|
|
for host_details in dpdk_hosts.values():
|
|
self.nova_wrapper.aggregates.remove_host(self.dpdk_aggregate.id,
|
|
host_details["canonical_hostname"])
|
|
self.nova_wrapper.aggregates.delete(self.dpdk_aggregate.id)
|
|
|
|
if self.context["boot_hw_offload_vms"]:
|
|
hw_offload_hosts = self.tripleo_inventory[
|
|
self.hw_offload_hosts_group]["hosts"]
|
|
for host_details in hw_offload_hosts.values():
|
|
self.nova_wrapper.aggregates.remove_host(self.hw_offload_aggregate.id,
|
|
host_details["canonical_hostname"])
|
|
self.nova_wrapper.aggregates.delete(self.hw_offload_aggregate.id)
|
|
|
|
for subnet in self.context["vanilla_subnets"].values():
|
|
try:
|
|
subnet_id = subnet["id"]
|
|
self.net_wrapper._delete_subnet(subnet_id)
|
|
LOG.debug(
|
|
"Subnet with id '%s' deleted from context"
|
|
% subnet_id
|
|
)
|
|
except Exception as e:
|
|
msg = "Can't delete subnet {} from context: {}".format(
|
|
subnet_id, e
|
|
)
|
|
LOG.warning(msg)
|
|
|
|
for network in self.context["vanilla_networks"].values():
|
|
try:
|
|
network_id = network["id"]
|
|
self.net_wrapper.delete_network(network)
|
|
LOG.debug(
|
|
"Network with id '%s' deleted from context"
|
|
% network_id
|
|
)
|
|
except Exception as e:
|
|
msg = "Can't delete network {} from context: {}".format(
|
|
network_id, e
|
|
)
|
|
LOG.warning(msg)
|
|
|
|
for subnets in self.context["nfv_subnets"].values():
|
|
for subnet in subnets.values():
|
|
try:
|
|
nfv_subnet_id = subnet["id"]
|
|
self.net_wrapper._delete_subnet(nfv_subnet_id)
|
|
LOG.debug(
|
|
"Subnet with id '%s' deleted from context"
|
|
% nfv_subnet_id
|
|
)
|
|
except Exception as e:
|
|
msg = "Can't delete subnet {} from context: {}".format(
|
|
nfv_subnet_id, e
|
|
)
|
|
LOG.warning(msg)
|
|
|
|
for networks in self.context["nfv_networks"].values():
|
|
for network in networks.values():
|
|
try:
|
|
nfv_network_id = network["id"]
|
|
self.net_wrapper.delete_network(network)
|
|
LOG.debug(
|
|
"Network with id '%s' deleted from context"
|
|
% nfv_network_id
|
|
)
|
|
except Exception as e:
|
|
msg = "Can't delete network {} from context: {}".format(
|
|
nfv_network_id, e
|
|
)
|
|
LOG.warning(msg)
|