def setUpClass(cls): super(Test, cls).setUpClass() eckey = ECKey() eckey.generate() cls.network_key = toWIF(PREFIX_SECRET_KEY_REGTEST, eckey.get_bytes()) cls.network_pubkey = eckey.get_pubkey().get_bytes().hex() if os.path.isdir(cfg.TEST_DATADIRS): logging.info('Removing ' + cfg.TEST_DATADIRS) shutil.rmtree(cfg.TEST_DATADIRS) for i in range(NUM_NODES): prepareDir(cfg.TEST_DATADIRS, i, cls.network_key, cls.network_pubkey) prepareOtherDir(cfg.TEST_DATADIRS, NMC_NODE) prepareOtherDir(cfg.TEST_DATADIRS, BTC_NODE, 'bitcoin.conf') cls.daemons = [] cls.swap_clients = [] cls.http_threads = [] cls.daemons.append(startDaemon(os.path.join(cfg.TEST_DATADIRS, str(BTC_NODE)), cfg.BITCOIN_BINDIR, cfg.BITCOIND)) logging.info('Started %s %d', cfg.BITCOIND, cls.daemons[-1].pid) cls.daemons.append(startDaemon(os.path.join(cfg.TEST_DATADIRS, str(NMC_NODE)), cfg.NAMECOIN_BINDIR, cfg.NAMECOIND)) logging.info('Started %s %d', cfg.NAMECOIND, cls.daemons[-1].pid) for i in range(NUM_NODES): cls.daemons.append(startDaemon(os.path.join(cfg.TEST_DATADIRS, str(i)), cfg.PARTICL_BINDIR, cfg.PARTICLD)) logging.info('Started %s %d', cfg.PARTICLD, cls.daemons[-1].pid) for i in range(NUM_NODES): rpc = make_part_cli_rpc_func(i) waitForRPC(rpc) if i == 0: rpc('extkeyimportmaster', ['abandon baby cabbage dad eager fabric gadget habit ice kangaroo lab absorb']) elif i == 1: rpc('extkeyimportmaster', ['pact mammal barrel matrix local final lecture chunk wasp survey bid various book strong spread fall ozone daring like topple door fatigue limb olympic', '', 'true']) rpc('getnewextaddress', ['lblExtTest']) rpc('rescanblockchain') else: rpc('extkeyimportmaster', [rpc('mnemonic', ['new'])['master']]) basicswap_dir = os.path.join(os.path.join(cfg.TEST_DATADIRS, str(i)), 'basicswap') settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME) with open(settings_path) as fs: settings = json.load(fs) fp = open(os.path.join(basicswap_dir, 'basicswap.log'), 'w') cls.swap_clients.append(BasicSwap(fp, basicswap_dir, settings, 'regtest', log_name='BasicSwap{}'.format(i))) cls.swap_clients[-1].setDaemonPID(Coins.BTC, cls.daemons[0].pid) cls.swap_clients[-1].setDaemonPID(Coins.NMC, cls.daemons[1].pid) cls.swap_clients[-1].setDaemonPID(Coins.PART, cls.daemons[2 + i].pid) cls.swap_clients[-1].start() t = HttpThread(cls.swap_clients[i].fp, TEST_HTTP_HOST, TEST_HTTP_PORT + i, False, cls.swap_clients[i]) cls.http_threads.append(t) t.start() waitForRPC(nmcRpc) num_blocks = 500 logging.info('Mining %d namecoin blocks', num_blocks) cls.nmc_addr = nmcRpc('getnewaddress mining_addr legacy') nmcRpc('generatetoaddress {} {}'.format(num_blocks, cls.nmc_addr)) ro = nmcRpc('getblockchaininfo') try: assert(ro['bip9_softforks']['csv']['status'] == 'active') except Exception: logging.info('nmc: csv is not active') try: assert(ro['bip9_softforks']['segwit']['status'] == 'active') except Exception: logging.info('nmc: segwit is not active') waitForRPC(btcRpc) cls.btc_addr = btcRpc('getnewaddress mining_addr bech32') logging.info('Mining %d Bitcoin blocks to %s', num_blocks, cls.btc_addr) btcRpc('generatetoaddress {} {}'.format(num_blocks, cls.btc_addr)) ro = btcRpc('getblockchaininfo') checkForks(ro) ro = nmcRpc('getwalletinfo') print('nmcRpc', ro) signal.signal(signal.SIGINT, signal_handler) cls.update_thread = threading.Thread(target=run_loop, args=(cls,)) cls.update_thread.start() cls.coins_update_thread = threading.Thread(target=run_coins_loop, args=(cls,)) cls.coins_update_thread.start() # Wait for height, or sequencelock is thrown off by genesis blocktime num_blocks = 3 logging.info('Waiting for Particl chain height %d', num_blocks) for i in range(60): particl_blocks = cls.swap_clients[0].callrpc('getblockchaininfo')['blocks'] print('particl_blocks', particl_blocks) if particl_blocks >= num_blocks: break delay_event.wait(1) assert(particl_blocks >= num_blocks)
def setUpClass(cls): super(Test, cls).setUpClass() cls.update_thread = None cls.coins_update_thread = None cls.http_threads = [] cls.swap_clients = [] cls.part_daemons = [] cls.btc_daemons = [] cls.part_stakelimit = 0 cls.btc_addr = None logger.propagate = False logger.handlers = [] logger.setLevel( logging.INFO) # DEBUG shows many messages from requests.post formatter = logging.Formatter( '%(asctime)s %(levelname)s : %(message)s') stream_stdout = logging.StreamHandler() stream_stdout.setFormatter(formatter) logger.addHandler(stream_stdout) if os.path.isdir(TEST_DIR): logging.info('Removing ' + TEST_DIR) shutil.rmtree(TEST_DIR) if not os.path.exists(TEST_DIR): os.makedirs(TEST_DIR) cls.stream_fp = logging.FileHandler(os.path.join(TEST_DIR, 'test.log')) cls.stream_fp.setFormatter(formatter) logger.addHandler(cls.stream_fp) try: logging.info('Preparing coin nodes.') for i in range(NUM_NODES): prepareDataDir(TEST_DIR, i, 'particl.conf', 'part_') cls.part_daemons.append( startDaemon(os.path.join(TEST_DIR, 'part_' + str(i)), cfg.PARTICL_BINDIR, cfg.PARTICLD)) logging.info('Started %s %d', cfg.PARTICLD, cls.part_daemons[-1].pid) for i in range(NUM_NODES): # Load mnemonics after all nodes have started to avoid staking getting stuck in TryToSync rpc = make_rpc_func(i) waitForRPC(rpc) if i == 0: rpc('extkeyimportmaster', [ 'abandon baby cabbage dad eager fabric gadget habit ice kangaroo lab absorb' ]) elif i == 1: rpc('extkeyimportmaster', [ 'pact mammal barrel matrix local final lecture chunk wasp survey bid various book strong spread fall ozone daring like topple door fatigue limb olympic', '', 'true' ]) rpc('getnewextaddress', ['lblExtTest']) rpc('rescanblockchain') else: rpc('extkeyimportmaster', [rpc('mnemonic', ['new'])['master']]) # Lower output split threshold for more stakeable outputs rpc('walletsettings', [ 'stakingoptions', { 'stakecombinethreshold': 100, 'stakesplitthreshold': 200 } ]) for i in range(NUM_BTC_NODES): prepareDataDir(TEST_DIR, i, 'bitcoin.conf', 'btc_', base_p2p_port=BTC_BASE_PORT, base_rpc_port=BTC_BASE_RPC_PORT) cls.btc_daemons.append( startDaemon(os.path.join(TEST_DIR, 'btc_' + str(i)), cfg.BITCOIN_BINDIR, cfg.BITCOIND)) logging.info('Started %s %d', cfg.BITCOIND, cls.part_daemons[-1].pid) waitForRPC(make_rpc_func(i, base_rpc_port=BTC_BASE_RPC_PORT)) logging.info('Preparing swap clients.') eckey = ECKey() eckey.generate() cls.network_key = toWIF(PREFIX_SECRET_KEY_REGTEST, eckey.get_bytes()) cls.network_pubkey = eckey.get_pubkey().get_bytes().hex() for i in range(NUM_NODES): prepare_swapclient_dir(TEST_DIR, i, cls.network_key, cls.network_pubkey) basicswap_dir = os.path.join( os.path.join(TEST_DIR, 'basicswap_' + str(i))) settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME) with open(settings_path) as fs: settings = json.load(fs) fp = open(os.path.join(basicswap_dir, 'basicswap.log'), 'w') sc = BasicSwap(fp, basicswap_dir, settings, 'regtest', log_name='BasicSwap{}'.format(i)) sc.setDaemonPID(Coins.BTC, cls.btc_daemons[i].pid) sc.setDaemonPID(Coins.PART, cls.part_daemons[i].pid) sc.start() cls.swap_clients.append(sc) t = HttpThread(cls.swap_clients[i].fp, TEST_HTTP_HOST, TEST_HTTP_PORT + i, False, cls.swap_clients[i]) cls.http_threads.append(t) t.start() cls.btc_addr = callnoderpc(0, 'getnewaddress', ['mining_addr', 'bech32'], base_rpc_port=BTC_BASE_RPC_PORT) num_blocks = 500 logging.info('Mining %d Bitcoin blocks to %s', num_blocks, cls.btc_addr) callnoderpc(0, 'generatetoaddress', [num_blocks, cls.btc_addr], base_rpc_port=BTC_BASE_RPC_PORT) checkForks( callnoderpc(0, 'getblockchaininfo', base_rpc_port=BTC_BASE_RPC_PORT)) logging.info('Starting update thread.') signal.signal(signal.SIGINT, signal_handler) cls.update_thread = threading.Thread(target=run_loop, args=(cls, )) cls.update_thread.start() cls.coins_update_thread = threading.Thread(target=run_coins_loop, args=(cls, )) cls.coins_update_thread.start() except Exception: traceback.print_exc() Test.tearDownClass() raise ValueError('setUpClass() failed.')
def runClient(fp, data_dir, chain, test_mode): global swap_client settings_path = os.path.join(data_dir, 'basicswap.json') pids_path = os.path.join(data_dir, '.pids') if not os.path.exists(settings_path): raise ValueError('Settings file not found: ' + str(settings_path)) with open(settings_path) as fs: settings = json.load(fs) swap_client = BasicSwap(fp, data_dir, settings, chain) daemons = [] pids = [] threads = [] if os.path.exists(pids_path): with open(pids_path) as fd: for ln in fd: # TODO: try close logger.warning('Found pid for daemon {} '.format(ln.strip())) # Ensure daemons are stopped swap_client.stopDaemons() try: # Try start daemons for c, v in settings['chainclients'].items(): if v['manage_daemon'] is True: logger.info('Starting {} daemon'.format(c.capitalize())) filename = c + 'd' + ('.exe' if os.name == 'nt' else '') daemons.append(startDaemon(v['datadir'], v['bindir'], filename)) pid = daemons[-1].pid pids.append((c, pid)) swap_client.setDaemonPID(c, pid) logger.info('Started {} {}'.format(filename, pid)) if len(pids) > 0: with open(pids_path, 'w') as fd: for p in pids: fd.write('{}:{}\n'.format(*p)) if not test_mode: # Signal only works in main thread signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) swap_client.start() if 'htmlhost' in settings: swap_client.log.info('Starting server at %s:%d.' % (settings['htmlhost'], settings['htmlport'])) allow_cors = settings[ 'allowcors'] if 'allowcors' in settings else ALLOW_CORS tS1 = HttpThread(fp, settings['htmlhost'], settings['htmlport'], allow_cors, swap_client) threads.append(tS1) tS1.start() logger.info('Exit with Ctrl + c.') while swap_client.is_running: time.sleep(0.5) swap_client.update() except Exception as ex: traceback.print_exc() swap_client.log.info('Stopping threads.') for t in threads: t.stop() t.join() closed_pids = [] for d in daemons: int_pid = d.pid logger.info('Terminating {}'.format(int_pid)) try: d.terminate() d.wait(timeout=120) if d.stdout: d.stdout.close() if d.stderr: d.stderr.close() if d.stdin: d.stdin.close() closed_pids.append(int_pid) except Exception as ex: logger.error('Error: {}'.format(ex)) if os.path.exists(pids_path): with open(pids_path) as fd: lines = fd.read().split('\n') still_running = '' for ln in lines: try: if not int(ln.split(':')[1]) in closed_pids: still_running += ln + '\n' except Exception: pass with open(pids_path, 'w') as fd: fd.write(still_running)
def setUpClass(cls): super(Test, cls).setUpClass() eckey = ECKey() eckey.generate() cls.network_key = toWIF(PREFIX_SECRET_KEY_REGTEST, eckey.get_bytes()) cls.network_pubkey = eckey.get_pubkey().get_bytes().hex() if os.path.isdir(cfg.DATADIRS): logging.info('Removing ' + cfg.DATADIRS) shutil.rmtree(cfg.DATADIRS) for i in range(NUM_NODES): prepareDir(cfg.DATADIRS, i, cls.network_key, cls.network_pubkey) prepareOtherDir(cfg.DATADIRS, NMC_NODE) prepareOtherDir(cfg.DATADIRS, BTC_NODE, 'bitcoin.conf') cls.daemons = [] cls.swap_clients = [] cls.daemons.append( startDaemon(BTC_NODE, cfg.BITCOIN_BINDIR, cfg.BITCOIND)) logging.info('Started %s %d', cfg.BITCOIND, cls.daemons[-1].pid) cls.daemons.append( startDaemon(NMC_NODE, cfg.NAMECOIN_BINDIR, cfg.NAMECOIND)) logging.info('Started %s %d', cfg.NAMECOIND, cls.daemons[-1].pid) for i in range(NUM_NODES): cls.daemons.append(startDaemon(i)) logging.info('Started %s %d', cfg.PARTICLD, cls.daemons[-1].pid) time.sleep(1) for i in range(NUM_NODES): basicswap_dir = os.path.join(os.path.join(cfg.DATADIRS, str(i)), 'basicswap') settings_path = os.path.join(basicswap_dir, 'basicswap.json') with open(settings_path) as fs: settings = json.load(fs) fp = open(os.path.join(basicswap_dir, 'basicswap.log'), 'w') cls.swap_clients.append( BasicSwap(fp, basicswap_dir, settings, 'regtest', log_name='BasicSwap{}'.format(i))) cls.swap_clients[-1].setDaemonPID(Coins.BTC, cls.daemons[0].pid) cls.swap_clients[-1].setDaemonPID(Coins.NMC, cls.daemons[1].pid) cls.swap_clients[-1].setDaemonPID(Coins.PART, cls.daemons[2 + i].pid) cls.swap_clients[-1].start() cls.swap_clients[0].callrpc('extkeyimportmaster', [ 'abandon baby cabbage dad eager fabric gadget habit ice kangaroo lab absorb' ]) cls.swap_clients[1].callrpc('extkeyimportmaster', [ 'pact mammal barrel matrix local final lecture chunk wasp survey bid various book strong spread fall ozone daring like topple door fatigue limb olympic', '', 'true' ]) cls.swap_clients[1].callrpc('getnewextaddress', ['lblExtTest']) cls.swap_clients[1].callrpc('rescanblockchain') waitForRPC(nmcRpc) num_blocks = 500 logging.info('Mining %d namecoin blocks', num_blocks) cls.nmc_addr = nmcRpc('getnewaddress mining_addr legacy') nmcRpc('generatetoaddress {} {}'.format(num_blocks, cls.nmc_addr)) ro = nmcRpc('getblockchaininfo') try: assert (ro['bip9_softforks']['csv']['status'] == 'active') except Exception: logging.info('nmc: csv is not active') try: assert (ro['bip9_softforks']['segwit']['status'] == 'active') except Exception: logging.info('nmc: segwit is not active') waitForRPC(btcRpc) cls.btc_addr = btcRpc('getnewaddress mining_addr bech32') logging.info('Mining %d bitcoin blocks to %s', num_blocks, cls.btc_addr) btcRpc('generatetoaddress {} {}'.format(num_blocks, cls.btc_addr)) ro = btcRpc('getblockchaininfo') assert (ro['bip9_softforks']['csv']['status'] == 'active') assert (ro['bip9_softforks']['segwit']['status'] == 'active') ro = nmcRpc('getwalletinfo') print('nmcRpc', ro) cls.http_threads = [] host = '0.0.0.0' # All interfaces (docker) for i in range(3): t = HttpThread(cls.swap_clients[i].fp, host, TEST_HTML_PORT + i, False, cls.swap_clients[i]) cls.http_threads.append(t) t.start() signal.signal(signal.SIGINT, signal_handler) cls.update_thread = threading.Thread(target=run_loop, args=(cls, )) cls.update_thread.start()
def setUpClass(cls): super(Test, cls).setUpClass() eckey = ECKey() eckey.generate() cls.network_key = toWIF(PREFIX_SECRET_KEY_REGTEST, eckey.get_bytes()) cls.network_pubkey = eckey.get_pubkey().get_bytes().hex() if os.path.isdir(cfg.TEST_DATADIRS): logging.info('Removing ' + cfg.TEST_DATADIRS) shutil.rmtree(cfg.TEST_DATADIRS) for i in range(NUM_NODES): data_dir = prepareDir(cfg.TEST_DATADIRS, i, cls.network_key, cls.network_pubkey) callrpc_cli(cfg.PARTICL_BINDIR, data_dir, 'regtest', '-wallet=wallet.dat create', 'particl-wallet') # Necessary for 0.21 prepareOtherDir(cfg.TEST_DATADIRS, LTC_NODE) data_dir = prepareOtherDir(cfg.TEST_DATADIRS, BTC_NODE, 'bitcoin.conf') callrpc_cli(cfg.BITCOIN_BINDIR, data_dir, 'regtest', '-wallet=wallet.dat create', 'bitcoin-wallet') # Necessary for 0.21 cls.daemons = [] cls.swap_clients = [] cls.http_threads = [] cls.daemons.append(startDaemon(os.path.join(cfg.TEST_DATADIRS, str(BTC_NODE)), cfg.BITCOIN_BINDIR, cfg.BITCOIND)) logging.info('Started %s %d', cfg.BITCOIND, cls.daemons[-1].pid) cls.daemons.append(startDaemon(os.path.join(cfg.TEST_DATADIRS, str(LTC_NODE)), cfg.LITECOIN_BINDIR, cfg.LITECOIND)) logging.info('Started %s %d', cfg.LITECOIND, cls.daemons[-1].pid) for i in range(NUM_NODES): cls.daemons.append(startDaemon(os.path.join(cfg.TEST_DATADIRS, str(i)), cfg.PARTICL_BINDIR, cfg.PARTICLD)) logging.info('Started %s %d', cfg.PARTICLD, cls.daemons[-1].pid) for i in range(NUM_NODES): # Load mnemonics after all nodes have started to avoid staking getting stuck in TryToSync rpc = make_part_cli_rpc_func(i) waitForRPC(rpc) if i == 0: rpc('extkeyimportmaster', ['abandon baby cabbage dad eager fabric gadget habit ice kangaroo lab absorb']) elif i == 1: rpc('extkeyimportmaster', ['pact mammal barrel matrix local final lecture chunk wasp survey bid various book strong spread fall ozone daring like topple door fatigue limb olympic', '', 'true']) rpc('getnewextaddress', ['lblExtTest']) rpc('rescanblockchain') else: rpc('extkeyimportmaster', [rpc('mnemonic', ['new'])['master']]) # Lower output split threshold for more stakeable outputs rpc('walletsettings', ['stakingoptions', {'stakecombinethreshold': 100, 'stakesplitthreshold': 200}]) basicswap_dir = os.path.join(os.path.join(cfg.TEST_DATADIRS, str(i)), 'basicswap') settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME) with open(settings_path) as fs: settings = json.load(fs) fp = open(os.path.join(basicswap_dir, 'basicswap.log'), 'w') sc = BasicSwap(fp, basicswap_dir, settings, 'regtest', log_name='BasicSwap{}'.format(i)) sc.setDaemonPID(Coins.BTC, cls.daemons[0].pid) sc.setDaemonPID(Coins.LTC, cls.daemons[1].pid) sc.setDaemonPID(Coins.PART, cls.daemons[2 + i].pid) sc.start() cls.swap_clients.append(sc) t = HttpThread(cls.swap_clients[i].fp, TEST_HTTP_HOST, TEST_HTTP_PORT + i, False, cls.swap_clients[i]) cls.http_threads.append(t) t.start() waitForRPC(ltcRpc) num_blocks = 500 logging.info('Mining %d litecoin blocks', num_blocks) cls.ltc_addr = ltcRpc('getnewaddress mining_addr legacy') ltcRpc('generatetoaddress {} {}'.format(num_blocks, cls.ltc_addr)) ro = ltcRpc('getblockchaininfo') checkForks(ro) waitForRPC(btcRpc) cls.btc_addr = btcRpc('getnewaddress mining_addr bech32') logging.info('Mining %d Bitcoin blocks to %s', num_blocks, cls.btc_addr) btcRpc('generatetoaddress {} {}'.format(num_blocks, cls.btc_addr)) ro = btcRpc('getblockchaininfo') checkForks(ro) ro = ltcRpc('getwalletinfo') print('ltcRpc', ro) signal.signal(signal.SIGINT, signal_handler) cls.update_thread = threading.Thread(target=run_loop, args=(cls,)) cls.update_thread.start() cls.coins_update_thread = threading.Thread(target=run_coins_loop, args=(cls,)) cls.coins_update_thread.start() # Wait for height, or sequencelock is thrown off by genesis blocktime num_blocks = 3 logging.info('Waiting for Particl chain height %d', num_blocks) for i in range(60): particl_blocks = cls.swap_clients[0].callrpc('getblockchaininfo')['blocks'] print('particl_blocks', particl_blocks) if particl_blocks >= num_blocks: break test_delay_event.wait(1) assert(particl_blocks >= num_blocks)
def runClient(fp, data_dir, chain): global swap_client settings_path = os.path.join(data_dir, cfg.CONFIG_FILENAME) pids_path = os.path.join(data_dir, '.pids') if not os.path.exists(settings_path): raise ValueError('Settings file not found: ' + str(settings_path)) with open(settings_path) as fs: settings = json.load(fs) swap_client = BasicSwap(fp, data_dir, settings, chain) daemons = [] pids = [] threads = [] if os.path.exists(pids_path): with open(pids_path) as fd: for ln in fd: # TODO: try close logger.warning('Found pid for daemon {} '.format(ln.strip())) # Ensure daemons are stopped swap_client.stopDaemons() try: # Try start daemons for c, v in settings['chainclients'].items(): if c == 'monero': if v['manage_daemon'] is True: logger.info('Starting {} daemon'.format(c.capitalize())) daemons.append( startXmrDaemon(v['datadir'], v['bindir'], 'monerod')) pid = daemons[-1].pid logger.info('Started {} {}'.format('monerod', pid)) if v['manage_wallet_daemon'] is True: logger.info('Starting {} wallet daemon'.format( c.capitalize())) daemons.append( startXmrWalletDaemon(v['datadir'], v['bindir'], 'monero-wallet-rpc')) pid = daemons[-1].pid logger.info('Started {} {}'.format('monero-wallet-rpc', pid)) continue if v['manage_daemon'] is True: logger.info('Starting {} daemon'.format(c.capitalize())) filename = c + 'd' + ('.exe' if os.name == 'nt' else '') daemons.append(startDaemon(v['datadir'], v['bindir'], filename)) pid = daemons[-1].pid pids.append((c, pid)) swap_client.setDaemonPID(c, pid) logger.info('Started {} {}'.format(filename, pid)) if len(pids) > 0: with open(pids_path, 'w') as fd: for p in pids: fd.write('{}:{}\n'.format(*p)) signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) swap_client.start() if 'htmlhost' in settings: swap_client.log.info('Starting server at %s:%d.' % (settings['htmlhost'], settings['htmlport'])) allow_cors = settings[ 'allowcors'] if 'allowcors' in settings else cfg.DEFAULT_ALLOW_CORS tS1 = HttpThread(fp, settings['htmlhost'], settings['htmlport'], allow_cors, swap_client) threads.append(tS1) tS1.start() logger.info('Exit with Ctrl + c.') while swap_client.is_running: time.sleep(0.5) swap_client.update() except Exception as ex: traceback.print_exc() swap_client.finalise() swap_client.log.info('Stopping HTTP threads.') for t in threads: t.stop() t.join() closed_pids = [] for d in daemons: logging.info('Interrupting {}'.format(d.pid)) try: d.send_signal(signal.SIGINT) except Exception as e: logging.info('Interrupting %d, error %s', d.pid, str(e)) for d in daemons: try: d.wait(timeout=120) for fp in (d.stdout, d.stderr, d.stdin): if fp: fp.close() closed_pids.append(d.pid) except Exception as ex: logger.error('Error: {}'.format(ex)) if os.path.exists(pids_path): with open(pids_path) as fd: lines = fd.read().split('\n') still_running = '' for ln in lines: try: if not int(ln.split(':')[1]) in closed_pids: still_running += ln + '\n' except Exception: pass with open(pids_path, 'w') as fd: fd.write(still_running)