Skip to content

Commit

Permalink
draft
Browse files Browse the repository at this point in the history
  • Loading branch information
git-hyagi committed Jan 9, 2025
1 parent ffd285d commit a333775
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 0 deletions.
9 changes: 9 additions & 0 deletions management_tools/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM registry.fedoraproject.org/fedora-minimal:39

RUN microdnf install -y pip gnuplot && microdnf clean all
RUN pip install requests && rm -rf /root/.cache/pip

COPY gnuplot-script .
COPY tasks-cli.py .

CMD ["python", "tasks-cli.py"]
9 changes: 9 additions & 0 deletions management_tools/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
* building
```
podman build -t tasks-cli:latest .
```

* running
```
podman run -it --rm tasks-cli
```
24 changes: 24 additions & 0 deletions management_tools/gnuplot-script
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
set xlabel "Values"
set ylabel "Frequency"
set title "Histogram of Data Values"
set output "/tmp/tasks.png"


#set xdata time
#set timefmt "%Y-%m-%dT%H:%M:%S.%zZ"

#set style data lines
set style data histogram
set style histogram rowstacked
set boxwidth 0.75
#set style histogram cluster gap 1
set style fill solid 1.0 border -1.0 # Fill style for the boxes

# Fine control of the major (labelled) tics on the x axis
set xtics rotate by -90

#plot "/tmp/a" u 1:2
plot filename using 2:xtic(1) ti 'runing' lt rgb 'green', '' using 3 ti 'waiting blocked' lt rgb 'red', '' using 4 ti 'waiting unblocked' lt rgb 'blue'

set grid ytics lt rgb "gray"
pause -1
187 changes: 187 additions & 0 deletions management_tools/tasks-cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
import argparse
import json
import os
import requests
import subprocess

from datetime import datetime, timedelta
from types import SimpleNamespace


DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ"
TZ = timedelta(hours=3)
TASKS_ENDPOINT = "/api/pulp/admin/tasks/?fields=started_at&"

QUERY_TYPES = SimpleNamespace(
RUNNING="running",
WAITING_UNBLOCKED="waiting_unblocked",
WAITING_BLOCKED="waiting_blocked",
)

parser = argparse.ArgumentParser()
parser.add_argument(
"-b",
"--base_address",
help="Pulp hostname address. For example: http://pulp-service:5001",
default="http://pulp-api-ephemeral-dden7g.apps.crc-eph.r9lp.p1.openshiftapps.com",
)
parser.add_argument(
"-u", "--username", help="Pulp user to run the API requests. [DEFAULT: admin]", default="admin"
)
parser.add_argument(
"-p",
"--password",
help="Password for Pulp user. [DEFAULT: password]",
default="X3fmXzf1ud0Dw1Kb4SbQ5f1IhWZm5VAirGXWVXTNV64=",
)
parser.add_argument("-c", "--certificate", help="Certificate to authenticate to Pulp API.")
parser.add_argument("-k", "--key", help="Private key for the certificate authentication.")
parser.add_argument(
"--period",
help="Period, in hours, to check the tasks. For example, for the last 24 hours: --period=24 [DEFAULT: 24]",
type=int,
default=6,
)
parser.add_argument(
"--bucket_size",
help="Bucket size, in seconds. For example, for a 30 seconds bucket: --bucket-size=30 [DEFAULT: 3600]",
type=int,
default=1800,
)
parser.add_argument(
"-o",
"--output",
help="Output file. [DEFAULT: /tmp/pulp_tasks.out]",
type=str,
default="/tmp/pulp_tasks.out",
)

args = parser.parse_args()

base_addr = args.base_address
username = args.username
password = args.password
period_in_hours = args.period
bucket_size_in_seconds = args.bucket_size
output_file = args.output


def run():

datetime_now = datetime.now() + TZ
query_date_time = datetime_now - timedelta(hours=period_in_hours)
start_date = query_date_time.strftime(DATETIME_FORMAT)
data = initialize_response_structure(period_in_hours, bucket_size_in_seconds, query_date_time)

for task_state in QUERY_TYPES.__dict__.values():
tasks = get_tasks(start_date, task_state)
make_buckets(
tasks, bucket_size_in_seconds, query_date_time, period_in_hours, task_state, data
)

# [TODO]: remove the following!!!!
# overwriting the first column for tests
tasks = get_tasks(start_date)
make_buckets(
tasks, bucket_size_in_seconds, query_date_time, period_in_hours, QUERY_TYPES.RUNNING, data
)

write_to_file(data)
p = subprocess.Popen("gnuplot -e \"filename='"+output_file+"'\" -c gnuplot-script", shell = True)
os.waitpid(p.pid, 0)

def write_to_file(data):
with open(output_file, "w") as f:
for key in data:
print(
key,
data[key][QUERY_TYPES.RUNNING],
data[key][QUERY_TYPES.WAITING_BLOCKED],
data[key][QUERY_TYPES.WAITING_UNBLOCKED],
)
f.write(
key
+ " "
+ str(data[key][QUERY_TYPES.RUNNING])
+ " "
+ str(data[key][QUERY_TYPES.WAITING_BLOCKED])
+ " "
+ str(data[key][QUERY_TYPES.WAITING_UNBLOCKED])
+ "\n"
)

def get_tasks(start_date, query_type=None):
url = base_addr + TASKS_ENDPOINT + "started_at__gte=" + start_date
if query_type == QUERY_TYPES.RUNNING:
url = running_tasks_url(start_date)
elif query_type == QUERY_TYPES.WAITING_UNBLOCKED:
url = tasks_in_waiting_state_and_unblocked_url(False, start_date)
elif query_type == QUERY_TYPES.WAITING_BLOCKED:
url = tasks_in_waiting_state_and_unblocked_url(True, start_date)

response = requests.get(url, auth=(username, password))
response_json = json.loads(response.text)

tasks_found_datetime = []
if response_json.get("results"):
for result in response_json["results"]:
tasks_found_datetime.append(result["started_at"])

return tasks_found_datetime


def initialize_response_structure(period, bucket_size, query_date_time):
data = {}
total_seconds = timedelta(hours=period).total_seconds()
number_of_intervals = int(total_seconds // bucket_size)

# Create a list of bucket start times
bucket_starts = [
query_date_time + timedelta(seconds=i * bucket_size) for i in range(number_of_intervals)
]

# Initialize buckets
for start_time in bucket_starts:
data[start_time.strftime(DATETIME_FORMAT)] = {}
for task_state in QUERY_TYPES.__dict__.values():
data[start_time.strftime(DATETIME_FORMAT)][task_state] = 0

return data


def make_buckets(tasks_found_datetime, bucket_size, query_date_time, period, query_type, data):
total_seconds = timedelta(hours=period).total_seconds()
number_of_intervals = int(total_seconds // bucket_size)

# Count tasks in each bucket
for task_datetime_str in tasks_found_datetime:
task_datetime = datetime.strptime(task_datetime_str, DATETIME_FORMAT)

# Find the appropriate bucket for the task
for i in range(number_of_intervals):
start_time = query_date_time + timedelta(seconds=i * bucket_size)
end_time = start_time + timedelta(seconds=bucket_size)

if start_time < task_datetime < end_time:
data[start_time.strftime(DATETIME_FORMAT)][query_type] += 1
break # Task is counted, no need to check further

return data


def running_tasks_url(start_date):
return base_addr + TASKS_ENDPOINT + "started_at__gte=" + start_date + "&state=running"


def tasks_in_waiting_state_and_unblocked_url(unblocked_null, start_date):
return (
base_addr
+ TASKS_ENDPOINT
+ "started_at__gte="
+ start_date
+ "&state=waiting&unblocked_at__isnull="
+ str(unblocked_null)
)


run()

0 comments on commit a333775

Please sign in to comment.