Skip to content

Commit

Permalink
Merge branch 'SovereignCloudStack:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
piobig2871 authored Sep 3, 2024
2 parents 48b53bb + 77d9323 commit 527ea8c
Show file tree
Hide file tree
Showing 16 changed files with 260 additions and 173 deletions.
8 changes: 6 additions & 2 deletions cloud_level_testing/features/environment.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import os

from cloud_level_testing.features.steps.tools import (
Tools,
Collector,
Expand All @@ -13,7 +15,7 @@

DEFAULT_PROMETHEUS_BATCH_NAME = "SCS-Health-Monitor"
DEFAULT_CLOUD_NAME = "gx"
DEFAULT_LOG_LEVEL = "INFO"
DEFAULT_LOG_LEVEL = os.environ.get("LOGLEVEL", "INFO")


class SetupClass:
Expand Down Expand Up @@ -84,6 +86,8 @@ def before_all(context):
cloudName = context.env.get("CLOUD_NAME", DEFAULT_CLOUD_NAME)

context.logger = Logger(level=DEFAULT_LOG_LEVEL)
context.logger.log_info(f"Starting logger in level {DEFAULT_LOG_LEVEL}")

context.prometheusExporter = PrometheusExporter()
context.prometheusExporter.add_default_label(LabelNames.CLOUD_LABEL, cloudName)

Expand Down Expand Up @@ -113,7 +117,7 @@ def after_feature(context, feature):
context.logger.log_info(
f"Feature '{feature.name}' failed: performing cleanup or additional actions"
)
if "create" in feature.tags or "delete" in feature.tag:
if "create" in feature.tags or "delete" in feature.tags:
if context.collector:
context.logger.log_info(
f"Feature '{feature.name}' is a deletion or creation feature: performing cleanup"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ Feature: Build benchmark infrastructure
Then I should be able to create subnets for both the jump hosts and vms
Then I should be able to connect the router to the jump host subnet
Then I should be able to connect the router to the vm subnets
Then I should be able to create default security groups
Then I should be able to create a security group for the hosts allowing inbound tcp connections for the port range <port_start> to <port_end>
Then I should be able to create <quantity_vms> VMs with a key pair named <keypair_name> and strip them over the VM networks
Then I should be able to query the ip addresses of the created <quantity_vms> VMs
Then I should be able to calculate the port forwardings for the jump hosts by associating the VM ip addresses with the jump hosts by az in the port range <port_start> to <port_end>
Then I should be able to create a jump host for each az using a key pair named <keypair_name>
Then I should be able to attach floating ips to the jump hosts
Then I can pass the context to another feature

Examples: Build benchmark infrastructure
| test_infix | ext_net | keypair_name | quantity_vms | port_start | port_end |username|
| infra | ext01 | infra-keypair | 2 | 222 | 229 | ubuntu |

29 changes: 26 additions & 3 deletions cloud_level_testing/features/steps/benchmark_infra.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import jinja2
import base64

from openstack.network.v2.floating_ip import FloatingIP

import tools

DEFAULT_SECURITY_GROUPS = ["ssh", "default", "ping-sg"]
Expand Down Expand Up @@ -136,13 +138,28 @@ def infra_connect_router_to_vm_net(context):
router_update["port_id"],
)

@then("I should be able to create default security groups")
def create_default_security_groups(context):
for sg_name in DEFAULT_SECURITY_GROUPS:
if tools.check_security_group_exists(context, sg_name) is not None:
continue
sg = context.collector.create_security_group(sg_name, f"Default security group '{sg_name}'")
context.logger.log_info(f"Default security group {sg.name} was created")

@then(
"I should be able to create a security group for the hosts allowing inbound tcp "
"connections for the port range {port_start:d} to {port_end:d}"
)
def create_security_group(context, port_start: int, port_end: int):
sg_name = context.host_sec_group_name

if tools.check_security_group_exists(context, sg_name) is not None:
# Exists already, duplicate will be created
context.logger.log_warning(f"Security group {sg_name} already exists! Skipping creation..")
return

sg = context.collector.create_security_group(
context.host_sec_group_name,
sg_name,
"Allow ssh redirection inside network and iperf3",
)
context.collector.create_security_group_rule(
Expand Down Expand Up @@ -237,9 +254,11 @@ def infra_create_floating_ip(context):
# fip = context.collector.create_floating_ip(
# BenchmarkInfra.calculate_jh_name_by_az(context, az)
# )
fip = tools.attach_floating_ip_to_server(
fip: FloatingIP = tools.attach_floating_ip_to_server(
context, BenchmarkInfra.calculate_jh_name_by_az(context, az)
)
fip = fip.floating_ip_address

# Add jump host internal ip and fip to port forwardings data structure
for jh_name, redir in context.redirs.items():
if jh_name == BenchmarkInfra.calculate_jh_name_by_az(context, az):
Expand Down Expand Up @@ -268,13 +287,17 @@ def infra_create_vms(context, quantity: int, keypair_name: str):
), "Number of VM networks has to be greater than 0"
# Strip VMs over VM networks (basically round-robin)
vm_net_id = context.vm_nets_ids[num % len(context.vm_nets_ids)]
security_groups = DEFAULT_SECURITY_GROUPS + [context.host_sec_group_name]

context.logger.log_info(f"infra_create_vms security_groups: {security_groups}")

context.collector.create_jumphost(
vm_name,
vm_net_id,
keypair_name,
context.vm_image,
context.flavor_name,
DEFAULT_SECURITY_GROUPS + [context.host_sec_group_name],
security_groups=security_groups,
userdata=user_data,
)

Expand Down
23 changes: 14 additions & 9 deletions cloud_level_testing/features/steps/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,12 @@ def delete_network_ports(context):

@then("I should be able to create {subnet_quantity:d} subnets")
def create_subnet(context, subnet_quantity: int):
counter_networks = 0
for network in context.client.network.networks():
if f"{context.test_name}-network" in network.name:
context.logger.log_info(f"Creating subnets for network: {network}")
counter_networks += 1

cidr = tools.create_subnets(num=subnet_quantity)
for num in range(1, subnet_quantity + 1):
subnet = tools.create_subnet(
Expand All @@ -290,11 +294,13 @@ def create_subnet(context, subnet_quantity: int):
network_id=network.id,
cidr=cidr[num - 1],
)
context.logger.log_info(f"Created subnet {subnet.name}")
context.collector.subnets.append(subnet.id)
else:
continue

context.logger.log_info(f"Subnets in collector: {context.collector.subnets}, "
f"wished: {subnet_quantity*counter_networks}")
assert (
len(context.collector.subnets) == subnet_quantity
len(context.collector.subnets) == (subnet_quantity * counter_networks)
), f"Failed to create the desired amount of subnets"

@then("I should be able to delete subnets")
Expand Down Expand Up @@ -651,9 +657,8 @@ def create_a_jumphost(
)

for security_group in security_groups:
security_group = tools.check_security_group_exists(context, security_group)
assert (
security_group
tools.check_security_group_exists(context, security_group) is not None
), f"Security Group with name {security_group} doesn't exist"

server = tools.create_jumphost(
Expand Down Expand Up @@ -771,7 +776,7 @@ def collect_network_ips(context):
assert hasattr(
context, "redirs"
), f"No redirs found infrastructure not completely built yet"
assert isinstance(context.redirs, dict), "redirs is no dictionary"
assert isinstance(context.redirs, dict), f"redirs is no dictionary, but is {type(context.redirs)}"
context.ips, assertline = tools.collect_ips(
context.redirs, context.test_name, context.logger
)
Expand All @@ -784,7 +789,7 @@ def ensure_jh_deployed(context):
context, "redirs"
), f"No redirs found infrastructure not completely built yet"
context.logger.log_debug(f"vm data {context.redirs}")
assert isinstance(context.redirs, dict), "redirs is no dictionary"
assert isinstance(context.redirs, dict), f"redirs is no dictionary, but is {type(context.redirs)}"
context.jh = tools.collect_jhs(
context.redirs, context.test_name, context.logger
)
Expand Down Expand Up @@ -853,8 +858,8 @@ def attach_floating_ip_to_server(context, server_name: str):
context: Behave context object.
server_name: Name of the server for floating IP.
"""
fip, assertline = tools.attach_floating_ip_to_server(context, server_name)
assert assertline == None, assertline
fip = tools.attach_floating_ip_to_server(context, server_name)
assert fip is not None

@then(
"I start calculating 4000 digits of pi on VM and check the ping response"
Expand Down
88 changes: 55 additions & 33 deletions cloud_level_testing/features/steps/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
import time
import datetime
from functools import wraps
from typing import Iterator

from openstack.compute.v2.server import Server
from openstack.network.v2.floating_ip import FloatingIP
from openstack.network.v2.network import Network

from libs.loggerClass import Logger
from concurrent.futures import ThreadPoolExecutor
import os
Expand Down Expand Up @@ -78,7 +84,7 @@ def create_network(self, name, **kwargs):
**kwargs: Additional parameters to be passed to the `create_network` function
Returns:
net (dict): network object
"""
"""
net = create_network(self.client, name, **kwargs)
self.networks.append(net.id)
return net
Expand Down Expand Up @@ -109,7 +115,7 @@ def add_interface_to_router(self, router, subnet_id):
subnet_id (str): The ID of the subnet to be attached to the router
Returns:
router_update (dict): The updated router object after adding the interface
router_update (dict): The updated router object after adding the interface
by the `add_interface_to_router` function
"""
router_update = add_interface_to_router(self.client, router, subnet_id)
Expand Down Expand Up @@ -148,7 +154,7 @@ def delete_router_subnets(self):
"""
Deletes subnets from routers.
Iterates over the router-subnet pairs stored in `self.router_subnets`, removing the subnet interface from
Iterates over the router-subnet pairs stored in `self.router_subnets`, removing the subnet interface from
each router. Upon successful removal, the pair is removed from `self.router_subnets`
Raises:
Expand Down Expand Up @@ -244,10 +250,12 @@ def create_security_group(self, sec_group_name: str, description: str):
security_group = self.client.network.create_security_group(
name=sec_group_name, description=description
)

assert (security_group is not None), \
f"Security group with name {sec_group_name} could not be created"

self.security_groups.append(security_group.id)
assert (
security_group is not None
), f"Security group with name {security_group.name} was not found"

return security_group

def create_security_group_rule(
Expand Down Expand Up @@ -471,7 +479,7 @@ def ensure_volume_exist(
):
"""
Ensures that a volume with the specified name exists and is available
If the volume does not exist, it creates a new volume with the specified size
If the volume does not exist, it creates a new volume with the specified size
and waits until it becomes available
Args:
Expand Down Expand Up @@ -499,7 +507,7 @@ def ensure_volume_exist(

def verify_volumes_deleted(client, test_name):
"""
Verifies that all volumes associated with the given test name have been deleted
Verifies that all volumes associated with the given test name have been deleted
from the block storage service
Args:
Expand All @@ -519,7 +527,7 @@ def verify_volumes_deleted(client, test_name):

def verify_volume_deleted(client, volume_id):
"""
Verifies that a volume associated with the given volume_id has been deleted
Verifies that a volume associated with the given volume_id has been deleted
from the block storage service
Args:
Expand Down Expand Up @@ -553,7 +561,7 @@ def verify_router_deleted(client, router_id):
def check_volumes_created(client, test_name):
"""
Checks if volumes associated with the given test name have been created and are available
If found, it waits until the volume's status is 'available' and returns that status
If found, it waits until the volume's status is 'available' and returns that status
An assertion error is raised if the volume does not reach the 'available' status
Args:
Expand All @@ -565,7 +573,7 @@ def check_volumes_created(client, test_name):
Raises:
AssertionError: If the volume is not in the 'available' status
"""
for volume in client.volume.volumes():
if test_name in volume.name:
Expand All @@ -576,9 +584,9 @@ def check_volumes_created(client, test_name):
return volume.status


def attach_floating_ip_to_server(context, server_name):
def attach_floating_ip_to_server(context, server_name) -> FloatingIP:
"""
Attaches a floating IP to the specified server and adds it to the context
Attaches a floating IP to the specified server and adds it to the context
Args:
context (object): The context object containing the client and logger
Expand All @@ -587,22 +595,38 @@ def attach_floating_ip_to_server(context, server_name):
Returns:
tuple: A tuple containing the floating IP and an assert line if an error occurred
"""
assertline = None
try:
server = context.client.compute.find_server(name_or_id=server_name)
fip = context.client.add_auto_ip(server=server, wait=True, reuse=False)
context.fip_address = fip
context.logger.log_info(f"Attached floating ip: {fip}")
except:
fip = None
assertline = f"Server with name {server_name} not found"
server: Server = context.client.compute.find_server(name_or_id=server_name)
assert server is not None

try:
floating_ip_id = get_floating_ip_id(context, fip)
context.collector.floating_ips.append(floating_ip_id)
except:
assertline = f"Failed to get the ID of floating ip {fip}."
return fip, assertline
# Find all available networks that are marked as "external" (connection to outside the cluster)
external_networks: Iterator[Network] = context.client.network.networks(is_router_external=True)

# Then iterate over them and take one as floating IP source pool
counter_external_networks = 0
chosen_external_network: Network | None = None
for network in external_networks:
context.logger.log_info(f"Network in external_networks: {network}")
counter_external_networks += 1
chosen_external_network = network

# Checking the counter and the chosen network might be redundant, but you cannot
# count the len() of the iterator above. We want to make sure both cases are tested.
assert counter_external_networks > 0, "There are no external facing networks available"
assert chosen_external_network is not None

fip: FloatingIP = context.client.create_floating_ip(
network=chosen_external_network.id,
server=server,
wait=True,
timeout=60)
assert fip is not None

context.fip_address = fip.floating_ip_address
context.logger.log_info(f"Attached floating ip: {fip}")

context.collector.floating_ips.append(fip.id)

return fip


def collect_float_ips(client, logger: Logger):
Expand Down Expand Up @@ -1111,7 +1135,7 @@ def create_jumphost(
... security_groups=["default", "ssh-access"]
... )
>>> print(jumphost["id"])
"""
"""
keypair_filename = f"{keypair_name}-private"

image = client.compute.find_image(name_or_id=vm_image)
Expand All @@ -1130,9 +1154,8 @@ def create_jumphost(
os.chmod(keypair_filename, 0o600)

for security_group in security_groups:
security_group = client.network.find_security_group(security_group)
assert (
security_group
client.network.find_security_group(security_group) is not None
), f"Security Group with name {security_group} doesn't exist"

server = client.create_server(
Expand Down Expand Up @@ -1199,7 +1222,6 @@ def create_subnet(client, name, network_id, ip_version=4, **kwargs):
subnet = client.network.create_subnet(
name=name, network_id=network_id, ip_version=ip_version, **kwargs
)
time.sleep(5)
assert not client.network.find_network(
name_or_id=subnet
), f"Failed to create subnet with name {subnet}"
Expand Down Expand Up @@ -1288,7 +1310,7 @@ def target_source_calc(jh_name, redirs, logger):
logger (object): A logger object used to log information and debug messages.
Returns:
tuple: A tuple containing the target IP address (str), source IP address (str), port number (int),
tuple: A tuple containing the target IP address (str), source IP address (str), port number (int),
and VM name (str) of the last VM associated with the specified jump host.
"""
vm_quantity = len(redirs[jh_name]["vms"])
Expand Down
Loading

0 comments on commit 527ea8c

Please sign in to comment.