Просмотр исходного кода

First stab at power utilization tracking

Jeremy Stretch 6 лет назад
Родитель
Сommit
ac3e899f5e
2 измененных файлов с 86 добавлено и 1 удалено
  1. 43 1
      netbox/dcim/models.py
  2. 43 0
      netbox/templates/dcim/device.html

+ 43 - 1
netbox/dcim/models.py

@@ -9,7 +9,7 @@ from django.contrib.postgres.fields import ArrayField, JSONField
 from django.core.exceptions import ObjectDoesNotExist, ValidationError
 from django.core.exceptions import ObjectDoesNotExist, ValidationError
 from django.core.validators import MaxValueValidator, MinValueValidator
 from django.core.validators import MaxValueValidator, MinValueValidator
 from django.db import models
 from django.db import models
-from django.db.models import Count, Q
+from django.db.models import Count, Q, Sum
 from django.urls import reverse
 from django.urls import reverse
 from mptt.models import MPTTModel, TreeForeignKey
 from mptt.models import MPTTModel, TreeForeignKey
 from taggit.managers import TaggableManager
 from taggit.managers import TaggableManager
@@ -1938,6 +1938,41 @@ class PowerPort(CableTermination, ComponentModel):
                 "Connected endpoint must be a PowerOutlet or PowerFeed, not {}.".format(type(value))
                 "Connected endpoint must be a PowerOutlet or PowerFeed, not {}.".format(type(value))
             )
             )
 
 
+    def get_power_stats(self):
+        """
+        Return power utilization statistics
+        """
+        feed = self._connected_powerfeed
+        if not feed or not self.poweroutlets.count():
+            return None
+
+        stats = []
+        powerfeed_available = self._connected_powerfeed.available_power
+
+        outlet_ids = PowerOutlet.objects.filter(power_port=self).values_list('pk', flat=True)
+        utilization = PowerPort.objects.filter(_connected_poweroutlet_id__in=outlet_ids).aggregate(
+            maximum_draw=Sum('maximum_draw'),
+            allocated_draw=Sum('allocated_draw'),
+        )
+        utilization['outlets'] = len(outlet_ids)
+        utilization['available_power'] = powerfeed_available
+        stats.append(utilization)
+
+        # Per-leg stats for three-phase feeds
+        if feed.phase == POWERFEED_PHASE_3PHASE:
+            for leg, leg_name in POWERFEED_LEG_CHOICES:
+                outlet_ids = PowerOutlet.objects.filter(power_port=self, feed_leg=leg).values_list('pk', flat=True)
+                utilization = PowerPort.objects.filter(_connected_poweroutlet_id__in=outlet_ids).aggregate(
+                    maximum_draw=Sum('maximum_draw'),
+                    allocated_draw=Sum('allocated_draw'),
+                )
+                utilization['name'] = 'Leg {}'.format(leg_name)
+                utilization['outlets'] = len(outlet_ids)
+                utilization['available_power'] = powerfeed_available / 3
+                stats.append(utilization)
+
+        return stats
+
 
 
 #
 #
 # Power outlets
 # Power outlets
@@ -2923,3 +2958,10 @@ class PowerFeed(ChangeLoggedModel, CableTermination, CustomFieldModel):
 
 
     def get_status_class(self):
     def get_status_class(self):
         return STATUS_CLASSES[self.status]
         return STATUS_CLASSES[self.status]
+
+    @property
+    def available_power(self):
+        kva = self.voltage * self.amperage * self.max_utilization
+        if self.phase == POWERFEED_PHASE_3PHASE:
+            return kva * 1.732
+        return kva

+ 43 - 0
netbox/templates/dcim/device.html

@@ -332,6 +332,49 @@
                     {% endif %}
                     {% endif %}
                 </div>
                 </div>
             {% endif %}
             {% endif %}
+            {% if power_ports and poweroutlets %}
+                <div class="panel panel-default">
+                    <div class="panel-heading">
+                        <strong>Power Utilization</strong>
+                    </div>
+                    <table class="table table-hover panel-body">
+                        <tr>
+                            <th>Input</th>
+                            <th>Outlets</th>
+                            <th>Allocated/Max (W)</th>
+                            <th>Available (VA)</th>
+                        </tr>
+                        {% for pp in power_ports %}
+                            {% for leg in pp.get_power_stats %}
+                                <tr>
+                                    {% if leg.name %}
+                                        <td style="padding-left: 20px">{{ leg.name }}</td>
+                                    {% else %}
+                                        <td>{{ pp }}</td>
+                                    {% endif %}
+                                    <td>{{ leg.outlets|placeholder }}</td>
+                                    <td>{{ leg.allocated_draw }} / {{ leg.maximum_draw }}</td>
+                                    <td>{{ leg.available_power }}</td>
+                                </tr>
+                            {% endfor %}
+                        {% endfor %}
+                    </table>
+                    {% if perms.dcim.add_interface or perms.dcim.add_consoleport or perms.dcim.add_powerport %}
+                        <div class="panel-footer text-right noprint">
+                            {% if perms.dcim.add_consoleport %}
+                                <a href="{% url 'dcim:consoleport_add' pk=device.pk %}" class="btn btn-xs btn-primary">
+                                    <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add console port
+                                </a>
+                            {% endif %}
+                            {% if perms.dcim.add_powerport %}
+                                <a href="{% url 'dcim:powerport_add' pk=device.pk %}" class="btn btn-xs btn-primary">
+                                    <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add power port
+                                </a>
+                            {% endif %}
+                        </div>
+                    {% endif %}
+                </div>
+            {% endif %}
             {% if request.user.is_authenticated %}
             {% if request.user.is_authenticated %}
                 <div class="panel panel-default">
                 <div class="panel panel-default">
                     <div class="panel-heading">
                     <div class="panel-heading">