Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Meet Orion #2

Merged
merged 1 commit into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Pylint

on: [push,pull_request]

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pylint
- name: Analysing the code with pylint
run: |
pylint -d C0103 $(git ls-files '*.py')
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,7 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

*.yaml
*.csv
.vscode/
68 changes: 68 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Orion - CLI tool to find regressions
Orion stands as a powerful command-line tool designed for identifying regressions within perf-scale CPT runs, leveraging metadata provided during the process. The detection mechanism relies on [hunter](https://github.com/datastax-labs/hunter).

Below is an illustrative example of the config and metadata that Orion can handle:

```
tests :
- name : aws-small-scale-cluster-density-v2
platform: AWS
masterNodesType: m6a.xlarge
masterNodesCount: 3
workerNodesType: m6a.xlarge
workerNodesCount: 24
benchmark: cluster-density-v2
ocpVersion: 4.15
networkType: OVNKubernetes
# encrypted: true
# fips: false
# ipsec: false

metrics :
- metric : podReadyLatency
metricType : latency

- metric : apiserverCPU
metricType : cpu
namespace: openshift-kube-apiserver

- metric: ovnCPU
metricType: cpu
namespace: openshift-ovn-kubernetes

- metric: etcdCPU
metricType: cpu
namespace: openshift-ovn-kubernetes


```

## Build Orion
Building Orion is a straightforward process. Follow these commands:

Clone the current repository using git clone.

```
>> git clone <repository_url>
>> pip install venv
>> source venv/bin/activate
>> pip install -r requirements.txt
>> export ES_SERVER = <es_server_url>
>> pip install .
```
## Run Orion
Executing Orion is as simple as building it. After following the build steps, run the following:
```
>> orion
```
At the moment,

Orion provides flexibility in configuring its behavior by allowing users to set the path to their config file using the ```--config``` flag.

For enhanced troubleshooting and debugging, Orion supports the ```--debug``` flag, enabling the generation of detailed debug logs.

Additionally, users can specify a custom path for the output CSV file using the ```--output``` flag, providing control over the location where the generated CSV will be stored.

Orion's seamless integration with metadata and hunter ensures a robust regression detection tool for perf-scale CPT runs.


161 changes: 161 additions & 0 deletions orion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
"""
This is the cli file for orion, tool to detect regressions using hunter
"""
# pylint: disable = import-error
import sys
from functools import reduce
import logging
import os

import click
import yaml
import pandas as pd
from fmatch.matcher import Matcher


@click.group()
def cli():
"""
cli function to group commands
"""


# pylint: disable=too-many-locals
@click.command()
@click.option("--config", default="config.yaml", help="Path to the configuration file")
@click.option("--output", default="output.csv", help="Path to save the output csv file")
@click.option("--debug", is_flag=True, help="log level ")
def orion(config, debug, output):
"""Orion is the cli tool to detect regressions over the runs

Args:
config (str): path to the config file
debug (bool): lets you log debug mode
output (str): path to the output csv file
"""
level = logging.DEBUG if debug else logging.INFO
logger = logging.getLogger("Orion")
logger = set_logging(level, logger)

if "ES_SERVER" not in os.environ:
logger.error("ES_SERVER environment variable not set")
sys.exit(1)

jtaleric marked this conversation as resolved.
Show resolved Hide resolved
try:
with open(config, "r", encoding="utf-8") as file:
data = yaml.safe_load(file)
logger.debug("The %s file has successfully loaded", config)
except FileNotFoundError as e:
logger.error("Config file not found: %s", e)
sys.exit(1)
except Exception as e: # pylint: disable=broad-exception-caught
logger.error("An error occurred: %s", e)
sys.exit(1)
for test in data["tests"]:
metadata = get_metadata(test)
logger.info("The test %s has started", test["name"])
match = Matcher(index="perf_scale_ci", level=level)
uuids = match.get_uuid_by_metadata(metadata)
if len(uuids) == 0:
print("No UUID present for given metadata")
sys.exit()

runs = match.match_kube_burner(uuids)
ids = match.filter_runs(runs, runs)
metrics = test["metrics"]
dataframe_list = []

for metric in metrics:
logger.info("Collecting %s", metric["metric"])
if metric["metricType"] == "latency":
if metric["metric"] == "podReadyLatency":
try:
podl = match.burner_results("", ids, "ripsaw-kube-burner*")
podl_df = match.convert_to_df(
podl, columns=["uuid", "timestamp", "P99"]
)
dataframe_list.append(podl_df)
logger.debug(podl_df)
except Exception as e: # pylint: disable=broad-exception-caught
logger.error(
"The namespace %s does not exist, exception %s",
metric["namespace"],
e,
)

elif metric["metricType"] == "cpu":
try:
cpu = match.burner_cpu_results(
ids, metric["namespace"], "ripsaw-kube-burner*"
)
cpu_df = match.convert_to_df(cpu, columns=["uuid", "cpu_avg"])
cpu_df = cpu_df.rename(
columns={"cpu_avg": metric["metric"] + "_cpu_avg"}
)
dataframe_list.append(cpu_df)
logger.debug(cpu_df)
except Exception as e: # pylint: disable=broad-exception-caught
logger.error(
"The namespace %s does not exist, exception %s",
metric["namespace"],
e,
)

merged_df = reduce(
lambda left, right: pd.merge(left, right, on="uuid", how="inner"),
dataframe_list,
)
match.save_results(merged_df, csv_file_path=output)


def get_metadata(test):
"""Gets metadata of the run from each test

Args:
test (dict): test dictionary

Returns:
dict: dictionary of the metadata
"""
metadata_columns = [
"platform",
"masterNodesType",
"masterNodesCount",
"workerNodesType",
"workerNodesCount",
"benchmark",
"ocpVersion",
"networkType",
"encrypted",
"fips",
"ipsec",
]
metadata = {key: test[key] for key in metadata_columns if key in test}
metadata["ocpVersion"] = str(metadata["ocpVersion"])
return metadata


def set_logging(level, logger):
"""sets log level and format

Args:
level (_type_): level of the log
logger (_type_): logger object

Returns:
logging.Logger: a formatted and level set logger
"""
logger.setLevel(level)
handler = logging.StreamHandler(sys.stdout)
handler.setLevel(level)
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger


if __name__ == "__main__":
cli.add_command(orion)
cli()
14 changes: 14 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
certifi==2023.11.17
click==8.1.7
elastic-transport==8.11.0
elasticsearch==8.11.1
elasticsearch7==7.13.0
fmatch==0.0.2
numpy==1.26.3
pandas==2.1.4
python-dateutil==2.8.2
pytz==2023.3.post1
PyYAML==6.0.1
six==1.16.0
tzdata==2023.4
urllib3==1.26.18
25 changes: 25 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# orion/setup.py
"""
setup.py for orion cli tool
"""
from setuptools import setup

setup(
name='orion',
version='1.0',
py_modules=['orion'],
install_requires=[
'click',
'fmatch'
],
entry_points={
'console_scripts': [
'orion = orion:orion',
],
},
classifiers=[
'Programming Language :: Python :: 3',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
],
)