import MySQLdb import time import subprocess import StringIO import re from wol import * import os import signal from Util import * import abc import sqlite3 from mysql2sqlite import mysql_to_sqlite def isMachineResponding(machineName): (returnCode, stdout, stderr) = executeProgram( [ 'ping', '-o', '-t', '1', machineName ] ) #log( 'isMachineResponding : result of command %s : %d' % (command, returnCode) ) if returnCode == 0: return True else: bMachineNameIsNotKnown = (returnCode == 68) bMachineIsNotResponding = (returnCode == 2) if bMachineIsNotResponding == False: bBUG_00000004_IS_STILL_ALIVE = True if bBUG_00000004_IS_STILL_ALIVE == True and returnCode == 142: log('isMachineResponding : bug00000004 Unexpected return code : returnCode=%d, stdout="%s", stderr="%s" , machineName = %s' % (returnCode, stdout, stderr, machineName) ) # don't stop the program until we understand bug00000004 elif bBUG_00000004_IS_STILL_ALIVE == True and returnCode == -14: # I had this error code on 07/09/2009 20:38 but I don't know yet what that means log('isMachineResponding : bug00000004 Unexpected return code : returnCode=%d, stdout="%s", stderr="%s" , machineName = %s' % (returnCode, stdout, stderr, machineName) ) # don't stop the program until we understand bug00000004 else: log('isMachineResponding : Unexpected return code : returnCode=%d, stdout="%s", stderr="%s" , machineName = %s' % (returnCode, stdout, stderr, machineName) ) assert(False) return False class ISqlDatabaseBackend(object): def __init__(self): pass @abc.abstractmethod def query(self, sql_query): """ :param str sql_query: the sql query to perform """ pass class RemoteMysqlDb(ISqlDatabaseBackend): def __init__(self, db_server_fqdn, db_user, db_name): """ :param str db_server_fqdn: the fully qualified domain name of the server hosting the database, eg simpatix10.univ-rennes1.fr :param str db_user: the user for accessing the inventory database, eg simpadb_reader :param str db_name: the name of the inventory database, eg simpadb """ self._db_server_fqdn = db_server_fqdn self._db_user = db_user self._db_name = db_name self._connect() def _connect(self): self._conn = MySQLdb.connect(self._db_server_fqdn, self._db_user, '', self._db_name) assert(self._conn) def query(self, sql_query): """ :param str sql_query: the sql query to perform """ self._conn.query( sql_query ) rows = conn.store_result() return rows class SqlFile(ISqlDatabaseBackend): def __init__(self, sql_file_path): """ :param str sql_file_path: the path of the sql file containing the inventory database """ self._sql_file_path = sql_file_path self._cur = None # sqlite cursor sqlite_db_path=':memory:' # sqlite-specific special name for a file stored in memory. We could use something like '/tmp/simpadb.sqlite' here but this would make parsing really slow (1 minute instead of 1s), unless either : # - proper fix : group of INSERT statements are surrounded by BEGIN and COMMIT (see http://stackoverflow.com/questions/4719836/python-and-sqlite3-adding-thousands-of-rows) # - the file is stored on a solid state disk try: os.remove(sqlite_db_path) except: pass self._con = sqlite3.connect(sqlite_db_path) f = open(self._sql_file_path, 'r') sql = f.read() # watch out for built-in `str` #print(sql) self._cur = self._con.cursor() #print(mysql_to_sqlite(sql)) self._cur.executescript(mysql_to_sqlite(sql)) def query(self, sql_query): """ :param str sql_query: the sql query to perform """ pass self._cur.execute( sql_query ) rows = self._cur.fetchall() return rows class SqlDatabaseReader(object): def __init__(self, inv_provider): """ :param ISqlDatabaseBackend inv_provider: the input that provides the inventory data """ self._inv_provider = inv_provider def query(self, sql_query): """ performs a query on the sql database :param str sql_query: the sql query to perform """ return self._inv_provider.query(sql_query) def get_table_attr(self, table, key_name, key_value, attr_name ): """ reads the value of the fiven attribute of the given item in the given table :param str table: the name of the table to read :param str key_name: the name of the column that stores the id of the item to read :param str key_value: the id of the item to read :param str attr_name: the name of the attribute to read from the item """ attr_value = None rows = self.query("SELECT "+attr_name+" FROM "+table+" WHERE "+key_name+"='"+key_value+"'") if len(rows) > 0: attr_value = rows[0][0] return attr_value def machineNameToMacAddress( machineName ): conn = MySQLdb.connect('simpatix10', 'simpadb_reader', '', 'simpadb') assert(conn) sqlQuery = """SELECT mac_address FROM ethernet_cards WHERE machine_name='"""+machineName+"""' AND type='normal'""" #print sqlQuery conn.query( sqlQuery ) r=conn.store_result() row = r.fetch_row(0) assert( len(row) == 1 ) #print 'row =', row macAddress = row[0][0] #print macAddress conn.close() return macAddress def getLightOutManagementIpAddress( machineName ): """ the light out management ip of servers allows to talk to the server even when it's asleep """ conn = MySQLdb.connect('simpatix10', 'simpadb_reader', '', 'simpadb') assert(conn) sqlQuery = """SELECT ip_address_1,ip_address_2,ip_address_3,ip_address_4 FROM ethernet_cards WHERE machine_name='"""+machineName+"""' AND type='light_out_management'""" #print sqlQuery conn.query( sqlQuery ) r=conn.store_result() row = r.fetch_row(0) assert( len(row) == 1 ) #print 'row =', row ipAddress = ('%s.%s.%s.%s') % (row[0][0], row[0][1], row[0][2], row[0][3]) #print macAddress conn.close() return ipAddress def getClusterMachinesNames(): clusterMachinesNames = [] conn = MySQLdb.connect('simpatix10', 'simpadb_reader', '', 'simpadb') assert(conn) sqlQuery = """SELECT name FROM machines WHERE affectation='cluster'""" #print sqlQuery conn.query( sqlQuery ) r=conn.store_result() rows = r.fetch_row(0) for row in rows: #print row clusterMachinesNames.append( row[0] ) conn.close() return clusterMachinesNames def machineSupportsIpmi( machineName ): if (machineName == 'simpatix') or (machineName == 'simpatix01' or (machineName == 'simpa-mac2')): # the command ipmitool sensor on simpatix doesn't work : # Unabled to establish a session with the BMC. # Command failed due to Unknown (0xFFFEF921) (0xFFFEF921) return False return True def putToSleep( machineName ): # note : pmset must be executed as root (returnCode, stdout, stderr) = executeCommand([ 'ssh', machineName, 'pmset sleepnow' ]) """ print returnCode print 'stdout :' print stdout print 'stderr :' print stderr """ assert( returnCode == 0 ) # check if the command succeeded by looking at the output (that's the only way I found) f = StringIO.StringIO(stdout) line = f.readline() f.close() matchObj = re.match('^Sleeping now...', line) if matchObj: return True else: return False def wakeUp(machineName): macAddress = machineNameToMacAddress( machineName ) wake_on_lan(macAddress) return True def isNonRespondingMachineSleeping(machineName): """ note : crappy method to detect if the machine is sleeping (if other methods are available, I would be very interested) """ wakeUp(machineName) time.sleep(120) if isMachineResponding( machineName ): putToSleep( machineName ) time.sleep(30) # allow a little time to make sure the machine is ready to receive other wake on lan messages return True else: return False if __name__ == '__main__': """ for i in range(30): machineName = 'simpatix%d' % (i+10) print 'lom ip of %s is %s' % (machineName, getLightOutManagementIpAddress(machineName)) """ wakeUp('simpatix21') #print putToSleep('simpatix13') #print isNonRespondingMachineSleeping('simpatix13')