Skip to content

Commit 647bcf6

Browse files
authored
Merge pull request #96 from candlerb/candlerb/power-summary
Add script to report on total allocated power draw and power outlets used/available
2 parents 6988208 + 7e256fb commit 647bcf6

File tree

1 file changed

+124
-0
lines changed

1 file changed

+124
-0
lines changed

scripts/power_summary.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
"""
2+
This script reports on power utilisation and power port availability,
3+
either globally (aggregated per site), or for an individual site
4+
(listing all the devices).
5+
6+
It's a script rather than a report so that it can prompt for site choice.
7+
8+
It doesn't rely on power ports being connected to power feeds or
9+
calculations done at PDU level; it uses the allocated_draw of
10+
each power port directly.
11+
"""
12+
13+
import csv
14+
import io
15+
from dcim.choices import PowerPortTypeChoices
16+
from dcim.models import Site, Device, PowerPort, PowerOutlet, PowerFeed, PowerPanel
17+
from extras.scripts import Script, StringVar, ObjectVar, ChoiceVar
18+
19+
DC_TYPES = [PowerPortTypeChoices.TYPE_DC]
20+
21+
class PowerUsageAllSites(Script):
22+
class Meta:
23+
name = "Power Usage (all sites)"
24+
description = "Report on allocated power per site"
25+
scheduling_enabled = False
26+
commit_default = False
27+
28+
def run(self, data, commit):
29+
output = io.StringIO()
30+
writer = csv.writer(output)
31+
writer.writerow(['Site','Allocated Draw'])
32+
for site in Site.objects.filter(status='active'):
33+
power_ports = PowerPort.objects.filter(device__site=site,device__status='active')
34+
site_draw = sum(((pp.allocated_draw or 0) for pp in power_ports))
35+
if site_draw > 0:
36+
writer.writerow([site.name, site_draw])
37+
return output.getvalue()
38+
39+
class PowerUsageSingleSite(Script):
40+
class Meta:
41+
name = "Power Usage (single site)"
42+
description = "Report on allocated power for each device in a site"
43+
scheduling_enabled = False
44+
commit_default = False
45+
46+
site = ObjectVar(
47+
model=Site,
48+
query_params={
49+
'status': 'active',
50+
},
51+
label="Site",
52+
)
53+
54+
def run(self, data, commit):
55+
output = io.StringIO()
56+
writer = csv.writer(output)
57+
site = data['site']
58+
power_ports = PowerPort.objects.filter(device__site=site,device__status='active')
59+
writer.writerow(['Device','Port','Allocated Draw'])
60+
site_draw = 0
61+
for pp in power_ports:
62+
if not pp.allocated_draw:
63+
continue
64+
writer.writerow([pp.device.name, pp.name, pp.allocated_draw])
65+
site_draw += pp.allocated_draw
66+
self.log_success(f"Total allocated draw for {site}: {site_draw}W")
67+
return output.getvalue()
68+
69+
class PowerOutletsAllSites(Script):
70+
class Meta:
71+
name = "Power Outlets (all sites)"
72+
description = "Report on total/free power outlets per site"
73+
scheduling_enabled = False
74+
commit_default = False
75+
76+
def run(self, data, commit):
77+
output = io.StringIO()
78+
writer = csv.writer(output)
79+
writer.writerow(['Site','AC total','AC free','DC total','DC free'])
80+
for site in Site.objects.filter(status='active'):
81+
ac_total = ac_free = dc_total = dc_free = 0
82+
power_ports = PowerOutlet.objects.filter(device__site=site,device__status='active')
83+
for pp in power_ports:
84+
if pp.type in DC_TYPES:
85+
dc_total += 1
86+
dc_free += (0 if pp.mark_connected or pp.cable else 1)
87+
else:
88+
ac_total += 1
89+
ac_free += (0 if pp.mark_connected or pp.cable else 1)
90+
if dc_total > 0 or ac_total > 0:
91+
writer.writerow([site.name, ac_total, ac_free, dc_total, dc_free])
92+
return output.getvalue()
93+
94+
class PowerOutletsSingleSite(Script):
95+
class Meta:
96+
name = "Power Outlets (single site)"
97+
description = "Report on power outlets for each PDU in a site"
98+
scheduling_enabled = False
99+
commit_default = False
100+
101+
site = ObjectVar(
102+
model=Site,
103+
query_params={
104+
'status': 'active',
105+
},
106+
label="Site",
107+
)
108+
109+
def run(self, data, commit):
110+
output = io.StringIO()
111+
writer = csv.writer(output)
112+
site = data['site']
113+
devices = Device.objects.filter(site=site,status='active')
114+
writer.writerow(['Device','Outlet Type','Total','Free'])
115+
for device in devices:
116+
count_by_type = {} # type => [total, free]
117+
for pp in device.poweroutlets.all():
118+
c = count_by_type.setdefault(pp.type, [0,0])
119+
c[0] += 1
120+
if not (pp.mark_connected or pp.cable):
121+
c[1] += 1
122+
for type, vals in count_by_type.items():
123+
writer.writerow([device.name, type, vals[0], vals[1]])
124+
return output.getvalue()

0 commit comments

Comments
 (0)