mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
More power work
This commit is contained in:
@ -3,8 +3,8 @@ from rest_framework import serializers
|
|||||||
from dcim.constants import CONNECTION_STATUS_CHOICES
|
from dcim.constants import CONNECTION_STATUS_CHOICES
|
||||||
from dcim.models import (
|
from dcim.models import (
|
||||||
Cable, ConsolePort, ConsoleServerPort, Device, DeviceBay, DeviceType, DeviceRole, FrontPort, FrontPortTemplate,
|
Cable, ConsolePort, ConsoleServerPort, Device, DeviceBay, DeviceType, DeviceRole, FrontPort, FrontPortTemplate,
|
||||||
Interface, Manufacturer, Platform, PowerOutlet, PowerPort, Rack, RackGroup, RackRole, RearPort, RearPortTemplate,
|
Interface, Manufacturer, Platform, PowerFeed, PowerOutlet, PowerPanel, PowerPort, Rack, RackGroup, RackRole,
|
||||||
Region, Site, VirtualChassis,
|
RearPort, RearPortTemplate, Region, Site, VirtualChassis,
|
||||||
)
|
)
|
||||||
from utilities.api import ChoiceField, WritableNestedSerializer
|
from utilities.api import ChoiceField, WritableNestedSerializer
|
||||||
|
|
||||||
@ -21,7 +21,9 @@ __all__ = [
|
|||||||
'NestedInterfaceSerializer',
|
'NestedInterfaceSerializer',
|
||||||
'NestedManufacturerSerializer',
|
'NestedManufacturerSerializer',
|
||||||
'NestedPlatformSerializer',
|
'NestedPlatformSerializer',
|
||||||
|
'NestedPowerFeedSerializer',
|
||||||
'NestedPowerOutletSerializer',
|
'NestedPowerOutletSerializer',
|
||||||
|
'NestedPowerPanelSerializer',
|
||||||
'NestedPowerPortSerializer',
|
'NestedPowerPortSerializer',
|
||||||
'NestedRackGroupSerializer',
|
'NestedRackGroupSerializer',
|
||||||
'NestedRackRoleSerializer',
|
'NestedRackRoleSerializer',
|
||||||
@ -247,3 +249,23 @@ class NestedVirtualChassisSerializer(WritableNestedSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualChassis
|
model = VirtualChassis
|
||||||
fields = ['id', 'url', 'master']
|
fields = ['id', 'url', 'master']
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Power panels/feeds
|
||||||
|
#
|
||||||
|
|
||||||
|
class NestedPowerPanelSerializer(serializers.ModelSerializer):
|
||||||
|
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerpanel-detail')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = PowerPanel
|
||||||
|
fields = ['id', 'url', 'name']
|
||||||
|
|
||||||
|
|
||||||
|
class NestedPowerFeedSerializer(serializers.ModelSerializer):
|
||||||
|
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerfeed-detail')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = PowerFeed
|
||||||
|
fields = ['id', 'url', 'name']
|
||||||
|
@ -7,8 +7,9 @@ from dcim.constants import *
|
|||||||
from dcim.models import (
|
from dcim.models import (
|
||||||
Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
|
Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
|
||||||
DeviceBayTemplate, DeviceType, DeviceRole, FrontPort, FrontPortTemplate, Interface, InterfaceTemplate,
|
DeviceBayTemplate, DeviceType, DeviceRole, FrontPort, FrontPortTemplate, Interface, InterfaceTemplate,
|
||||||
Manufacturer, InventoryItem, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack,
|
Manufacturer, InventoryItem, Platform, PowerFeed, PowerOutlet, PowerOutletTemplate, PowerPanel, PowerPort,
|
||||||
RackGroup, RackReservation, RackRole, RearPort, RearPortTemplate, Region, Site, VirtualChassis,
|
PowerPortTemplate, Rack, RackGroup, RackReservation, RackRole, RearPort, RearPortTemplate, Region, Site,
|
||||||
|
VirtualChassis,
|
||||||
)
|
)
|
||||||
from extras.api.customfields import CustomFieldModelSerializer
|
from extras.api.customfields import CustomFieldModelSerializer
|
||||||
from ipam.api.nested_serializers import NestedIPAddressSerializer, NestedVLANSerializer
|
from ipam.api.nested_serializers import NestedIPAddressSerializer, NestedVLANSerializer
|
||||||
@ -587,3 +588,56 @@ class VirtualChassisSerializer(TaggitSerializer, ValidatedModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualChassis
|
model = VirtualChassis
|
||||||
fields = ['id', 'master', 'domain', 'tags']
|
fields = ['id', 'master', 'domain', 'tags']
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Power panels
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
class PowerPanelSerializer(ValidatedModelSerializer):
|
||||||
|
site = NestedSiteSerializer()
|
||||||
|
rack_group = NestedRackGroupSerializer(
|
||||||
|
required=False,
|
||||||
|
allow_null=True,
|
||||||
|
default=None
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = PowerPanel
|
||||||
|
fields = ['id', 'site', 'rack_group', 'name']
|
||||||
|
|
||||||
|
|
||||||
|
class PowerFeedSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||||
|
power_panel = NestedPowerPanelSerializer()
|
||||||
|
rack = NestedRackSerializer(
|
||||||
|
required=False,
|
||||||
|
allow_null=True,
|
||||||
|
default=None
|
||||||
|
)
|
||||||
|
type = ChoiceField(
|
||||||
|
choices=POWERFEED_TYPE_CHOICES,
|
||||||
|
default=POWERFEED_TYPE_PRIMARY
|
||||||
|
)
|
||||||
|
status = ChoiceField(
|
||||||
|
choices=POWERFEED_STATUS_CHOICES,
|
||||||
|
default=POWERFEED_STATUS_ACTIVE
|
||||||
|
)
|
||||||
|
supply = ChoiceField(
|
||||||
|
choices=POWERFEED_SUPPLY_CHOICES,
|
||||||
|
default=POWERFEED_SUPPLY_AC
|
||||||
|
)
|
||||||
|
phase = ChoiceField(
|
||||||
|
choices=POWERFEED_PHASE_CHOICES,
|
||||||
|
default=POWERFEED_PHASE_SINGLE
|
||||||
|
)
|
||||||
|
tags = TagListSerializerField(
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = PowerFeed
|
||||||
|
fields = [
|
||||||
|
'id', 'power_panel', 'rack', 'name', 'status', 'type', 'supply', 'phase', 'voltage', 'amperage',
|
||||||
|
'max_utilization', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
|
||||||
|
]
|
||||||
|
@ -68,6 +68,10 @@ router.register(r'cables', views.CableViewSet)
|
|||||||
# Virtual chassis
|
# Virtual chassis
|
||||||
router.register(r'virtual-chassis', views.VirtualChassisViewSet)
|
router.register(r'virtual-chassis', views.VirtualChassisViewSet)
|
||||||
|
|
||||||
|
# Power
|
||||||
|
router.register(r'power-panels', views.PowerPanelViewSet)
|
||||||
|
router.register(r'power-feeds', views.PowerFeedViewSet)
|
||||||
|
|
||||||
# Miscellaneous
|
# Miscellaneous
|
||||||
router.register(r'connected-device', views.ConnectedDeviceViewSet, basename='connected-device')
|
router.register(r'connected-device', views.ConnectedDeviceViewSet, basename='connected-device')
|
||||||
|
|
||||||
|
@ -16,8 +16,9 @@ from dcim import filters
|
|||||||
from dcim.models import (
|
from dcim.models import (
|
||||||
Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
|
Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
|
||||||
DeviceBayTemplate, DeviceRole, DeviceType, FrontPort, FrontPortTemplate, Interface, InterfaceTemplate,
|
DeviceBayTemplate, DeviceRole, DeviceType, FrontPort, FrontPortTemplate, Interface, InterfaceTemplate,
|
||||||
Manufacturer, InventoryItem, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack,
|
Manufacturer, InventoryItem, Platform, PowerFeed, PowerOutlet, PowerOutletTemplate, PowerPanel, PowerPort,
|
||||||
RackGroup, RackReservation, RackRole, RearPort, RearPortTemplate, Region, Site, VirtualChassis,
|
PowerPortTemplate, Rack, RackGroup, RackReservation, RackRole, RearPort, RearPortTemplate, Region, Site,
|
||||||
|
VirtualChassis,
|
||||||
)
|
)
|
||||||
from extras.api.serializers import RenderedGraphSerializer
|
from extras.api.serializers import RenderedGraphSerializer
|
||||||
from extras.api.views import CustomFieldModelViewSet
|
from extras.api.views import CustomFieldModelViewSet
|
||||||
@ -534,6 +535,26 @@ class VirtualChassisViewSet(ModelViewSet):
|
|||||||
serializer_class = serializers.VirtualChassisSerializer
|
serializer_class = serializers.VirtualChassisSerializer
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Power panels
|
||||||
|
#
|
||||||
|
|
||||||
|
class PowerPanelViewSet(ModelViewSet):
|
||||||
|
queryset = PowerPanel.objects.all()
|
||||||
|
serializer_class = serializers.PowerPanelSerializer
|
||||||
|
# filterset_class = filters.PowerPanelFilter
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Power feeds
|
||||||
|
#
|
||||||
|
|
||||||
|
class PowerFeedViewSet(ModelViewSet):
|
||||||
|
queryset = PowerFeed.objects.all()
|
||||||
|
serializer_class = serializers.PowerFeedSerializer
|
||||||
|
# filterset_class = filters.PowerFeedFilter
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Miscellaneous
|
# Miscellaneous
|
||||||
#
|
#
|
||||||
|
@ -448,8 +448,8 @@ RACK_DIMENSION_UNIT_CHOICES = (
|
|||||||
POWERFEED_TYPE_PRIMARY = 1
|
POWERFEED_TYPE_PRIMARY = 1
|
||||||
POWERFEED_TYPE_REDUNDANT = 2
|
POWERFEED_TYPE_REDUNDANT = 2
|
||||||
POWERFEED_TYPE_CHOICES = (
|
POWERFEED_TYPE_CHOICES = (
|
||||||
(POWERFEED_TYPE_PRIMARY, 'AC'),
|
(POWERFEED_TYPE_PRIMARY, 'Primary'),
|
||||||
(POWERFEED_TYPE_REDUNDANT, 'DC'),
|
(POWERFEED_TYPE_REDUNDANT, 'Redundant'),
|
||||||
)
|
)
|
||||||
POWERFEED_SUPPLY_AC = 1
|
POWERFEED_SUPPLY_AC = 1
|
||||||
POWERFEED_SUPPLY_DC = 2
|
POWERFEED_SUPPLY_DC = 2
|
||||||
|
@ -3183,7 +3183,7 @@ class PowerPanelForm(BootstrapMixin, forms.ModelForm):
|
|||||||
'site': APISelect(
|
'site': APISelect(
|
||||||
api_url="/api/dcim/sites/",
|
api_url="/api/dcim/sites/",
|
||||||
filter_for={
|
filter_for={
|
||||||
'rackgroup': 'site_id',
|
'rack_group': 'site_id',
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
@ -3231,7 +3231,7 @@ class PowerFeedForm(BootstrapMixin, CustomFieldForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = PowerFeed
|
model = PowerFeed
|
||||||
fields = [
|
fields = [
|
||||||
'site', 'power_panel', 'rack', 'name', 'type', 'status', 'supply', 'voltage', 'amperage', 'phase',
|
'site', 'power_panel', 'rack', 'name', 'status', 'type', 'supply', 'phase', 'voltage', 'amperage',
|
||||||
'max_utilization', 'comments', 'tags',
|
'max_utilization', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
@ -3241,24 +3241,24 @@ class PowerFeedForm(BootstrapMixin, CustomFieldForm):
|
|||||||
'rack': APISelect(
|
'rack': APISelect(
|
||||||
api_url="/api/dcim/racks/"
|
api_url="/api/dcim/racks/"
|
||||||
),
|
),
|
||||||
'type': StaticSelect2(),
|
|
||||||
'status': StaticSelect2(),
|
'status': StaticSelect2(),
|
||||||
|
'type': StaticSelect2(),
|
||||||
'supply': StaticSelect2(),
|
'supply': StaticSelect2(),
|
||||||
'phase': StaticSelect2(),
|
'phase': StaticSelect2(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PowerFeedCSVForm(forms.ModelForm):
|
class PowerFeedCSVForm(forms.ModelForm):
|
||||||
type = CSVChoiceField(
|
|
||||||
choices=POWERFEED_TYPE_CHOICES,
|
|
||||||
required=False,
|
|
||||||
help_text='Primary or redundant'
|
|
||||||
)
|
|
||||||
status = CSVChoiceField(
|
status = CSVChoiceField(
|
||||||
choices=POWERFEED_STATUS_CHOICES,
|
choices=POWERFEED_STATUS_CHOICES,
|
||||||
required=False,
|
required=False,
|
||||||
help_text='Operational status'
|
help_text='Operational status'
|
||||||
)
|
)
|
||||||
|
type = CSVChoiceField(
|
||||||
|
choices=POWERFEED_TYPE_CHOICES,
|
||||||
|
required=False,
|
||||||
|
help_text='Primary or redundant'
|
||||||
|
)
|
||||||
supply = CSVChoiceField(
|
supply = CSVChoiceField(
|
||||||
choices=POWERFEED_SUPPLY_CHOICES,
|
choices=POWERFEED_SUPPLY_CHOICES,
|
||||||
required=False,
|
required=False,
|
||||||
@ -3292,14 +3292,14 @@ class PowerFeedBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEd
|
|||||||
api_url="/api/dcim/rack-groups",
|
api_url="/api/dcim/rack-groups",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
type = forms.ChoiceField(
|
status = forms.ChoiceField(
|
||||||
choices=add_blank_choice(POWERFEED_TYPE_CHOICES),
|
choices=add_blank_choice(POWERFEED_STATUS_CHOICES),
|
||||||
required=False,
|
required=False,
|
||||||
initial='',
|
initial='',
|
||||||
widget=StaticSelect2()
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
status = forms.ChoiceField(
|
type = forms.ChoiceField(
|
||||||
choices=add_blank_choice(POWERFEED_STATUS_CHOICES),
|
choices=add_blank_choice(POWERFEED_TYPE_CHOICES),
|
||||||
required=False,
|
required=False,
|
||||||
initial='',
|
initial='',
|
||||||
widget=StaticSelect2()
|
widget=StaticSelect2()
|
||||||
@ -3310,18 +3310,18 @@ class PowerFeedBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEd
|
|||||||
initial='',
|
initial='',
|
||||||
widget=StaticSelect2()
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
voltage = forms.IntegerField(
|
|
||||||
required=False
|
|
||||||
)
|
|
||||||
amperage = forms.IntegerField(
|
|
||||||
required=False
|
|
||||||
)
|
|
||||||
phase = forms.ChoiceField(
|
phase = forms.ChoiceField(
|
||||||
choices=add_blank_choice(POWERFEED_PHASE_CHOICES),
|
choices=add_blank_choice(POWERFEED_PHASE_CHOICES),
|
||||||
required=False,
|
required=False,
|
||||||
initial='',
|
initial='',
|
||||||
widget=StaticSelect2()
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
|
voltage = forms.IntegerField(
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
amperage = forms.IntegerField(
|
||||||
|
required=False
|
||||||
|
)
|
||||||
max_utilization = forms.IntegerField(
|
max_utilization = forms.IntegerField(
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
@ -2730,18 +2730,22 @@ class PowerFeed(ChangeLoggedModel, CustomFieldModel):
|
|||||||
name = models.CharField(
|
name = models.CharField(
|
||||||
max_length=50
|
max_length=50
|
||||||
)
|
)
|
||||||
type = models.PositiveSmallIntegerField(
|
|
||||||
choices=POWERFEED_TYPE_CHOICES,
|
|
||||||
default=POWERFEED_TYPE_PRIMARY
|
|
||||||
)
|
|
||||||
status = models.PositiveSmallIntegerField(
|
status = models.PositiveSmallIntegerField(
|
||||||
choices=POWERFEED_STATUS_CHOICES,
|
choices=POWERFEED_STATUS_CHOICES,
|
||||||
default=POWERFEED_STATUS_ACTIVE
|
default=POWERFEED_STATUS_ACTIVE
|
||||||
)
|
)
|
||||||
|
type = models.PositiveSmallIntegerField(
|
||||||
|
choices=POWERFEED_TYPE_CHOICES,
|
||||||
|
default=POWERFEED_TYPE_PRIMARY
|
||||||
|
)
|
||||||
supply = models.PositiveSmallIntegerField(
|
supply = models.PositiveSmallIntegerField(
|
||||||
choices=POWERFEED_SUPPLY_CHOICES,
|
choices=POWERFEED_SUPPLY_CHOICES,
|
||||||
default=POWERFEED_SUPPLY_AC
|
default=POWERFEED_SUPPLY_AC
|
||||||
)
|
)
|
||||||
|
phase = models.PositiveSmallIntegerField(
|
||||||
|
choices=POWERFEED_PHASE_CHOICES,
|
||||||
|
default=POWERFEED_PHASE_SINGLE
|
||||||
|
)
|
||||||
voltage = models.PositiveSmallIntegerField(
|
voltage = models.PositiveSmallIntegerField(
|
||||||
validators=[MinValueValidator(1)],
|
validators=[MinValueValidator(1)],
|
||||||
default=120
|
default=120
|
||||||
@ -2750,10 +2754,6 @@ class PowerFeed(ChangeLoggedModel, CustomFieldModel):
|
|||||||
validators=[MinValueValidator(1)],
|
validators=[MinValueValidator(1)],
|
||||||
default=20
|
default=20
|
||||||
)
|
)
|
||||||
phase = models.PositiveSmallIntegerField(
|
|
||||||
choices=POWERFEED_PHASE_CHOICES,
|
|
||||||
default=POWERFEED_PHASE_SINGLE
|
|
||||||
)
|
|
||||||
max_utilization = models.PositiveSmallIntegerField(
|
max_utilization = models.PositiveSmallIntegerField(
|
||||||
validators=[MinValueValidator(1), MaxValueValidator(100)],
|
validators=[MinValueValidator(1), MaxValueValidator(100)],
|
||||||
default=80,
|
default=80,
|
||||||
@ -2771,7 +2771,7 @@ class PowerFeed(ChangeLoggedModel, CustomFieldModel):
|
|||||||
tags = TaggableManager(through=TaggedItem)
|
tags = TaggableManager(through=TaggedItem)
|
||||||
|
|
||||||
csv_headers = [
|
csv_headers = [
|
||||||
'power_panel', 'rack', 'name', 'type', 'status', 'supply', 'voltage', 'amperage', 'phase', 'max_utilization',
|
'power_panel', 'rack', 'name', 'status', 'type', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization',
|
||||||
'comments',
|
'comments',
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2790,12 +2790,18 @@ class PowerFeed(ChangeLoggedModel, CustomFieldModel):
|
|||||||
self.power_panel.name,
|
self.power_panel.name,
|
||||||
self.rack.name if self.rack else None,
|
self.rack.name if self.rack else None,
|
||||||
self.name,
|
self.name,
|
||||||
self.get_type_display(),
|
|
||||||
self.get_status_display(),
|
self.get_status_display(),
|
||||||
|
self.get_type_display(),
|
||||||
self.get_supply_display(),
|
self.get_supply_display(),
|
||||||
|
self.get_phase_display(),
|
||||||
self.voltage,
|
self.voltage,
|
||||||
self.amperage,
|
self.amperage,
|
||||||
self.get_phase_display(),
|
|
||||||
self.max_utilization,
|
self.max_utilization,
|
||||||
self.comments,
|
self.comments,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_type_class(self):
|
||||||
|
return STATUS_CLASSES[self.type]
|
||||||
|
|
||||||
|
def get_status_class(self):
|
||||||
|
return STATUS_CLASSES[self.status]
|
||||||
|
@ -145,6 +145,10 @@ STATUS_LABEL = """
|
|||||||
<span class="label label-{{ record.get_status_class }}">{{ record.get_status_display }}</span>
|
<span class="label label-{{ record.get_status_class }}">{{ record.get_status_display }}</span>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
TYPE_LABEL = """
|
||||||
|
<span class="label label-{{ record.get_type_class }}">{{ record.get_type_display }}</span>
|
||||||
|
"""
|
||||||
|
|
||||||
DEVICE_PRIMARY_IP = """
|
DEVICE_PRIMARY_IP = """
|
||||||
{{ record.primary_ip6.address.ip|default:"" }}
|
{{ record.primary_ip6.address.ip|default:"" }}
|
||||||
{% if record.primary_ip6 and record.primary_ip4 %}<br />{% endif %}
|
{% if record.primary_ip6 and record.primary_ip4 %}<br />{% endif %}
|
||||||
@ -799,17 +803,10 @@ class PowerPanelTable(BaseTable):
|
|||||||
powerfeed_count = tables.Column(
|
powerfeed_count = tables.Column(
|
||||||
verbose_name='Feeds'
|
verbose_name='Feeds'
|
||||||
)
|
)
|
||||||
actions = tables.TemplateColumn(
|
|
||||||
template_code=RACKROLE_ACTIONS,
|
|
||||||
attrs={
|
|
||||||
'td': {'class': 'text-right noprint'}
|
|
||||||
},
|
|
||||||
verbose_name=''
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta(BaseTable.Meta):
|
class Meta(BaseTable.Meta):
|
||||||
model = PowerPanel
|
model = PowerPanel
|
||||||
fields = ('pk', 'name', 'site', 'rackgroup', 'powerfeed_count', 'actions')
|
fields = ('pk', 'name', 'site', 'rack_group', 'powerfeed_count')
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -819,16 +816,18 @@ class PowerPanelTable(BaseTable):
|
|||||||
class PowerFeedTable(BaseTable):
|
class PowerFeedTable(BaseTable):
|
||||||
pk = ToggleColumn()
|
pk = ToggleColumn()
|
||||||
name = tables.LinkColumn()
|
name = tables.LinkColumn()
|
||||||
powerpanel = tables.LinkColumn(
|
power_panel = tables.LinkColumn(
|
||||||
viewname='dcim:powerpanel',
|
viewname='dcim:powerpanel',
|
||||||
args=[Accessor('powerpanel.pk')],
|
args=[Accessor('power_panel.pk')],
|
||||||
|
|
||||||
)
|
)
|
||||||
rack = tables.LinkColumn(
|
status = tables.TemplateColumn(
|
||||||
viewname='dcim:rack',
|
template_code=STATUS_LABEL
|
||||||
accessor=Accessor('rack.pk')
|
)
|
||||||
|
type = tables.TemplateColumn(
|
||||||
|
template_code=TYPE_LABEL
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta(BaseTable.Meta):
|
class Meta(BaseTable.Meta):
|
||||||
model = PowerFeed
|
model = PowerFeed
|
||||||
fields = ('pk', 'name', 'powerpanel', 'rack', 'type', 'status', 'supply', 'voltage', 'amperage', 'phase')
|
fields = ('pk', 'name', 'power_panel', 'rack', 'status', 'type', 'supply', 'voltage', 'amperage', 'phase')
|
||||||
|
@ -392,10 +392,12 @@ class RackView(View):
|
|||||||
prev_rack = Rack.objects.filter(site=rack.site, name__lt=rack.name).order_by('-name').first()
|
prev_rack = Rack.objects.filter(site=rack.site, name__lt=rack.name).order_by('-name').first()
|
||||||
|
|
||||||
reservations = RackReservation.objects.filter(rack=rack)
|
reservations = RackReservation.objects.filter(rack=rack)
|
||||||
|
power_feeds = PowerFeed.objects.filter(rack=rack).select_related('power_panel')
|
||||||
|
|
||||||
return render(request, 'dcim/rack.html', {
|
return render(request, 'dcim/rack.html', {
|
||||||
'rack': rack,
|
'rack': rack,
|
||||||
'reservations': reservations,
|
'reservations': reservations,
|
||||||
|
'power_feeds': power_feeds,
|
||||||
'nonracked_devices': nonracked_devices,
|
'nonracked_devices': nonracked_devices,
|
||||||
'next_rack': next_rack,
|
'next_rack': next_rack,
|
||||||
'prev_rack': prev_rack,
|
'prev_rack': prev_rack,
|
||||||
@ -2123,9 +2125,9 @@ class VirtualChassisRemoveMemberView(PermissionRequiredMixin, GetReturnURLMixin,
|
|||||||
|
|
||||||
class PowerPanelListView(ObjectListView):
|
class PowerPanelListView(ObjectListView):
|
||||||
queryset = PowerPanel.objects.select_related(
|
queryset = PowerPanel.objects.select_related(
|
||||||
'site', 'rackgroup'
|
'site', 'rack_group'
|
||||||
).annotate(
|
).annotate(
|
||||||
rack_count=Count('powerfeeds')
|
powerfeed_count=Count('powerfeeds')
|
||||||
)
|
)
|
||||||
table = tables.PowerPanelTable
|
table = tables.PowerPanelTable
|
||||||
template_name = 'dcim/powerpanel_list.html'
|
template_name = 'dcim/powerpanel_list.html'
|
||||||
@ -2183,7 +2185,7 @@ class PowerPanelBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|||||||
|
|
||||||
class PowerFeedListView(ObjectListView):
|
class PowerFeedListView(ObjectListView):
|
||||||
queryset = PowerFeed.objects.select_related(
|
queryset = PowerFeed.objects.select_related(
|
||||||
'powerpanel', 'rack'
|
'power_panel', 'rack'
|
||||||
)
|
)
|
||||||
# filter = filters.PowerFeedFilter
|
# filter = filters.PowerFeedFilter
|
||||||
# filter_form = forms.PowerFeedFilterForm
|
# filter_form = forms.PowerFeedFilterForm
|
||||||
@ -2229,7 +2231,7 @@ class PowerFeedBulkImportView(PermissionRequiredMixin, BulkImportView):
|
|||||||
|
|
||||||
class PowerFeedBulkEditView(PermissionRequiredMixin, BulkEditView):
|
class PowerFeedBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||||
permission_required = 'dcim.change_powerfeed'
|
permission_required = 'dcim.change_powerfeed'
|
||||||
queryset = PowerFeed.objects.select_related('powerpanel', 'rack')
|
queryset = PowerFeed.objects.select_related('power_panel', 'rack')
|
||||||
# filter = filters.PowerFeedFilter
|
# filter = filters.PowerFeedFilter
|
||||||
table = tables.PowerFeedTable
|
table = tables.PowerFeedTable
|
||||||
form = forms.PowerFeedBulkEditForm
|
form = forms.PowerFeedBulkEditForm
|
||||||
@ -2238,7 +2240,7 @@ class PowerFeedBulkEditView(PermissionRequiredMixin, BulkEditView):
|
|||||||
|
|
||||||
class PowerFeedBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
class PowerFeedBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||||
permission_required = 'dcim.delete_powerfeed'
|
permission_required = 'dcim.delete_powerfeed'
|
||||||
queryset = PowerFeed.objects.select_related('powerpanel', 'rack')
|
queryset = PowerFeed.objects.select_related('power_panel', 'rack')
|
||||||
# filter = filters.PowerFeedFilter
|
# filter = filters.PowerFeedFilter
|
||||||
table = tables.PowerFeedTable
|
table = tables.PowerFeedTable
|
||||||
default_return_url = 'dcim:powerfeed_list'
|
default_return_url = 'dcim:powerfeed_list'
|
||||||
|
@ -9,13 +9,13 @@
|
|||||||
{% render_field form.power_panel %}
|
{% render_field form.power_panel %}
|
||||||
{% render_field form.rack %}
|
{% render_field form.rack %}
|
||||||
{% render_field form.name %}
|
{% render_field form.name %}
|
||||||
{% render_field form.type %}
|
|
||||||
{% render_field form.status %}
|
{% render_field form.status %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading"><strong>Characteristics</strong></div>
|
<div class="panel-heading"><strong>Characteristics</strong></div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
|
{% render_field form.type %}
|
||||||
{% render_field form.supply %}
|
{% render_field form.supply %}
|
||||||
{% render_field form.voltage %}
|
{% render_field form.voltage %}
|
||||||
{% render_field form.amperage %}
|
{% render_field form.amperage %}
|
||||||
|
@ -190,47 +190,37 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel panel-default">
|
{% if power_feeds %}
|
||||||
<div class="panel-heading">
|
<div class="panel panel-default">
|
||||||
<strong>Non-Racked Devices</strong>
|
<div class="panel-heading">
|
||||||
</div>
|
<strong>Power Feeds</strong>
|
||||||
{% if nonracked_devices %}
|
</div>
|
||||||
<table class="table table-hover panel-body">
|
<table class="table panel-body">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Panel</th>
|
||||||
<th>Role</th>
|
<th>Feed</th>
|
||||||
|
<th>Status</th>
|
||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
<th>Parent</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
{% for device in nonracked_devices %}
|
{% for powerfeed in power_feeds %}
|
||||||
<tr{% if device.device_type.u_height %} class="warning"{% endif %}>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<a href="{% url 'dcim:device' pk=device.pk %}">{{ device }}</a>
|
<a href="{{ powerfeed.power_panel.get_absolute_url }}">{{ powerfeed.power_panel.name }}</a>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="{{ powerfeed.get_absolute_url }}">{{ powerfeed.name }}</a>
|
||||||
</td>
|
</td>
|
||||||
<td>{{ device.device_role }}</td>
|
|
||||||
<td>{{ device.device_type.display_name }}</td>
|
|
||||||
<td>
|
<td>
|
||||||
{% if device.parent_bay %}
|
<span class="label label-{{ powerfeed.get_status_class }}">{{ powerfeed.get_status_display }}</span>
|
||||||
<a href="{{ device.parent_bay.device.get_absolute_url }}">{{ device.parent_bay }}</a>
|
</td>
|
||||||
{% else %}
|
<td>
|
||||||
<span class="text-muted">—</span>
|
<span class="label label-{{ powerfeed.get_type_class }}">{{ powerfeed.get_type_display }}</span>
|
||||||
{% endif %}
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
{% else %}
|
</div>
|
||||||
<div class="panel-body text-muted">None</div>
|
{% endif %}
|
||||||
{% endif %}
|
|
||||||
{% if perms.dcim.add_device %}
|
|
||||||
<div class="panel-footer text-right noprint">
|
|
||||||
<a href="{% url 'dcim:device_add' %}?site={{ rack.site.pk }}&rack={{ rack.pk }}" class="btn btn-primary btn-xs">
|
|
||||||
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
|
|
||||||
Add a non-racked device
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<strong>Images</strong>
|
<strong>Images</strong>
|
||||||
@ -307,11 +297,52 @@
|
|||||||
{% include 'dcim/inc/rack_elevation.html' with primary_face=front_elevation secondary_face=rear_elevation face_id=0 reserved_units=rack.get_reserved_units %}
|
{% include 'dcim/inc/rack_elevation.html' with primary_face=front_elevation secondary_face=rear_elevation face_id=0 reserved_units=rack.get_reserved_units %}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 col-sm-6 col-xs-12">
|
<div class="col-md-6 col-sm-6 col-xs-12">
|
||||||
<div class="rack_header">
|
<div class="rack_header">
|
||||||
<h4>Rear</h4>
|
<h4>Rear</h4>
|
||||||
</div>
|
</div>
|
||||||
{% include 'dcim/inc/rack_elevation.html' with primary_face=rear_elevation secondary_face=front_elevation face_id=1 reserved_units=rack.get_reserved_units %}
|
{% include 'dcim/inc/rack_elevation.html' with primary_face=rear_elevation secondary_face=front_elevation face_id=1 reserved_units=rack.get_reserved_units %}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<strong>Non-Racked Devices</strong>
|
||||||
|
</div>
|
||||||
|
{% if nonracked_devices %}
|
||||||
|
<table class="table table-hover panel-body">
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Role</th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Parent</th>
|
||||||
|
</tr>
|
||||||
|
{% for device in nonracked_devices %}
|
||||||
|
<tr{% if device.device_type.u_height %} class="warning"{% endif %}>
|
||||||
|
<td>
|
||||||
|
<a href="{% url 'dcim:device' pk=device.pk %}">{{ device }}</a>
|
||||||
|
</td>
|
||||||
|
<td>{{ device.device_role }}</td>
|
||||||
|
<td>{{ device.device_type.display_name }}</td>
|
||||||
|
<td>
|
||||||
|
{% if device.parent_bay %}
|
||||||
|
<a href="{{ device.parent_bay.device.get_absolute_url }}">{{ device.parent_bay }}</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted">—</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<div class="panel-body text-muted">None</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if perms.dcim.add_device %}
|
||||||
|
<div class="panel-footer text-right noprint">
|
||||||
|
<a href="{% url 'dcim:device_add' %}?site={{ rack.site.pk }}&rack={{ rack.pk }}" class="btn btn-primary btn-xs">
|
||||||
|
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
|
||||||
|
Add a non-racked device
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
Reference in New Issue
Block a user