# encoding: utf-8 import datetime from Lib import SimpaDbUtil class MachineSpecIdNotFound(Exception): def __init__(self, machine_name): message = "failed to find the machine_spec_id for the machine '%s'" % machine_name super(MachineSpecIdNotFound, self).__init__(message) self.machine_name = machine_name class PlugTypeNotFound(Exception): def __init__(self, machine_spec_id, plug_name): message = "failed to find the plug_type for the machine_spec_id '%s' and plug_name '%s'" % (machine_spec_id, plug_name) super(PlugTypeNotFound, self).__init__(message) self.machine_spec_id = machine_spec_id self.plug_name = plug_name class Inventory(object): def __init__(self, sql_reader): """ :param SimpaDbUtil.SqlDatabaseReader sql_reader: the inventory database """ super(Inventory, self).__init__() self._sql_reader = sql_reader def query(self, sql_query): return self._sql_reader.query(sql_query) def get_machine_serial_number(self, machine_name): ''' returns the serial number of the given machine ''' machine_serial_number = self._sql_reader.get_table_attr('machines', 'name', machine_name, 'serial_number') return machine_serial_number def get_machine_name(self, machine_serial_number): ''' returns the user-friendly name of the given machine ''' machine_name = self._sql_reader.get_table_attr('machines', 'serial_number', machine_serial_number, 'name') return machine_name def machine_name_to_machine_spec_id(self, machine_name): try: machine_spec_id = self._sql_reader.get_table_attr('machines', 'name', machine_name, 'machine_spec_id') except SimpaDbUtil.TableAttrNotFound as e: # @UnusedVariable raise MachineSpecIdNotFound(machine_name) if machine_spec_id == '': raise MachineSpecIdNotFound(machine_name) return machine_spec_id # electricity related methods def machine_spec_id_to_power_consumption(self, machine_spec_id): try: 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 # 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 return power_consumption def get_plug_type_attr(self, plug_type, attr_name): """ :param str plug_type: eg 'c14' """ # INSERT INTO `powerplug_type_desc` (`plug_type_id`, `genre`, `max_amps`) VALUES # ('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) return attr_value def get_plug_type(self, machine_name, plug_name): """ :param str machine_name: eg 'pdu4' :param str plug_name: eg 'o4' """ machine_spec_id = None try: machine_spec_id = self.machine_name_to_machine_spec_id(machine_name) except MachineSpecIdNotFound as e: raise e else: # INSERT INTO `powerplug_desc` (`machine_spec_id`, `powerplug_id`, `plug_type`) VALUES # ('atos_mpdu_2901382', 'i', 'iec60309_blue_pne6h_32a_m'), rows = self._sql_reader.query("SELECT plug_type FROM powerplug_desc WHERE machine_spec_id='%s' AND powerplug_id='%s'" % (machine_spec_id, plug_name)) if len(rows) > 0: plug_type = rows[0][0] else: raise PlugTypeNotFound(machine_spec_id, plug_name) return plug_type def read_plug_capacity(self, plug): """ :param PowerDiagram.Plug plug: the power plug of a 'device' we're interested in (eg pdu4.o1) """ plug_capacity = None plug_type = None try: plug_type = self.get_plug_type(plug.machine.name, plug.name) except MachineSpecIdNotFound: # some machines are not actual machines (eg edf, ups1pdu) pass #except PlugTypeNotFound: # some plugs are just plain connections, with no actual plug types # pass if plug_type is not None: # print('plug_type : %s' % plug_type) plug_capacity = self.get_plug_type_attr(plug_type, 'max_amps') # if plug_capacity: # print('plug_capacity : %f A' % plug_capacity) # print("read_plug_capacity : plug capacity for plug.machine.name="+plug.machine.name+" plug="+str(plug)+" : "+ str(plug_capacity)+ "A") return plug_capacity # cluster related methods def get_machine_purchase_date(self, machine_id): ordering_id = self._sql_reader.get_table_attr('machines', 'name', machine_id, 'command_id') # print(ordering_id) # handle case of multiple orders ordering_id = ordering_id.split('+')[0] if len(ordering_id) == 0: return None ordering_date_as_str = self._sql_reader.get_table_attr('orderings', 'ordering_id', ordering_id, 'ordering_date') if ordering_date_as_str is None: return None if len(ordering_date_as_str) == 0: return None ordering_date = datetime.datetime.strptime(ordering_date_as_str, '%d/%m/%Y') return ordering_date def get_machine_rack_location(self, machine_id): rack_id = self._sql_reader.get_table_attr('rackable_machine_to_location', 'machine_id', machine_id, 'rack_id') slot_index = self._sql_reader.get_table_attr('rackable_machine_to_location', 'machine_id', machine_id, 'slot_index') return rack_id, slot_index def get_cpu_dflops(self, cpu_model): ''' returns the number of double precision operation per second this cpu can achieve ''' # INSERT INTO `cpu_specs` (`cpu_model`, `num_cores`, `clock_speed`, `dflops_per_core_per_cycle`, `comment`) VALUES # ('intel_xeon_x5550', 4, 2.67, 4, ''), num_cores = int(self._sql_reader.get_table_attr('cpu_specs', 'cpu_model', cpu_model, 'num_cores')) clock_speed = float(self._sql_reader.get_table_attr('cpu_specs', 'cpu_model', cpu_model, 'clock_speed')) * 1.e9 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) return clock_speed * dflops_per_core_per_cycle * num_cores def get_num_cpus(self, computer_name): return int(self._sql_reader.get_table_attr('computer_to_cpu', 'computer_id', computer_name, 'num_cpu')) def get_cpu_model(self, computer_name): return self._sql_reader.get_table_attr('computer_to_cpu', 'computer_id', computer_name, 'cpu_model') def get_cpu_frequency(self, computer_name): 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')) def get_computer_dflops(self, computer_name): # print(computer_serial_number) 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') flops = num_cpus * self.get_cpu_dflops(cpu_model) return flops def get_computer_options_price(self, computer_name): options_price = 0.0 if computer_name == 'simpatix58' or computer_name == 'simpatix59': return 7675.0 / 4 * 2 # each of these computers has 2 nvidia fermi C2050 gpus return options_price 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.) :return str: the item that contains the given item, None if this item has no contrainer """ container_id = None rows = self._sql_reader.query("SELECT container_id FROM container WHERE part_id='%s'" % item_id) if len(rows) > 0: container_id = rows[0][0] return container_id 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.) :return float: the price of the item exluding taxes """ item_price = self._sql_reader.get_table_attr('machines', 'name', item_id, 'price_ex_vat') if item_price is None: item_price = 0.0 else: item_price = float(item_price) if include_maintenance: # INSERT INTO `maintenance` (`maintenance_id`, `machine_id`, `price_ex_vat`, `command_id`, `comment`) VALUES rows = self._sql_reader.query("SELECT price_ex_vat FROM maintenance WHERE machine_id='%s'" % item_id) for row in rows: maintenance_price_ex_vat = float(row[0]) item_price += maintenance_price_ex_vat if include_contents: # add the price of included parts rows = self._sql_reader.query("SELECT part_id FROM container WHERE container_id='%s'" % item_id) for row in rows: part_id = row[0] item_price += self.get_item_price(part_id, include_contents, include_maintenance) # print(u'price of %s : %.2f € HT' % (item_id, item_price)) return item_price def get_item_ownership(self, item_id): ownership = [] rows = self._sql_reader.query("SELECT * FROM ownership WHERE machine_id='%s'" % item_id) for row in rows: (machine_id, owner, owner_ratio, comment) = row # @UnusedVariable ownership.append({'owner': owner, 'owner_ratio': owner_ratio}) return ownership def get_item_use(self, item_id): ownership = [] rows = self._sql_reader.query("SELECT * FROM machine_users") for row in rows: (machine_id, user, user_ratio, comment) = row # @UnusedVariable if machine_id == item_id: ownership.append({'user': user, 'user_ratio': user_ratio}) return ownership