Skip to content
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
693cf62
Add cls to json type
itdove Jul 10, 2025
ece286f
Merge branch 'devel' into vcpu_collector
itdove Jul 11, 2025
4e59870
Remove the classes to simplify code
itdove Jul 11, 2025
aa23d3b
Add environment variable METRIC_UTILITY_ANSIBLE_SAAS_CLUSTER_NAME and…
itdove Jul 11, 2025
4e60f4e
ruff fix
itdove Jul 11, 2025
09c41a9
fix init timestamp
itdove Jul 11, 2025
2c5ac9d
Add get_mandatory_collectors
itdove Jul 11, 2025
766e173
Reformat collectors.py
itdove Jul 11, 2025
ce2a3a4
Use METRIC_UTILITY_VCPU_COUNT_ENABLED instead of METRIC_UTILITY_VCPU_…
itdove Jul 11, 2025
252c4c4
Test
itdove Jul 11, 2025
c04bacc
Add clean METRICS_UTILITY_MANDATORY_COLLECTORS env var in test
itdove Jul 14, 2025
befeaa3
Add pytest
itdove Jul 15, 2025
6e524ac
fix ruff
itdove Jul 15, 2025
2fb2f6f
Reformat
itdove Jul 15, 2025
1160b5a
Log error instead of raising exception
itdove Jul 15, 2025
2305130
Fix tests ruff
itdove Jul 15, 2025
b4ddec2
Raise exception on error
itdove Jul 15, 2025
019c8fe
Reformat
itdove Jul 15, 2025
a6de69a
ruff
itdove Jul 15, 2025
ee028ba
Add MANDATORY COLLECTORS validity
itdove Jul 18, 2025
e0dfdbf
Fix pytest
itdove Jul 18, 2025
1cd5b56
Merge remote-tracking branch 'upstream/devel' into vcpu_collector
itdove Jul 18, 2025
2233671
Fix mock config
itdove Jul 18, 2025
d8a725d
Use metrics_utility.exceptions
itdove Jul 18, 2025
588cf42
Rename METRICS_UTILITY_VCPU_COUNT_ENABLED to METRICS_UTILITY_USAGE_BA…
itdove Jul 23, 2025
15f3a23
Merge remote-tracking branch 'upstream/devel' into vcpu_collector
itdove Jul 23, 2025
4a8e241
Update pytest
itdove Jul 23, 2025
882ffee
Run ruff
itdove Jul 23, 2025
f45b9ed
Rename METRICS_UTILITY_ANSIBLE_SAAS_CLUSTER_NAME to METRICS_UTILITY_C…
itdove Jul 24, 2025
b40024d
Merge remote-tracking branch 'upstream/devel' into vcpu_collector
itdove Jul 24, 2025
b007b29
Use logging
itdove Jul 24, 2025
5e0ad14
comments
itdove Jul 24, 2025
96ea5f7
Create a new logger
itdove Jul 24, 2025
479c401
Format
itdove Jul 24, 2025
61c73f7
Fix precheck
itdove Jul 24, 2025
3f1b621
with quote in precheck
itdove Jul 24, 2025
83b4914
Fix test
itdove Jul 24, 2025
6e85e74
Use METRICS_UTILITY_DISABLE_JOB_HOST_SUMMARY_COLLECTOR
itdove Jul 24, 2025
6dde765
reformat
itdove Jul 24, 2025
ca00582
Remove METRICS_UTILITY_MANDATORY_COLLECTORS for validation
itdove Jul 24, 2025
e0936e8
Add doc in test_Containerfile
itdove Jul 25, 2025
f83975a
add test for METRICS_UTILITY_DISABLE_JOB_HOST_SUMMARY_COLLECTOR
itdove Jul 25, 2025
094f742
Remove unused local varaible
itdove Jul 25, 2025
305d04b
Add test if failed to get a kube client
itdove Jul 25, 2025
4b9e84f
Fix imports
itdove Jul 25, 2025
e00e0c6
Remove var VALID_MANDATORY_COLLECTORS
itdove Jul 25, 2025
e6a0b83
Rename VALID_OPTIONAL_COLLECTORS to its original name
itdove Jul 25, 2025
51f5f4c
Merge remote-tracking branch 'upstream/devel' into vcpu_collector
itdove Jul 28, 2025
94d19dd
ruff format
itdove Jul 28, 2025
32bf24b
safe_tarfile_member_check
itdove Jul 28, 2025
bed0b50
format
itdove Jul 28, 2025
f936eda
Fix sonar
itdove Jul 28, 2025
1f527e0
fix sonarQube
itdove Jul 28, 2025
ee64ef9
Add METRICS_UTILITY_COLLECTOR_LOCK_SUFFIX and METRICS_UTILITY_DISABLE…
itdove Jul 28, 2025
8cd4f34
REmove comments
itdove Jul 28, 2025
30a3d85
Deleting test_total_workers_vcpu_standalone.py... not needed
itdove Jul 30, 2025
180632d
Add limit_slicing
itdove Aug 1, 2025
118611f
Parenthesis
itdove Aug 1, 2025
a51d7b1
Add macos instruction
itdove Aug 5, 2025
565881a
Merge remote-tracking branch 'upstream/devel' into vcpu_collector
itdove Aug 5, 2025
35116c1
sort import
itdove Aug 5, 2025
479b756
Delete file at the end of each test
itdove Aug 5, 2025
2dca7b8
Try again
itdove Aug 5, 2025
1a89e96
Comment assert
itdove Aug 5, 2025
8a26617
revert
itdove Aug 5, 2025
8642550
comment tests
itdove Aug 5, 2025
82ec79d
Print
itdove Aug 5, 2025
efa2e2a
Catch extra exception
itdove Aug 6, 2025
ba3882e
Fix exception
itdove Aug 6, 2025
80464f9
Remove exception
itdove Aug 6, 2025
72384e1
format
itdove Aug 6, 2025
8c873ff
fix assert ruff
itdove Aug 6, 2025
2320dc8
Merge remote-tracking branch 'upstream/devel' into vcpu_collector
itdove Aug 6, 2025
353e9a8
Merge remote-tracking branch 'upstream/devel' into vcpu_collector
itdove Aug 7, 2025
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ For more flexibility, use:
- `METRICS_UTILITY_CRC_INGRESS_URL`
- `METRICS_UTILITY_CRC_SSO_URL`
- `METRICS_UTILITY_OPTIONAL_CCSP_REPORT_SHEETS`
- `METRICS_UTILITY_MANDATORY_COLLECTORS`
- `METRICS_UTILITY_OPTIONAL_COLLECTORS`
- `METRICS_UTILITY_ORGANIZATION_FILTER`
- `METRICS_UTILITY_PRICE_PER_NODE`
Expand Down
69 changes: 69 additions & 0 deletions metrics_utility/automation_controller_billing/collectors.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import json
import logging
import os
import os.path
import platform

from datetime import datetime, timezone

import distro

from awx.conf.license import get_license
Expand All @@ -11,9 +14,15 @@
from django.db import connection
from django.utils.timezone import now, timedelta
from django.utils.translation import gettext_lazy as _
from kubernetes import client
from kubernetes import config as kube_config

from metrics_utility.base import CsvFileSplitter, register
from metrics_utility.exceptions import MetricsException, MissingRequiredEnvVar


logging.basicConfig(format='%(asctime)s(+%(relativeCreated)d): %(message)s', level=logging.WARNING)
logger = logging.getLogger(__name__)

"""
This module is used to define metrics collected by
Expand All @@ -33,6 +42,10 @@ def something(since):
"""


def get_mandatory_collectors():
return os.environ.get('METRICS_UTILITY_MANDATORY_COLLECTORS', 'job_host_summary').split(',')


def get_optional_collectors():
return os.environ.get('METRICS_UTILITY_OPTIONAL_COLLECTORS', 'main_jobevent').split(',')

Expand Down Expand Up @@ -205,6 +218,9 @@ def yaml_and_json_parsing_functions():

@register('job_host_summary', '1.2', format='csv', description=_('Data for billing'), fnc_slicing=daily_slicing)
def job_host_summary_table(since, full_path, until, **kwargs):
if 'job_host_summary' not in get_mandatory_collectors():
return None

# TODO: controler needs to have an index on main_jobhostsummary.modified
prepend_query = """
-- Define function for parsing field out of yaml encoded as text
Expand Down Expand Up @@ -464,3 +480,56 @@ def main_host_table(since, full_path, until, **kwargs):
return _copy_table(
table='main_host', query=f'COPY ({query}) TO STDOUT WITH CSV HEADER', path=full_path, prepend_query=yaml_and_json_parsing_functions()
)


@register('total_workers_vcpu', '1.0', format='json', description=_('Total workers vCPU'))
def total_workers_vcpu(since, full_path, until, **kwargs):
if 'total_workers_vcpu' not in get_optional_collectors():
Comment thread
itdove marked this conversation as resolved.
return None

cluster_name = os.environ.get('METRICS_UTILITY_ANSIBLE_SAAS_CLUSTER_NAME')
Comment thread
itdove marked this conversation as resolved.
Outdated
if not cluster_name:
logger.error('environment variable METRICS_UTILITY_ANSIBLE_SAAS_CLUSTER_NAME is not set')
raise MissingRequiredEnvVar('environment variable METRICS_UTILITY_ANSIBLE_SAAS_CLUSTER_NAME is not set')

now = datetime.now(timezone.utc)

info = {'cluster_name': cluster_name, 'timestamp': now.isoformat(), 'nodes': []}

# If METRICS_UTILITY_VCPU_COUNT_ENABLED is not set or not set to true then it returns 1
vcpu_count_enabled_str = os.environ.get('METRICS_UTILITY_VCPU_COUNT_ENABLED')
Comment thread
itdove marked this conversation as resolved.
Outdated
vcpu_count_enabled = False
if vcpu_count_enabled_str and (vcpu_count_enabled_str.lower() == 'true'):
vcpu_count_enabled = True
if not vcpu_count_enabled:
return {'cluster_name': info['cluster_name'], 'total_workers_vcpu': '1'}
Comment thread
itdove marked this conversation as resolved.
Outdated

try:
kube_config.load_incluster_config()
except kube_config.ConfigException:
try:
kube_config.load_kube_config()
except kube_config.ConfigException as e:
logger.error(f'Could not configure Kubernetes Python client ERROR: {e}')
raise MetricsException(f'Could not configure Kubernetes Python client ERROR: {e}')

# Create a CoreV1Api client
api_instance = client.CoreV1Api()

nodes = api_instance.list_node()
Comment thread
itdove marked this conversation as resolved.
Outdated

total_workers_vcpu = 0
for node_info in nodes.items:
Comment thread
itdove marked this conversation as resolved.
for resource, value in node_info.status.capacity.items():
if resource == 'cpu':
info['nodes'].append({node_info.metadata.name: int(value)})
total_workers_vcpu += int(value)

info['total_workers_vcpu'] = total_workers_vcpu

logger_info = logging.getLogger(__name__)
logger_info.setLevel(logging.INFO)

logger_info.info(json.dumps(info, indent=2))

return {'cluster_name': info['cluster_name'], 'total_workers_vcpu': info['total_workers_vcpu']}
1 change: 1 addition & 0 deletions metrics_utility/base/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def __init__(self, collector, fnc_collecting):
self.version = fnc_collecting.__insights_analytics_version__

self.data_type = fnc_collecting.__insights_analytics_type__

self.filename = f'{self.key}.{self.data_type}'
# either since/until or full sync(if enabled)
self.since = None # set by Collector._create_collections()
Expand Down
26 changes: 21 additions & 5 deletions metrics_utility/management/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@
'managed_nodes_by_organizations',
},
}
VALID_COLLECTORS = {'main_host', 'main_jobevent', 'main_indirectmanagednodeaudit'}
VALID_OPTIONAL_COLLECTORS = {'main_host', 'main_jobevent', 'main_indirectmanagednodeaudit', 'total_workers_vcpu'}
VALID_MANDATORY_COLLECTORS = {'job_host_summary'}
VALID_SHIP_TARGET_BUILD = {'directory', 's3', 'controller_db'}
VALID_SHIP_TARGET_GATHER = {'directory', 's3', 'crc'}

Expand Down Expand Up @@ -222,18 +223,33 @@ def validate_collectors(errors):
Environment Variables:
METRICS_UTILITY_OPTIONAL_COLLECTORS (str, optional): Comma-separated
list of collector names. Defaults to 'main_jobevent' if not set.
METRICS_UTILITY_MANDATORY_COLLECTORS (str, optional): Comma-separated
Comment thread
itdove marked this conversation as resolved.
Outdated
list of collector names. Defaults to 'main_jobevent' if not set.
Comment thread
itdove marked this conversation as resolved.
Outdated

Notes:
- The set of valid collectors is defined by the global variable
VALID_COLLECTORS.
- The set of valid optional collectors is defined by the global variable
VALID_OPTIONAL_COLLECTORS.
- The set of valid mandatory collectors is defined by the global variable
VALID_MANDATORY_COLLECTORS.
- Error messages include the invalid collector names and the list of
valid values.
"""
collectors_env_var = os.environ.get('METRICS_UTILITY_MANDATORY_COLLECTORS')
if collectors_env_var:
collectors = collectors_env_var.split(',')
if collectors:
invalid = set(collectors) - VALID_MANDATORY_COLLECTORS
if invalid:
errors.append(
f'Invalid METRICS_UTILITY_MANDATORY_COLLECTORS: \
{", ".join(invalid)}. Valid values: {", ".join(VALID_MANDATORY_COLLECTORS)}'
)

collectors = os.environ.get('METRICS_UTILITY_OPTIONAL_COLLECTORS', 'main_jobevent').split(',')
if collectors:
invalid = set(collectors) - VALID_COLLECTORS
invalid = set(collectors) - VALID_OPTIONAL_COLLECTORS
if invalid:
errors.append(f'Invalid METRICS_UTILITY_OPTIONAL_COLLECTORS: {", ".join(invalid)}. Valid values: {", ".join(VALID_COLLECTORS)}')
errors.append(f'Invalid METRICS_UTILITY_OPTIONAL_COLLECTORS: {", ".join(invalid)}. Valid values: {", ".join(VALID_OPTIONAL_COLLECTORS)}')


def validate_ship_target(errors, method):
Expand Down
Loading