just fixed pylint warnings and errors

This commit is contained in:
Guillaume Raffy 2021-01-21 16:14:29 +00:00
parent 160bc22c3d
commit 82816e5193
2 changed files with 45 additions and 44 deletions

View File

@ -2,7 +2,7 @@
The goal of this application is to generate a power diagram that will help system administrators to: The goal of this application is to generate a power diagram that will help system administrators to:
- document the power supply architecture - document the power supply architecture
- easily spot potential power overloads (for example if the power consumption exceeds the capacity of a cable) - easily spot potential power overloads (for example if the power consumption exceeds the capacity of a cable)
This application takes its input from a database, currently in the form of an sql dump, but it could easily be adapted to read directly from a mysql database This application takes its input from a database, currently in the form of an sql dump, but it could easily be adapted to read directly from a mysql database
''' '''
@ -16,7 +16,7 @@ from SimpaDbUtil import SqlFile, SqlDatabaseReader, TableAttrNotFound
def add_capacity_constraints(capacity1, capacity2): def add_capacity_constraints(capacity1, capacity2):
""" """
combines 2 capacity constraints (max amperes) together combines 2 capacity constraints (max amperes) together
:param float capacity1: max amperes for the first capacity, None if there are no constraints :param float capacity1: max amperes for the first capacity, None if there are no constraints
:param float capacity2: max amperes for the second capacity, None if there are no constraints :param float capacity2: max amperes for the second capacity, None if there are no constraints
:return float: max amperes for the combined capacity, None if there are no constraints :return float: max amperes for the combined capacity, None if there are no constraints
@ -95,7 +95,6 @@ class Machine(object):
return self.name == 'edf' or re.match('^ups[0-9]*$', self.name) return self.name == 'edf' or re.match('^ups[0-9]*$', self.name)
class Plug(object): class Plug(object):
""" """
represents a power plug (input or output) of a device represents a power plug (input or output) of a device
@ -131,20 +130,21 @@ class Plug(object):
# apply incoming connection amperes limitation # apply incoming connection amperes limitation
capacity = add_capacity_constraints(capacity, in_con.get_max_amperes()) capacity = add_capacity_constraints(capacity, in_con.get_max_amperes())
if debug: if debug:
print(str(self)+ 'after incoming connection amperes limitation, capacity = ' + str(capacity)) print(str(self) + 'after incoming connection amperes limitation, capacity = ' + str(capacity))
else: else:
# apply the machine containing this plug's amperes limitation # apply the machine containing this plug's amperes limitation
capacity = add_capacity_constraints(capacity, self.machine.get_max_amperes()) capacity = add_capacity_constraints(capacity, self.machine.get_max_amperes())
if debug: if debug:
print(str(self)+'apply the machine containing this plug s amperes limitation, capacity = ' + str(capacity)) print(str(self) + 'apply the machine containing this plug s amperes limitation, capacity = ' + str(capacity))
# apply this plug's amperes limitation # apply this plug's amperes limitation
capacity = add_capacity_constraints(capacity, self.current_capacity_constraint) capacity = add_capacity_constraints(capacity, self.current_capacity_constraint)
if debug: if debug:
print(str(self)+'after apply this plug s amperes limitation, capacity = ' + str(capacity), self.current_capacity_constraint) print(str(self) + 'after apply this plug s amperes limitation, capacity = ' + str(capacity), self.current_capacity_constraint)
return capacity return capacity
class Connection(object): class Connection(object):
""" """
a power cable connecting an input power plug to an output power plug a power cable connecting an input power plug to an output power plug
@ -157,7 +157,7 @@ class Connection(object):
def __str__(self): def __str__(self):
return str(self.from_plug) + ' -> ' + str(self.to_plug) + ' (' + str(self.from_plug.get_max_amperes()) + ' A, ' + str(self.get_max_amperes()) + ' A)' return str(self.from_plug) + ' -> ' + str(self.to_plug) + ' (' + str(self.from_plug.get_max_amperes()) + ' A, ' + str(self.get_max_amperes()) + ' A)'
def get_max_amperes(self): def get_max_amperes(self):
# gLogger.debug('%s (%s A) -> %s (%s A): ' % (str(self.from_plug), str(self.from_plug.get_max_amperes()), str(self.to_plug), str(self.to_plug.current_capacity_constraint))) # gLogger.debug('%s (%s A) -> %s (%s A): ' % (str(self.from_plug), str(self.from_plug.get_max_amperes()), str(self.to_plug), str(self.to_plug.current_capacity_constraint)))
capacity = self.from_plug.get_max_amperes() capacity = self.from_plug.get_max_amperes()
@ -203,7 +203,7 @@ class Connection(object):
to_machine = self.to_plug.machine to_machine = self.to_plug.machine
power_consumption = None power_consumption = None
if worst_case_scenario: if worst_case_scenario:
if False: # self.is_redundancy_cable(): if False: # self.is_redundancy_cable():
power_consumption = 0.0 power_consumption = 0.0
else: else:
power_consumption = to_machine.get_power_consumption(worst_case_scenario) power_consumption = to_machine.get_power_consumption(worst_case_scenario)
@ -217,6 +217,7 @@ class Connection(object):
power_consumption = to_machine.get_power_consumption(worst_case_scenario) / num_input_cables power_consumption = to_machine.get_power_consumption(worst_case_scenario) / num_input_cables
return power_consumption return power_consumption
class PowerConfig(object): class PowerConfig(object):
""" """
the description of how machines are connected together (in terms of electric power) the description of how machines are connected together (in terms of electric power)
@ -225,17 +226,17 @@ class PowerConfig(object):
def __init__(self, simpa_db_sql_file_path): def __init__(self, simpa_db_sql_file_path):
self.machines = {} self.machines = {}
self.connections = [] self.connections = []
sql_source = SqlFile(simpa_db_sql_file_path) sql_source = SqlFile(simpa_db_sql_file_path)
sql_reader = SqlDatabaseReader(sql_source) sql_reader = SqlDatabaseReader(sql_source)
inventory = Inventory(sql_reader) inventory = Inventory(sql_reader)
self._parse_from_inventory(inventory) self._parse_from_inventory(inventory)
def _parse_from_inventory(self, inventory): def _parse_from_inventory(self, inventory):
""" """
:param Inventory inventory: :param Inventory inventory:
""" """
rows = inventory.query("SELECT * FROM machine_to_power") rows = inventory.query("SELECT * FROM machine_to_power")
for row in rows: for row in rows:
@ -255,7 +256,7 @@ class PowerConfig(object):
(to_plug_as_str, max_amps_as_str) = row (to_plug_as_str, max_amps_as_str) = row
to_plug = self._get_plug(to_plug_as_str) to_plug = self._get_plug(to_plug_as_str)
to_plug.set_current_capacity_constraint(float(max_amps_as_str)) to_plug.set_current_capacity_constraint(float(max_amps_as_str))
for machine in self.machines.values(): for machine in self.machines.values():
machine_name = machine.name machine_name = machine.name
@ -283,13 +284,12 @@ class PowerConfig(object):
machine_spec_id = None # some simple 'machines' such as powerext003 have undefined machine_spec_id machine_spec_id = None # some simple 'machines' such as powerext003 have undefined machine_spec_id
except MachineSpecIdNotFound: except MachineSpecIdNotFound:
pass pass
if machine_spec_id is not None: if machine_spec_id is not None:
power_consumption = inventory.machine_spec_id_to_power_consumption(machine_spec_id) power_consumption = inventory.machine_spec_id_to_power_consumption(machine_spec_id)
if power_consumption is not None: if power_consumption is not None:
machine.power_consumption = power_consumption machine.power_consumption = power_consumption
def get_connection_to(self, to_plug): def get_connection_to(self, to_plug):
for connection in self.connections: for connection in self.connections:
if connection.to_plug == to_plug: if connection.to_plug == to_plug:
@ -300,27 +300,28 @@ class PowerConfig(object):
if machine_name not in self.machines: if machine_name not in self.machines:
self.machines[machine_name] = Machine(machine_name, self) self.machines[machine_name] = Machine(machine_name, self)
return self.machines[machine_name] return self.machines[machine_name]
def _get_plug(self, plug_as_str): def _get_plug(self, plug_as_str):
elements = plug_as_str.split('_') elements = plug_as_str.split('_')
plug_name = elements[-1] plug_name = elements[-1]
machine_name = plug_as_str[0:-(len(plug_name) + 1)] machine_name = plug_as_str[0:-(len(plug_name) + 1)]
machine = self._get_machine(machine_name) machine = self._get_machine(machine_name)
return machine.get_plug(plug_name) return machine.get_plug(plug_name)
def _add_connection(self, from_plug_as_str, to_plug_as_str): def _add_connection(self, from_plug_as_str, to_plug_as_str):
from_plug = self._get_plug(from_plug_as_str) from_plug = self._get_plug(from_plug_as_str)
to_plug = self._get_plug(to_plug_as_str) to_plug = self._get_plug(to_plug_as_str)
conn = Connection(from_plug, to_plug) conn = Connection(from_plug, to_plug)
self.connections.append(conn) self.connections.append(conn)
return conn return conn
def __str__(self): def __str__(self):
s = '' s = ''
for c in self.connections: for c in self.connections:
s += str(c) + '\n' s += str(c) + '\n'
return s return s
class CableColorer(object): class CableColorer(object):
def get_cable_color(self, cable, worst_case_scenario): def get_cable_color(self, cable, worst_case_scenario):
@ -329,6 +330,7 @@ class CableColorer(object):
""" """
raise NotImplementedError raise NotImplementedError
class SimpleColorer(CableColorer): class SimpleColorer(CableColorer):
def get_cable_color(self, cable, worst_case_scenario): def get_cable_color(self, cable, worst_case_scenario):
@ -349,6 +351,7 @@ class SimpleColorer(CableColorer):
color = '/svg/green' color = '/svg/green'
return color return color
class RampColorer(CableColorer): class RampColorer(CableColorer):
@staticmethod @staticmethod
@ -384,24 +387,24 @@ class RampColorer(CableColorer):
color = '/svg/red' # draw overloaded cables in red color = '/svg/red' # draw overloaded cables in red
return color return color
def power_config_to_svg(power_config, svg_file_path, worst_case_scenario=True): def power_config_to_svg(power_config, svg_file_path, worst_case_scenario=True):
""" """
creates a svg diagram representing the input power configuration creates a svg diagram representing the input power configuration
:param PowerConfig power_config: the input power config :param PowerConfig power_config: the input power config
""" """
graph = pygraphviz.AGraph(strict=False) # strict=False allows more than one connection between 2 nodes graph = pygraphviz.AGraph(strict=False) # strict=False allows more than one connection between 2 nodes
graph.graph_attr['overlap'] = 'false' graph.graph_attr['overlap'] = 'false'
graph.graph_attr['splines'] = 'true' graph.graph_attr['splines'] = 'true'
graph.graph_attr['rankdir'] = 'LR' # to get hrizontal tree rather than vertical graph.graph_attr['rankdir'] = 'LR' # to get hrizontal tree rather than vertical
graph.edge_attr['colorscheme'] = 'rdylgn9' # 'brbg11' graph.edge_attr['colorscheme'] = 'rdylgn9' # 'brbg11'
graph.node_attr['shape'] = 'box' graph.node_attr['shape'] = 'box'
graph.node_attr['height'] = 0.3 # default 0.5 inches graph.node_attr['height'] = 0.3 # default 0.5 inches
graph.node_attr['fontname'] = 'Helvetica' # default : Times-Roman graph.node_attr['fontname'] = 'Helvetica' # default : Times-Roman
graph.edge_attr['fontsize'] = 10 # default : 14 pt graph.edge_attr['fontsize'] = 10 # default : 14 pt
graph.edge_attr['len'] = 1.5 # default : 1.0 graph.edge_attr['len'] = 1.5 # default : 1.0
# graph.add_node('a') # graph.add_node('a')
# graph.add_node('b') # graph.add_node('b')
@ -438,7 +441,6 @@ def power_config_to_svg(power_config, svg_file_path, worst_case_scenario=True):
</tr>\ </tr>\
</table>>' % (machine.name, machine_total_power_consumption) </table>>' % (machine.name, machine_total_power_consumption)
if False: if False:
x = 0.0 x = 0.0
for rack in racks.itervalues(): for rack in racks.itervalues():
@ -470,7 +472,7 @@ def power_config_to_svg(power_config, svg_file_path, worst_case_scenario=True):
penwidth = capacity * penwidth_scaler penwidth = capacity * penwidth_scaler
label = "%.1f/%s" % (amperes, max_amp) label = "%.1f/%s" % (amperes, max_amp)
# color='//%d' % int(9.0-amperes/capacity*8) # color='//%d' % int(9.0-amperes/capacity*8)
# graph.add_edge(con.from_plug.machine.name, con.to_plug.machine.name, color="%s:%s" % (color, wsc_color), label=label, penwidth="%s:%s" % (penwidth, penwidth)) # graph.add_edge(con.from_plug.machine.name, con.to_plug.machine.name, color="%s:%s" % (color, wsc_color), label=label, penwidth="%s:%s" % (penwidth, penwidth))
graph.add_edge(con.from_plug.machine.name, con.to_plug.machine.name, color=color, label=label, penwidth=penwidth) graph.add_edge(con.from_plug.machine.name, con.to_plug.machine.name, color=color, label=label, penwidth=penwidth)
@ -481,10 +483,9 @@ def power_config_to_svg(power_config, svg_file_path, worst_case_scenario=True):
sub.graph_attr['label'] = rack_id sub.graph_attr['label'] = rack_id
# sub.graph_attr['rank']='same' # sub.graph_attr['rank']='same'
# assert False # assert False
#graph.layout(prog='twopi') # graph.layout(prog='twopi')
with open('./toto.dot', 'w') as f: with open('./toto.dot', 'w') as f:
f.write(graph.string()) f.write(graph.string())
graph.layout(prog='dot') graph.layout(prog='dot')
graph.draw(svg_file_path) graph.draw(svg_file_path)

View File

@ -1,6 +1,6 @@
# encoding: utf-8 # encoding: utf-8
import datetime import datetime
#from Lib import SimpaDbUtil # from Lib import SimpaDbUtil
import SimpaDbUtil import SimpaDbUtil
@ -20,14 +20,14 @@ class PlugTypeNotFound(Exception):
class Inventory(object): class Inventory(object):
def __init__(self, sql_reader): def __init__(self, sql_reader):
""" """
:param SimpaDbUtil.SqlDatabaseReader sql_reader: the inventory database :param SimpaDbUtil.SqlDatabaseReader sql_reader: the inventory database
""" """
super(Inventory, self).__init__() super(Inventory, self).__init__()
self._sql_reader = sql_reader self._sql_reader = sql_reader
def query(self, sql_query): def query(self, sql_query):
return self._sql_reader.query(sql_query) return self._sql_reader.query(sql_query)
@ -48,7 +48,7 @@ class Inventory(object):
def machine_name_to_machine_spec_id(self, machine_name): def machine_name_to_machine_spec_id(self, machine_name):
try: try:
machine_spec_id = self._sql_reader.get_table_attr('machines', 'name', machine_name, 'machine_spec_id') machine_spec_id = self._sql_reader.get_table_attr('machines', 'name', machine_name, 'machine_spec_id')
except SimpaDbUtil.TableAttrNotFound as e: # @UnusedVariable except SimpaDbUtil.TableAttrNotFound as e: # noqa: F841 @UnusedVariable
raise MachineSpecIdNotFound(machine_name) raise MachineSpecIdNotFound(machine_name)
if machine_spec_id == '': if machine_spec_id == '':
raise MachineSpecIdNotFound(machine_name) raise MachineSpecIdNotFound(machine_name)
@ -59,7 +59,7 @@ class Inventory(object):
def machine_spec_id_to_power_consumption(self, machine_spec_id): def machine_spec_id_to_power_consumption(self, machine_spec_id):
try: try:
power_consumption = float(self._sql_reader.get_table_attr('machine_spec_to_power_consumption', 'machine_spec_id', machine_spec_id, 'power_consumption')) power_consumption = float(self._sql_reader.get_table_attr('machine_spec_to_power_consumption', 'machine_spec_id', machine_spec_id, 'power_consumption'))
except SimpaDbUtil.TableAttrNotFound as e: # @UnusedVariable except SimpaDbUtil.TableAttrNotFound as e: # noqa: F841 @UnusedVariable
# some passive machines such as pdus are not detailed in the machine_spec_to_power_consumption because they don't consume power # some passive machines such as pdus are not detailed in the machine_spec_to_power_consumption because they don't consume power
power_consumption = 0.0 power_consumption = 0.0
return power_consumption return power_consumption
@ -72,7 +72,7 @@ class Inventory(object):
# ('iec60309_blue_pne6h_32a_m', 'm', 32.0), # ('iec60309_blue_pne6h_32a_m', 'm', 32.0),
attr_value = self._sql_reader.get_table_attr('powerplug_type_desc', 'plug_type_id', plug_type, attr_name) attr_value = self._sql_reader.get_table_attr('powerplug_type_desc', 'plug_type_id', plug_type, attr_name)
return attr_value return attr_value
def get_plug_type(self, machine_name, plug_name): def get_plug_type(self, machine_name, plug_name):
""" """
:param str machine_name: eg 'pdu4' :param str machine_name: eg 'pdu4'
@ -92,7 +92,7 @@ class Inventory(object):
else: else:
raise PlugTypeNotFound(machine_spec_id, plug_name) raise PlugTypeNotFound(machine_spec_id, plug_name)
return plug_type return plug_type
def read_plug_capacity(self, plug): def read_plug_capacity(self, plug):
""" """
:param PowerDiagram.Plug plug: the power plug of a 'device' we're interested in (eg pdu4.o1) :param PowerDiagram.Plug plug: the power plug of a 'device' we're interested in (eg pdu4.o1)
@ -105,12 +105,12 @@ class Inventory(object):
except MachineSpecIdNotFound: except MachineSpecIdNotFound:
# some machines are not actual machines (eg edf, ups1pdu) # some machines are not actual machines (eg edf, ups1pdu)
pass pass
#except PlugTypeNotFound: # except PlugTypeNotFound:
# some plugs are just plain connections, with no actual plug types # some plugs are just plain connections, with no actual plug types
# pass # pass
if plug_type is not None: if plug_type is not None:
# print('plug_type : %s' % plug_type) # print('plug_type : %s' % plug_type)
plug_capacity = self.get_plug_type_attr(plug_type, 'max_amps') plug_capacity = self.get_plug_type_attr(plug_type, 'max_amps')
# if plug_capacity: # if plug_capacity:
# print('plug_capacity : %f A' % plug_capacity) # print('plug_capacity : %f A' % plug_capacity)
@ -150,7 +150,7 @@ class Inventory(object):
dflops_per_core_per_cycle = int(self._sql_reader.get_table_attr('cpu_specs', 'cpu_model', cpu_model, 'dflops_per_core_per_cycle')) dflops_per_core_per_cycle = int(self._sql_reader.get_table_attr('cpu_specs', 'cpu_model', cpu_model, 'dflops_per_core_per_cycle'))
# print(num_cores, clock_speed, dflops_per_core_per_cycle) # print(num_cores, clock_speed, dflops_per_core_per_cycle)
return clock_speed * dflops_per_core_per_cycle * num_cores return clock_speed * dflops_per_core_per_cycle * num_cores
def get_num_cpus(self, computer_name): def get_num_cpus(self, computer_name):
return int(self._sql_reader.get_table_attr('computer_to_cpu', 'computer_id', computer_name, 'num_cpu')) return int(self._sql_reader.get_table_attr('computer_to_cpu', 'computer_id', computer_name, 'num_cpu'))
@ -160,20 +160,20 @@ class Inventory(object):
def get_cpu_frequency(self, computer_name): def get_cpu_frequency(self, computer_name):
cpu_model = self._sql_reader.get_table_attr('computer_to_cpu', 'computer_id', computer_name, 'cpu_model') cpu_model = self._sql_reader.get_table_attr('computer_to_cpu', 'computer_id', computer_name, 'cpu_model')
return float(self._sql_reader.get_table_attr('cpu_specs', 'cpu_model', cpu_model, 'clock_speed')) return float(self._sql_reader.get_table_attr('cpu_specs', 'cpu_model', cpu_model, 'clock_speed'))
def get_computer_dflops(self, computer_name): def get_computer_dflops(self, computer_name):
# print(computer_serial_number) # print(computer_serial_number)
num_cpus = int(self._sql_reader.get_table_attr( 'computer_to_cpu', 'computer_id', computer_name, 'num_cpu')) num_cpus = int(self._sql_reader.get_table_attr('computer_to_cpu', 'computer_id', computer_name, 'num_cpu'))
cpu_model = self._sql_reader.get_table_attr('computer_to_cpu', 'computer_id', computer_name, 'cpu_model') cpu_model = self._sql_reader.get_table_attr('computer_to_cpu', 'computer_id', computer_name, 'cpu_model')
flops = num_cpus * self.get_cpu_dflops(cpu_model) flops = num_cpus * self.get_cpu_dflops(cpu_model)
return flops return flops
def get_computer_options_price(self, computer_name): def get_computer_options_price(self, computer_name):
options_price = 0.0 options_price = 0.0
if computer_name == 'simpatix58' or computer_name == 'simpatix59': if computer_name == 'simpatix58' or computer_name == 'simpatix59':
return 7675.0 / 4 * 2 # each of these computers has 2 nvidia fermi C2050 gpus return 7675.0 / 4 * 2 # each of these computers has 2 nvidia fermi C2050 gpus
return options_price return options_price
def get_item_container(self, item_id): def get_item_container(self, item_id):
""" """
:param str item_id: the identifier of an inventory item (a machine (eg simpa-switch002), a group of machines (ceph), etc.) :param str item_id: the identifier of an inventory item (a machine (eg simpa-switch002), a group of machines (ceph), etc.)
@ -184,7 +184,7 @@ class Inventory(object):
if len(rows) > 0: if len(rows) > 0:
container_id = rows[0][0] container_id = rows[0][0]
return container_id return container_id
def get_item_price(self, item_id, include_contents=False, include_maintenance=False): def get_item_price(self, item_id, include_contents=False, include_maintenance=False):
""" """
:param str item_id: the identifier of an inventory item (a machine (eg simpa-switch002), a group of machines (ceph), etc.) :param str item_id: the identifier of an inventory item (a machine (eg simpa-switch002), a group of machines (ceph), etc.)
@ -201,7 +201,7 @@ class Inventory(object):
for row in rows: for row in rows:
maintenance_price_ex_vat = float(row[0]) maintenance_price_ex_vat = float(row[0])
item_price += maintenance_price_ex_vat item_price += maintenance_price_ex_vat
if include_contents: if include_contents:
# add the price of included parts # add the price of included parts
rows = self._sql_reader.query("SELECT part_id FROM container WHERE container_id='%s'" % item_id) rows = self._sql_reader.query("SELECT part_id FROM container WHERE container_id='%s'" % item_id)
@ -210,10 +210,10 @@ class Inventory(object):
item_price += self.get_item_price(part_id, include_contents, include_maintenance) item_price += self.get_item_price(part_id, include_contents, include_maintenance)
# print(u'price of %s : %.2f € HT' % (item_id, item_price)) # print(u'price of %s : %.2f € HT' % (item_id, item_price))
return item_price return item_price
def get_item_ownership(self, item_id): def get_item_ownership(self, item_id):
ownership = [] ownership = []
rows = self._sql_reader.query("SELECT * FROM ownership WHERE machine_id='%s'" % item_id) rows = self._sql_reader.query("SELECT * FROM ownership WHERE machine_id='%s'" % item_id)
for row in rows: for row in rows:
(machine_id, owner, owner_ratio, comment) = row # @UnusedVariable (machine_id, owner, owner_ratio, comment) = row # @UnusedVariable
@ -222,7 +222,7 @@ class Inventory(object):
def get_item_use(self, item_id): def get_item_use(self, item_id):
ownership = [] ownership = []
rows = self._sql_reader.query("SELECT * FROM machine_users") rows = self._sql_reader.query("SELECT * FROM machine_users")
for row in rows: for row in rows:
(machine_id, user, user_ratio, comment) = row # @UnusedVariable (machine_id, user, user_ratio, comment) = row # @UnusedVariable