--scan option: specify where to scan if not on localhost Change-Id: I51a694eb3cb045e7d18c19a332db8e6ba063009b
101 lines
3.3 KiB
Python
Executable File
101 lines
3.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# *****************************************************************************
|
|
# Copyright (c) 2015-2024 by the authors, see LICENSE
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify it under
|
|
# the terms of the GNU General Public License as published by the Free Software
|
|
# Foundation; either version 2 of the License, or (at your option) any later
|
|
# version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along with
|
|
# this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
#
|
|
# Module authors:
|
|
# Alexander Lenz <alexander.lenz@frm2.tum.de>
|
|
# Markus Zolliker <markus.zolliker@psi.ch>
|
|
#
|
|
# *****************************************************************************
|
|
|
|
import sys
|
|
import argparse
|
|
import socket
|
|
from pathlib import Path
|
|
|
|
# Add import path for inplace usage
|
|
sys.path.insert(0, str(Path(__file__).absolute().parents[1]))
|
|
|
|
from frappy.client.interactive import init, run, clientenv, interact
|
|
from frappy.protocol.discovery import scan
|
|
|
|
|
|
def parseArgv(argv):
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('-i', '--include',
|
|
help='file to execute after connecting to the clients', metavar='file',
|
|
type=Path, action='append', default=[])
|
|
parser.add_argument('-s', '--scan',
|
|
help='hosts to scan for (-s subnet for all nodes in subnet)',
|
|
action='append', default=[])
|
|
parser.add_argument('-o', '--only-execute',
|
|
help='Do not go into interactive mode after executing files. \
|
|
Has no effect without --include.', action='store_true')
|
|
parser.add_argument('node',
|
|
help='Nodes the client should connect to.\n', metavar='host:port',
|
|
nargs='*', type=str, default=[])
|
|
return parser.parse_args(argv)
|
|
|
|
|
|
def own_ip():
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
s.settimeout(0)
|
|
try:
|
|
# doesn't even have to be reachable
|
|
s.connect(('10.254.254.254', 1))
|
|
return s.getsockname()[0]
|
|
except Exception:
|
|
return '127.0.0.1'
|
|
finally:
|
|
s.close()
|
|
|
|
|
|
args = parseArgv(sys.argv[1:])
|
|
|
|
nodes = args.node
|
|
hosts = args.scan
|
|
if not nodes and not hosts:
|
|
host = ['localhost']
|
|
if hosts:
|
|
answers = []
|
|
for host in hosts:
|
|
ans = scan()
|
|
if host == 'subnet': # all in subnet
|
|
answers.extend(ans)
|
|
else: # filter by ip
|
|
ip = socket.gethostbyname(host)
|
|
if ip == '127.0.0.1':
|
|
ip = own_ip()
|
|
answers.extend(a for a in ans if a.address == ip)
|
|
nodes.extend(f'{h.hostname}:{h.port}' for h in answers)
|
|
success = init(*nodes)
|
|
|
|
run_error = ''
|
|
file_success = False
|
|
try:
|
|
for file in args.include:
|
|
run(file)
|
|
file_success = True
|
|
except Exception as e:
|
|
run_error = f'\n{clientenv.short_traceback()}'
|
|
|
|
if success:
|
|
if args.include and file_success and args.only_execute:
|
|
print('skipping interactive mode')
|
|
exit()
|
|
interact(run_error)
|