factory.py revision e5f7ae44738af9f6138103e7c57c26b415486ce8
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 9e5f7ae44738af9f6138103e7c57c26b415486ce8Simran Basifrom autotest_lib.server.hosts import moblab_host, sonic_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. 33e5f7ae44738af9f6138103e7c57c26b415486ce8Simran Basihost_types = [cros_host.CrosHost, moblab_host.MoblabHost, sonic_host.SonicHost, 34e5f7ae44738af9f6138103e7c57c26b415486ce8Simran Basi adb_host.ADBHost,] 3546dadc9439355f72d394dcc4700902001bd797ffbeeps 36d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng 37d0672689266d3d63901f3a35fb7e0a2d96d6e39abeepsdef _get_host_arguments(): 38d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps """Returns parameters needed to ssh into a host. 39d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 40d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps There are currently 2 use cases for creating a host. 41d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 1. Through the server_job, in which case the server_job injects 42d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps the appropriate ssh parameters into our name space and they 43d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps are available as the variables ssh_user, ssh_pass etc. 44d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 2. Directly through factory.create_host, in which case we use 45d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps the same defaults as used in the server job to create a host. 46d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 47d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps @returns: A tuple of parameters needed to create an ssh connection, ordered 48d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps as: ssh_user, ssh_pass, ssh_port, ssh_verbosity, ssh_options. 49d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps """ 50d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps g = globals() 51d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps return (g.get('ssh_user', DEFAULT_SSH_USER), 52d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps g.get('ssh_pass', DEFAULT_SSH_PASS), 53d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps g.get('ssh_port', DEFAULT_SSH_PORT), 54d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps g.get('ssh_verbosity_flag', DEFAULT_SSH_VERBOSITY), 55d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps g.get('ssh_options', DEFAULT_SSH_OPTIONS)) 56d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 57d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 58724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basidef _detect_host(connectivity_class, hostname, **args): 59724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi """Detect host type. 60724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi 6146dadc9439355f72d394dcc4700902001bd797ffbeeps Goes through all the possible host classes, calling check_host with a 6246dadc9439355f72d394dcc4700902001bd797ffbeeps basic host object. Currently this is an ssh host, but theoretically it 6346dadc9439355f72d394dcc4700902001bd797ffbeeps can be any host object that the check_host method of appropriate host 6446dadc9439355f72d394dcc4700902001bd797ffbeeps type knows to use. 65724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi 66724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi @param connectivity_class: connectivity class to use to talk to the host 67724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi (ParamikoHost or SSHHost) 68724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi @param hostname: A string representing the host name of the device. 69724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi @param args: Args that will be passed to the constructor of 70724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi the host class. 71724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi 7246dadc9439355f72d394dcc4700902001bd797ffbeeps @returns: Class type of the first host class that returns True to the 7346dadc9439355f72d394dcc4700902001bd797ffbeeps check_host method. 74724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi """ 7546dadc9439355f72d394dcc4700902001bd797ffbeeps # TODO crbug.com/302026 (sbasi) - adjust this pathway for ADBHost in 7646dadc9439355f72d394dcc4700902001bd797ffbeeps # the future should a host require verify/repair. 7746dadc9439355f72d394dcc4700902001bd797ffbeeps with closing(connectivity_class(hostname, **args)) as host: 7846dadc9439355f72d394dcc4700902001bd797ffbeeps for host_module in host_types: 7946dadc9439355f72d394dcc4700902001bd797ffbeeps if host_module.check_host(host, timeout=10): 8046dadc9439355f72d394dcc4700902001bd797ffbeeps return host_module 8146dadc9439355f72d394dcc4700902001bd797ffbeeps 8246dadc9439355f72d394dcc4700902001bd797ffbeeps logging.warning('Unable to apply conventional host detection methods, ' 8346dadc9439355f72d394dcc4700902001bd797ffbeeps 'defaulting to chromeos host.') 8446dadc9439355f72d394dcc4700902001bd797ffbeeps return cros_host.CrosHost 85724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi 86724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi 87e48bcfb879c943df72a866e3db8b2df8e930b2c1mblighdef create_host( 883693fc8d1136f17c47bac3e4a2faeb525301e05aDale Curtis hostname, auto_monitor=False, follow_paths=None, pattern_paths=None, 89724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi netconsole=False, **args): 90d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng """Create a host object. 91d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng 92d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng This method mixes host classes that are needed into a new subclass 93d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng and creates a instance of the new class. 94d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng 95d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng @param hostname: A string representing the host name of the device. 96d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng @param auto_monitor: A boolean value, if True, will try to mix 97d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng SerialHost in. If the host supports use as SerialHost, 98d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng will not mix in LogfileMonitorMixin anymore. 99d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng If the host doesn't support it, will 100d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng fall back to direct demesg logging and mix 101d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng LogfileMonitorMixin in. 102d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng @param follow_paths: A list, passed to LogfileMonitorMixin, 103d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng remote paths to monitor. 104d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng @param pattern_paths: A list, passed to LogfileMonitorMixin, 105d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng local paths to alert pattern definition files. 106d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng @param netconsole: A boolean value, if True, will mix NetconsoleHost in. 107d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng @param args: Args that will be passed to the constructor of 108d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng the new host class. 109431010f31bceddcf92f36e1b82397b9a56ffee54Simran Basi @param adb: If True creates an instance of adb_host not cros_host. 110d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng 111d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng @returns: A host object which is an instance of the newly created 112d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng host class. 113d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng """ 11496667caad23538696f737100803e68a1c1ecf357Fang Deng 115724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi ssh_user, ssh_pass, ssh_port, ssh_verbosity_flag, ssh_options = \ 116724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi _get_host_arguments() 117724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi 118724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi hostname, args['user'], args['password'], args['port'] = \ 119724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi server_utils.parse_machine(hostname, ssh_user, ssh_pass, ssh_port) 120724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi args['ssh_verbosity_flag'] = ssh_verbosity_flag 121724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi args['ssh_options'] = ssh_options 122431010f31bceddcf92f36e1b82397b9a56ffee54Simran Basi 123635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski # by default assume we're using SSH support 12455552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh if SSH_ENGINE == 'paramiko': 12555552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh from autotest_lib.server.hosts import paramiko_host 126724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi connectivity_class = paramiko_host.ParamikoHost 12755552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh elif SSH_ENGINE == 'raw_ssh': 128724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi connectivity_class = ssh_host.SSHHost 12955552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh else: 13055552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh raise error.AutoServError("Unknown SSH engine %s. Please verify the " 13155552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh "value of the configuration key 'ssh_engine' " 13255552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh "on autotest's global_config.ini file." % 13355552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh SSH_ENGINE) 134635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski 135724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi classes = [_detect_host(connectivity_class, hostname, **args), 136724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi connectivity_class] 137c6136e92bb5aef1acda979fd303fc855cf704434jadmanski # by default mix in run_test support 138c6136e92bb5aef1acda979fd303fc855cf704434jadmanski classes.append(autotest.AutotestHostMixin) 139c6136e92bb5aef1acda979fd303fc855cf704434jadmanski 140cb4aac7441db2fa1880d06ba57b1ab354fdbc18ajadmanski # if the user really wants to use netconsole, let them 141cb4aac7441db2fa1880d06ba57b1ab354fdbc18ajadmanski if netconsole: 142cb4aac7441db2fa1880d06ba57b1ab354fdbc18ajadmanski classes.append(netconsole.NetconsoleHost) 143cb4aac7441db2fa1880d06ba57b1ab354fdbc18ajadmanski 14454f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski if auto_monitor: 14554f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski # use serial console support if it's available 14654f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski conmux_args = {} 14754f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski for key in ("conmux_server", "conmux_attach"): 14854f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski if key in args: 14954f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski conmux_args[key] = args[key] 15054f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski if serial.SerialHost.host_is_supported(hostname, **conmux_args): 15154f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski classes.append(serial.SerialHost) 152635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski else: 153af959a4e2909cd0013cc58d22ca4527570995319jadmanski # no serial available, fall back to direct dmesg logging 154af959a4e2909cd0013cc58d22ca4527570995319jadmanski if follow_paths is None: 155af959a4e2909cd0013cc58d22ca4527570995319jadmanski follow_paths = [DEFAULT_FOLLOW_PATH] 15654f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski else: 157af959a4e2909cd0013cc58d22ca4527570995319jadmanski follow_paths = list(follow_paths) + [DEFAULT_FOLLOW_PATH] 158e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh 159af959a4e2909cd0013cc58d22ca4527570995319jadmanski if pattern_paths is None: 160af959a4e2909cd0013cc58d22ca4527570995319jadmanski pattern_paths = [DEFAULT_PATTERNS_PATH] 161af959a4e2909cd0013cc58d22ca4527570995319jadmanski else: 162af959a4e2909cd0013cc58d22ca4527570995319jadmanski pattern_paths = ( 163af959a4e2909cd0013cc58d22ca4527570995319jadmanski list(pattern_paths) + [DEFAULT_PATTERNS_PATH]) 164e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh 165af959a4e2909cd0013cc58d22ca4527570995319jadmanski logfile_monitor_class = logfile_monitor.NewLogfileMonitorMixin( 166af959a4e2909cd0013cc58d22ca4527570995319jadmanski follow_paths, pattern_paths) 167af959a4e2909cd0013cc58d22ca4527570995319jadmanski classes.append(logfile_monitor_class) 168e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh 169e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh elif follow_paths: 170e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh logfile_monitor_class = logfile_monitor.NewLogfileMonitorMixin( 171e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh follow_paths, pattern_paths) 172e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh classes.append(logfile_monitor_class) 173635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski 174635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski # do any site-specific processing of the classes list 175d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski site_factory.postprocess_classes(classes, hostname, 176ea90226c42c24de00839d2c68a04909b233e9a4fjadmanski auto_monitor=auto_monitor, **args) 177635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski 178635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski # create a custom host class for this machine and return an instance of it 179635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski host_class = type("%s_host" % hostname, tuple(classes), {}) 180d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski host_instance = host_class(hostname, **args) 181d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski 182d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski # call job_start if this is the first time this host is being used 183d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski if hostname not in _started_hostnames: 184d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski host_instance.job_start() 185d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski _started_hostnames.add(hostname) 186d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski 187d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski return host_instance 188