feat(models): add resource utilization methods for hosts and workloads

Add get_resource_utilization to WorkloadHost to compute available and used
resources dynamically from pooled resources and active workloads.

Add get_resource_usage to Workload to return list of used resources for the
workload.

Fix minor typo in TODO comment and add SQLAlchemy func import.
This commit is contained in:
2025-10-26 23:11:05 +10:30
parent 0989a66198
commit e31fda6220
+56 -5
View File
@@ -1,7 +1,7 @@
import uuid
from datetime import datetime
from sqlalchemy import (
Column, String, Boolean, DateTime, ForeignKey, Integer, Float, Text, Enum, event, inspect
Column, String, Boolean, DateTime, ForeignKey, Integer, Float, Text, Enum, event, inspect, func
)
import sqlalchemy
from sqlalchemy.dialects.mysql import LONGTEXT
@@ -387,8 +387,46 @@ class WorkloadHost(BaseModel):
"vni": port.network.vni,
"workload_host_ip": port.workload.workload_host.ip_address_eastwest
})
return sdn_payload
return sdn_payload
def get_resource_utilization(self):
"""
Computes resource utilization for this workload host.
Returns a dictionary with resource types as keys, containing available and used quantities.
Dynamically based on WorkloadHostPooledResource entries for this host.
"""
resources = {}
# Get all pooled resources for this host
pooled_resources = self.pooled_resources
for pooled in pooled_resources:
resource_type = pooled.resource_type
total_quantity = pooled.total_quantity
# Sum usage from non-deleted workloads on this host for this resource type
used_query = db.session.query(
func.sum(WorkloadResourceUsage.quantity).label('total_used')
).outerjoin(
Workload, Workload.id == WorkloadResourceUsage.workload_id
).filter(
WorkloadResourceUsage.resource_type == resource_type,
Workload.workload_host_id == self.id,
Workload.deleted == False
)
quantity_in_use = used_query.scalar() or 0.0
resources[resource_type] = {
'total_quantity': float(total_quantity),
'quantity_in_use': float(quantity_in_use)
}
return {
'resources': resources
}
class WorkloadHostAvailablePort(BaseModel):
__tablename__ = "workload_host_available_ports"
@@ -672,9 +710,9 @@ class Workload(BaseModel):
Special handler for failed containers
"""
try:
# TODO - What if this is a host failure? Do we just handle every container inviddually or should we aggregate
# TODO - What if this is a host failure? Do we just handle every container inviddually or should we aggregate
# the event into a host failure event and handle it more intelligently(Might be harder?)
# Attempt to rebuild in place
# container.rebuild_in_place()
logger.warning("Rebuilding container in place after failure")
@@ -697,6 +735,19 @@ class Workload(BaseModel):
)
raise
def get_resource_usage(self):
"""
Returns the resource usage for this workload as a list of dicts.
"""
usages = WorkloadResourceUsage.query.filter_by(workload_id=self.id).all()
return [
{
"name": usage.resource_type,
"used_amount": float(usage.quantity)
}
for usage in usages
]
class WorkloadHostPortMapping(db.Model):
"""
Maps container internal ports to external ports on the workload host.