factory.py revision 46dadc9439355f72d394dcc4700902001bd797ff
1d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng"""Provides a factory method to create a host object.""" 2d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng 346dadc9439355f72d394dcc4700902001bd797ffbeepsimport logging 45189dd5255f3cd8d68026b081367c32d135dd9b6Aviv Keshetfrom contextlib import closing 546dadc9439355f72d394dcc4700902001bd797ffbeeps 6c5947faa755945f81537c6c33c322dccacac0adeAviv Keshetfrom autotest_lib.client.common_lib import error, global_config 7c6136e92bb5aef1acda979fd303fc855cf704434jadmanskifrom autotest_lib.server import autotest, utils as server_utils 80ca40e28b664c76d62909b1a344738dfb6f7e936Fang Dengfrom autotest_lib.server.hosts import site_factory, cros_host, ssh_host, serial 946dadc9439355f72d394dcc4700902001bd797ffbeepsfrom autotest_lib.server.hosts import eureka_host 10431010f31bceddcf92f36e1b82397b9a56ffee54Simran Basifrom autotest_lib.server.hosts import adb_host, logfile_monitor 11431010f31bceddcf92f36e1b82397b9a56ffee54Simran Basi 12e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh 13d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng 14e48bcfb879c943df72a866e3db8b2df8e930b2c1mblighDEFAULT_FOLLOW_PATH = '/var/log/kern.log' 15e48bcfb879c943df72a866e3db8b2df8e930b2c1mblighDEFAULT_PATTERNS_PATH = 'console_patterns' 1655552bf4a54d847f2cc30b307b3636c2be2ad5a2mblighSSH_ENGINE = global_config.global_config.get_config_value('AUTOSERV', 1755552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh 'ssh_engine', 1855552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh type=str) 19d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 20d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps# Default ssh options used in creating a host. 21d0672689266d3d63901f3a35fb7e0a2d96d6e39abeepsDEFAULT_SSH_USER = 'root' 22d0672689266d3d63901f3a35fb7e0a2d96d6e39abeepsDEFAULT_SSH_PASS = '' 23d0672689266d3d63901f3a35fb7e0a2d96d6e39abeepsDEFAULT_SSH_PORT = 22 24d0672689266d3d63901f3a35fb7e0a2d96d6e39abeepsDEFAULT_SSH_VERBOSITY = '' 25d0672689266d3d63901f3a35fb7e0a2d96d6e39abeepsDEFAULT_SSH_OPTIONS = '' 26d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 27d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski# for tracking which hostnames have already had job_start called 28d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski_started_hostnames = set() 29d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski 3046dadc9439355f72d394dcc4700902001bd797ffbeeps# A list of all the possible host types, ordered according to frequency of 3146dadc9439355f72d394dcc4700902001bd797ffbeeps# host types in the lab, so the more common hosts don't incur a repeated ssh 3246dadc9439355f72d394dcc4700902001bd797ffbeeps# overhead in checking for less common host types. 3346dadc9439355f72d394dcc4700902001bd797ffbeepshost_types = [cros_host.CrosHost, eureka_host.EurekaHost, adb_host.ADBHost,] 3446dadc9439355f72d394dcc4700902001bd797ffbeeps 35d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng 36d0672689266d3d63901f3a35fb7e0a2d96d6e39abeepsdef _get_host_arguments(): 37d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps """Returns parameters needed to ssh into a host. 38d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 39d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps There are currently 2 use cases for creating a host. 40d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 1. Through the server_job, in which case the server_job injects 41d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps the appropriate ssh parameters into our name space and they 42d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps are available as the variables ssh_user, ssh_pass etc. 43d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 2. Directly through factory.create_host, in which case we use 44d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps the same defaults as used in the server job to create a host. 45d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 46d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps @returns: A tuple of parameters needed to create an ssh connection, ordered 47d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps as: ssh_user, ssh_pass, ssh_port, ssh_verbosity, ssh_options. 48d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps """ 49d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps g = globals() 50d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps return (g.get('ssh_user', DEFAULT_SSH_USER), 51d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps g.get('ssh_pass', DEFAULT_SSH_PASS), 52d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps g.get('ssh_port', DEFAULT_SSH_PORT), 53d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps g.get('ssh_verbosity_flag', DEFAULT_SSH_VERBOSITY), 54d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps g.get('ssh_options', DEFAULT_SSH_OPTIONS)) 55d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 56d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 57724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basidef _detect_host(connectivity_class, hostname, **args): 58724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi """Detect host type. 59724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi 6046dadc9439355f72d394dcc4700902001bd797ffbeeps Goes through all the possible host classes, calling check_host with a 6146dadc9439355f72d394dcc4700902001bd797ffbeeps basic host object. Currently this is an ssh host, but theoretically it 6246dadc9439355f72d394dcc4700902001bd797ffbeeps can be any host object that the check_host method of appropriate host 6346dadc9439355f72d394dcc4700902001bd797ffbeeps type knows to use. 64724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi 65724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi @param connectivity_class: connectivity class to use to talk to the host 66724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi (ParamikoHost or SSHHost) 67724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi @param hostname: A string representing the host name of the device. 68724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi @param args: Args that will be passed to the constructor of 69724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi the host class. 70724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi 7146dadc9439355f72d394dcc4700902001bd797ffbeeps @returns: Class type of the first host class that returns True to the 7246dadc9439355f72d394dcc4700902001bd797ffbeeps check_host method. 73724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi """ 7446dadc9439355f72d394dcc4700902001bd797ffbeeps # TODO crbug.com/302026 (sbasi) - adjust this pathway for ADBHost in 7546dadc9439355f72d394dcc4700902001bd797ffbeeps # the future should a host require verify/repair. 7646dadc9439355f72d394dcc4700902001bd797ffbeeps with closing(connectivity_class(hostname, **args)) as host: 7746dadc9439355f72d394dcc4700902001bd797ffbeeps for host_module in host_types: 7846dadc9439355f72d394dcc4700902001bd797ffbeeps if host_module.check_host(host, timeout=10): 7946dadc9439355f72d394dcc4700902001bd797ffbeeps return host_module 8046dadc9439355f72d394dcc4700902001bd797ffbeeps 8146dadc9439355f72d394dcc4700902001bd797ffbeeps logging.warning('Unable to apply conventional host detection methods, ' 8246dadc9439355f72d394dcc4700902001bd797ffbeeps 'defaulting to chromeos host.') 8346dadc9439355f72d394dcc4700902001bd797ffbeeps return cros_host.CrosHost 84724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi 85724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi 86e48bcfb879c943df72a866e3db8b2df8e930b2c1mblighdef create_host( 873693fc8d1136f17c47bac3e4a2faeb525301e05aDale Curtis hostname, auto_monitor=False, follow_paths=None, pattern_paths=None, 88724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi netconsole=False, **args): 89d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng """Create a host object. 90d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng 91d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng This method mixes host classes that are needed into a new subclass 92d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng and creates a instance of the new class. 93d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng 94d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng @param hostname: A string representing the host name of the device. 95d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng @param auto_monitor: A boolean value, if True, will try to mix 96d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng SerialHost in. If the host supports use as SerialHost, 97d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng will not mix in LogfileMonitorMixin anymore. 98d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng If the host doesn't support it, will 99d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng fall back to direct demesg logging and mix 100d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng LogfileMonitorMixin in. 101d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng @param follow_paths: A list, passed to LogfileMonitorMixin, 102d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng remote paths to monitor. 103d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng @param pattern_paths: A list, passed to LogfileMonitorMixin, 104d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng local paths to alert pattern definition files. 105d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng @param netconsole: A boolean value, if True, will mix NetconsoleHost in. 106d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng @param args: Args that will be passed to the constructor of 107d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng the new host class. 108431010f31bceddcf92f36e1b82397b9a56ffee54Simran Basi @param adb: If True creates an instance of adb_host not cros_host. 109d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng 110d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng @returns: A host object which is an instance of the newly created 111d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng host class. 112d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng """ 11396667caad23538696f737100803e68a1c1ecf357Fang Deng 114724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi ssh_user, ssh_pass, ssh_port, ssh_verbosity_flag, ssh_options = \ 115724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi _get_host_arguments() 116724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi 117724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi hostname, args['user'], args['password'], args['port'] = \ 118724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi server_utils.parse_machine(hostname, ssh_user, ssh_pass, ssh_port) 119724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi args['ssh_verbosity_flag'] = ssh_verbosity_flag 120724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi args['ssh_options'] = ssh_options 121431010f31bceddcf92f36e1b82397b9a56ffee54Simran Basi 122635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski # by default assume we're using SSH support 12355552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh if SSH_ENGINE == 'paramiko': 12455552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh from autotest_lib.server.hosts import paramiko_host 125724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi connectivity_class = paramiko_host.ParamikoHost 12655552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh elif SSH_ENGINE == 'raw_ssh': 127724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi connectivity_class = ssh_host.SSHHost 12855552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh else: 12955552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh raise error.AutoServError("Unknown SSH engine %s. Please verify the " 13055552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh "value of the configuration key 'ssh_engine' " 13155552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh "on autotest's global_config.ini file." % 13255552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh SSH_ENGINE) 133635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski 134724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi classes = [_detect_host(connectivity_class, hostname, **args), 135724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi connectivity_class] 136c6136e92bb5aef1acda979fd303fc855cf704434jadmanski # by default mix in run_test support 137c6136e92bb5aef1acda979fd303fc855cf704434jadmanski classes.append(autotest.AutotestHostMixin) 138c6136e92bb5aef1acda979fd303fc855cf704434jadmanski 139cb4aac7441db2fa1880d06ba57b1ab354fdbc18ajadmanski # if the user really wants to use netconsole, let them 140cb4aac7441db2fa1880d06ba57b1ab354fdbc18ajadmanski if netconsole: 141cb4aac7441db2fa1880d06ba57b1ab354fdbc18ajadmanski classes.append(netconsole.NetconsoleHost) 142cb4aac7441db2fa1880d06ba57b1ab354fdbc18ajadmanski 14354f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski if auto_monitor: 14454f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski # use serial console support if it's available 14554f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski conmux_args = {} 14654f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski for key in ("conmux_server", "conmux_attach"): 14754f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski if key in args: 14854f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski conmux_args[key] = args[key] 14954f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski if serial.SerialHost.host_is_supported(hostname, **conmux_args): 15054f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski classes.append(serial.SerialHost) 151635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski else: 152af959a4e2909cd0013cc58d22ca4527570995319jadmanski # no serial available, fall back to direct dmesg logging 153af959a4e2909cd0013cc58d22ca4527570995319jadmanski if follow_paths is None: 154af959a4e2909cd0013cc58d22ca4527570995319jadmanski follow_paths = [DEFAULT_FOLLOW_PATH] 15554f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski else: 156af959a4e2909cd0013cc58d22ca4527570995319jadmanski follow_paths = list(follow_paths) + [DEFAULT_FOLLOW_PATH] 157e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh 158af959a4e2909cd0013cc58d22ca4527570995319jadmanski if pattern_paths is None: 159af959a4e2909cd0013cc58d22ca4527570995319jadmanski pattern_paths = [DEFAULT_PATTERNS_PATH] 160af959a4e2909cd0013cc58d22ca4527570995319jadmanski else: 161af959a4e2909cd0013cc58d22ca4527570995319jadmanski pattern_paths = ( 162af959a4e2909cd0013cc58d22ca4527570995319jadmanski list(pattern_paths) + [DEFAULT_PATTERNS_PATH]) 163e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh 164af959a4e2909cd0013cc58d22ca4527570995319jadmanski logfile_monitor_class = logfile_monitor.NewLogfileMonitorMixin( 165af959a4e2909cd0013cc58d22ca4527570995319jadmanski follow_paths, pattern_paths) 166af959a4e2909cd0013cc58d22ca4527570995319jadmanski classes.append(logfile_monitor_class) 167e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh 168e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh elif follow_paths: 169e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh logfile_monitor_class = logfile_monitor.NewLogfileMonitorMixin( 170e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh follow_paths, pattern_paths) 171e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh classes.append(logfile_monitor_class) 172635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski 173635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski # do any site-specific processing of the classes list 174d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski site_factory.postprocess_classes(classes, hostname, 175ea90226c42c24de00839d2c68a04909b233e9a4fjadmanski auto_monitor=auto_monitor, **args) 176635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski 177635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski # create a custom host class for this machine and return an instance of it 178635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski host_class = type("%s_host" % hostname, tuple(classes), {}) 179d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski host_instance = host_class(hostname, **args) 180d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski 181d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski # call job_start if this is the first time this host is being used 182d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski if hostname not in _started_hostnames: 183d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski host_instance.job_start() 184d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski _started_hostnames.add(hostname) 185d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski 186d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski return host_instance 187