diff --git a/netbox/dcim/models/racks.py b/netbox/dcim/models/racks.py index 9b05d8026..63e545abc 100644 --- a/netbox/dcim/models/racks.py +++ b/netbox/dcim/models/racks.py @@ -22,7 +22,7 @@ from utilities.choices import ColorChoices from utilities.fields import ColorField, NaturalOrderingField from utilities.querysets import RestrictedQuerySet from utilities.mptt import TreeManager -from utilities.utils import array_to_string, serialize_object +from utilities.utils import array_to_string, serialize_object, UtilizationData from .device_components import PowerOutlet, PowerPort from .devices import Device from .power import PowerFeed @@ -505,9 +505,10 @@ class Rack(ChangeLoggedModel, CustomFieldModel): return self.devices.filter(position=0) def get_utilization(self): - """ - Determine the utilization rate of the rack and return it as a percentage. Occupied and reserved units both count - as utilized. + """Gets utilization numerator and denominator for racks. + + Returns: + UtilizationData: (numerator=Occupied Unit Count, denominator=U Height of the rack) """ # Determine unoccupied units available_units = self.get_available_units() @@ -517,19 +518,19 @@ class Rack(ChangeLoggedModel, CustomFieldModel): if u in available_units: available_units.remove(u) - occupied_unit_count = self.u_height - len(available_units) - # Return the numerator and denominator as percentage is to be calculated later where needed - return (occupied_unit_count, self.u_height) + return UtilizationData(numerator=self.u_height - len(available_units), denominator=self.u_height) def get_power_utilization(self): - """ - Determine the utilization rate of power in the rack and return it as a percentage. + """Determine the utilization numerator and denominator for power utilization on the rack. + + Returns: + UtilizationData: (numerator, denominator) """ powerfeeds = PowerFeed.objects.filter(rack=self) available_power_total = sum(pf.available_power for pf in powerfeeds) if not available_power_total: - return (0, 0) + return UtilizationData(numerator=0, denominator=0) pf_powerports = PowerPort.objects.filter( _cable_peer_type=ContentType.objects.get_for_model(PowerFeed), @@ -541,7 +542,7 @@ class Rack(ChangeLoggedModel, CustomFieldModel): _cable_peer_id__in=poweroutlets.values_list('id', flat=True) ).aggregate(Sum('allocated_draw'))['allocated_draw__sum'] or 0 - return (allocated_draw_total, available_power_total) + return UtilizationData(numerator=allocated_draw_total, denominator=available_power_total) @extras_features('custom_fields', 'custom_links', 'export_templates', 'webhooks') diff --git a/netbox/dcim/tables/template_code.py b/netbox/dcim/tables/template_code.py index 1f67c5d7d..67675e468 100644 --- a/netbox/dcim/tables/template_code.py +++ b/netbox/dcim/tables/template_code.py @@ -82,9 +82,10 @@ RACKGROUP_ELEVATIONS = """ """ +# Value is a namedtuple that takes a numerator and denominator to pass in. UTILIZATION_GRAPH = """ {% load helpers %} -{% utilization_graph value.0 value.1 %} +{% utilization_graph value %} """ # diff --git a/netbox/ipam/models.py b/netbox/ipam/models.py index af950b149..dcd9f248d 100644 --- a/netbox/ipam/models.py +++ b/netbox/ipam/models.py @@ -14,7 +14,7 @@ from dcim.models import Device, Interface from extras.models import ChangeLoggedModel, CustomFieldModel, ObjectChange, TaggedItem from extras.utils import extras_features from utilities.querysets import RestrictedQuerySet -from utilities.utils import array_to_string, serialize_object +from utilities.utils import array_to_string, serialize_object, UtilizationData from virtualization.models import VirtualMachine, VMInterface from .choices import * from .constants import * @@ -308,13 +308,26 @@ class Aggregate(ChangeLoggedModel, CustomFieldModel): return self.prefix.version return None - def get_utilization(self): + + def get_percent_utilized(self): + """Gets the percentage utilized from the get_utilization method. + + Returns + float: Percentage utilization """ - Determine the prefix utilization of the aggregate and return it as a percentage. + utilization = self.get_utilization() + return int(utilization.numerator / float(utilization.denominator) * 100) + + + def get_utilization(self): + """Gets the numerator and denominator for calculating utilization of an Aggregrate. + Returns: + UtilizationData: Aggregate utilization (numerator=size of child prefixes, denominator=prefix size) """ queryset = Prefix.objects.filter(prefix__net_contained_or_equal=str(self.prefix)) child_prefixes = netaddr.IPSet([p.prefix for p in queryset]) - return (child_prefixes.size, self.prefix.size) + + return UtilizationData(numerator=child_prefixes.size, denominator=self.prefix.size) class Role(ChangeLoggedModel): @@ -595,24 +608,25 @@ class Prefix(ChangeLoggedModel, CustomFieldModel): return '{}/{}'.format(next(available_ips.__iter__()), self.prefix.prefixlen) def get_utilization(self): + """Get the child prefix size and parent size. + + For Prefixes with a status of "container", get the number child prefixes. For all others, count child IP addresses. + + Returns: + UtilizationData (namedtuple): (numerator, denominator) """ - Get the child prefix size and parent prefix size return them as a tuple. For Prefixes with a status of - "container", get the number child prefixes. For all others, count child IP addresses. - """ - if self.status == PrefixStatusChoices.STATUS_CONTAINER: - queryset = Prefix.objects.filter( - prefix__net_contained=str(self.prefix), - vrf=self.vrf - ) + if self.status == Prefix.STATUS_CONTAINER: + queryset = Prefix.objects.filter(prefix__net_contained=str(self.prefix), vrf=self.vrf) child_prefixes = netaddr.IPSet([p.prefix for p in queryset]) - return (child_prefixes.size, self.prefix.size) + return UtilizationData(numerator=child_prefixes.size, denominator=self.prefix.size) + else: # Compile an IPSet to avoid counting duplicate IPs child_count = netaddr.IPSet([ip.address.ip for ip in self.get_child_ips()]).size prefix_size = self.prefix.size if self.prefix.version == 4 and self.prefix.prefixlen < 31 and not self.is_pool: prefix_size -= 2 - return (child_count, prefix_size) + return UtilizationData(numerator=child_count, denominator=prefix_size) @extras_features('custom_fields', 'custom_links', 'export_templates', 'webhooks') diff --git a/netbox/templates/dcim/device.html b/netbox/templates/dcim/device.html index 70c515f9a..e0a711a4d 100644 --- a/netbox/templates/dcim/device.html +++ b/netbox/templates/dcim/device.html @@ -225,7 +225,7 @@