factory.py revision 1bf60eb788365f083d0ee8045a6556f906149dec
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 71c3b853b2d9b80c9efcc1a27112731b96d765e6eJ. Richard Barnettefrom autotest_lib.server import utils as server_utils 81c3b853b2d9b80c9efcc1a27112731b96d765e6eJ. Richard Barnettefrom autotest_lib.server.hosts import cros_host, ssh_host 9e5f7ae44738af9f6138103e7c57c26b415486ce8Simran Basifrom autotest_lib.server.hosts import moblab_host, sonic_host 10549beb41550bf954394ca8c3a611397c97745759Kevin Chengfrom autotest_lib.server.hosts import adb_host, testbed 11e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh 12d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng 1355552bf4a54d847f2cc30b307b3636c2be2ad5a2mblighSSH_ENGINE = global_config.global_config.get_config_value('AUTOSERV', 1455552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh 'ssh_engine', 1555552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh type=str) 16d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 17d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps# Default ssh options used in creating a host. 18d0672689266d3d63901f3a35fb7e0a2d96d6e39abeepsDEFAULT_SSH_USER = 'root' 19d0672689266d3d63901f3a35fb7e0a2d96d6e39abeepsDEFAULT_SSH_PASS = '' 20d0672689266d3d63901f3a35fb7e0a2d96d6e39abeepsDEFAULT_SSH_PORT = 22 21d0672689266d3d63901f3a35fb7e0a2d96d6e39abeepsDEFAULT_SSH_VERBOSITY = '' 22d0672689266d3d63901f3a35fb7e0a2d96d6e39abeepsDEFAULT_SSH_OPTIONS = '' 23d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 24d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski# for tracking which hostnames have already had job_start called 25d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski_started_hostnames = set() 26d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski 2746dadc9439355f72d394dcc4700902001bd797ffbeeps# A list of all the possible host types, ordered according to frequency of 2846dadc9439355f72d394dcc4700902001bd797ffbeeps# host types in the lab, so the more common hosts don't incur a repeated ssh 2946dadc9439355f72d394dcc4700902001bd797ffbeeps# overhead in checking for less common host types. 30e5f7ae44738af9f6138103e7c57c26b415486ce8Simran Basihost_types = [cros_host.CrosHost, moblab_host.MoblabHost, sonic_host.SonicHost, 31e5f7ae44738af9f6138103e7c57c26b415486ce8Simran Basi adb_host.ADBHost,] 3246dadc9439355f72d394dcc4700902001bd797ffbeeps 33d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng 34d0672689266d3d63901f3a35fb7e0a2d96d6e39abeepsdef _get_host_arguments(): 35d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps """Returns parameters needed to ssh into a host. 36d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 37d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps There are currently 2 use cases for creating a host. 38d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 1. Through the server_job, in which case the server_job injects 39d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps the appropriate ssh parameters into our name space and they 40d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps are available as the variables ssh_user, ssh_pass etc. 41d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 2. Directly through factory.create_host, in which case we use 42d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps the same defaults as used in the server job to create a host. 43d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 44d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps @returns: A tuple of parameters needed to create an ssh connection, ordered 45d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps as: ssh_user, ssh_pass, ssh_port, ssh_verbosity, ssh_options. 46d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps """ 47d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps g = globals() 48d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps return (g.get('ssh_user', DEFAULT_SSH_USER), 49d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps g.get('ssh_pass', DEFAULT_SSH_PASS), 50d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps g.get('ssh_port', DEFAULT_SSH_PORT), 51d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps g.get('ssh_verbosity_flag', DEFAULT_SSH_VERBOSITY), 52d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps g.get('ssh_options', DEFAULT_SSH_OPTIONS)) 53d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 54d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps 55724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basidef _detect_host(connectivity_class, hostname, **args): 56724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi """Detect host type. 57724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi 5846dadc9439355f72d394dcc4700902001bd797ffbeeps Goes through all the possible host classes, calling check_host with a 5946dadc9439355f72d394dcc4700902001bd797ffbeeps basic host object. Currently this is an ssh host, but theoretically it 6046dadc9439355f72d394dcc4700902001bd797ffbeeps can be any host object that the check_host method of appropriate host 6146dadc9439355f72d394dcc4700902001bd797ffbeeps type knows to use. 62724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi 63724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi @param connectivity_class: connectivity class to use to talk to the host 64724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi (ParamikoHost or SSHHost) 65724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi @param hostname: A string representing the host name of the device. 66724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi @param args: Args that will be passed to the constructor of 67724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi the host class. 68724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi 6946dadc9439355f72d394dcc4700902001bd797ffbeeps @returns: Class type of the first host class that returns True to the 7046dadc9439355f72d394dcc4700902001bd797ffbeeps check_host method. 71724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi """ 7246dadc9439355f72d394dcc4700902001bd797ffbeeps # TODO crbug.com/302026 (sbasi) - adjust this pathway for ADBHost in 7346dadc9439355f72d394dcc4700902001bd797ffbeeps # the future should a host require verify/repair. 7446dadc9439355f72d394dcc4700902001bd797ffbeeps with closing(connectivity_class(hostname, **args)) as host: 7546dadc9439355f72d394dcc4700902001bd797ffbeeps for host_module in host_types: 7646dadc9439355f72d394dcc4700902001bd797ffbeeps if host_module.check_host(host, timeout=10): 7746dadc9439355f72d394dcc4700902001bd797ffbeeps return host_module 7846dadc9439355f72d394dcc4700902001bd797ffbeeps 7946dadc9439355f72d394dcc4700902001bd797ffbeeps logging.warning('Unable to apply conventional host detection methods, ' 8046dadc9439355f72d394dcc4700902001bd797ffbeeps 'defaulting to chromeos host.') 8146dadc9439355f72d394dcc4700902001bd797ffbeeps return cros_host.CrosHost 82724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi 83724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi 841bf60eb788365f083d0ee8045a6556f906149decSimran Basidef create_host(machine, host_class=None, **args): 85d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng """Create a host object. 86d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng 87d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng This method mixes host classes that are needed into a new subclass 88d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng and creates a instance of the new class. 89d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng 901bf60eb788365f083d0ee8045a6556f906149decSimran Basi @param machine: A dict representing the device under test or a String 911bf60eb788365f083d0ee8045a6556f906149decSimran Basi representing the DUT hostname (for legacy caller support). 921bf60eb788365f083d0ee8045a6556f906149decSimran Basi If it is a machine dict, the 'hostname' key is required. 931bf60eb788365f083d0ee8045a6556f906149decSimran Basi Optional 'host_attributes' key will pipe in host_attributes 941bf60eb788365f083d0ee8045a6556f906149decSimran Basi from the autoserv runtime or the AFE. 95a5522a35b55c7cac915cf0b4efc69ead32e26d35Simran Basi @param host_class: Host class to use, if None, will attempt to detect 96a5522a35b55c7cac915cf0b4efc69ead32e26d35Simran Basi the correct class. 97d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng @param args: Args that will be passed to the constructor of 98d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng the new host class. 99d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng 100d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng @returns: A host object which is an instance of the newly created 101d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng host class. 102d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng """ 1031bf60eb788365f083d0ee8045a6556f906149decSimran Basi hostname, host_attributes = server_utils.get_host_info_from_machine( 1041bf60eb788365f083d0ee8045a6556f906149decSimran Basi machine) 1051bf60eb788365f083d0ee8045a6556f906149decSimran Basi args['host_attributes'] = host_attributes 106724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi ssh_user, ssh_pass, ssh_port, ssh_verbosity_flag, ssh_options = \ 107724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi _get_host_arguments() 108724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi 109724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi hostname, args['user'], args['password'], args['port'] = \ 110724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi server_utils.parse_machine(hostname, ssh_user, ssh_pass, ssh_port) 111724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi args['ssh_verbosity_flag'] = ssh_verbosity_flag 112724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi args['ssh_options'] = ssh_options 113431010f31bceddcf92f36e1b82397b9a56ffee54Simran Basi 114635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski # by default assume we're using SSH support 11555552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh if SSH_ENGINE == 'paramiko': 11655552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh from autotest_lib.server.hosts import paramiko_host 117724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi connectivity_class = paramiko_host.ParamikoHost 11855552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh elif SSH_ENGINE == 'raw_ssh': 119724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi connectivity_class = ssh_host.SSHHost 12055552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh else: 12155552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh raise error.AutoServError("Unknown SSH engine %s. Please verify the " 12255552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh "value of the configuration key 'ssh_engine' " 12355552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh "on autotest's global_config.ini file." % 12455552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh SSH_ENGINE) 125635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski 126a5522a35b55c7cac915cf0b4efc69ead32e26d35Simran Basi if not host_class: 127a5522a35b55c7cac915cf0b4efc69ead32e26d35Simran Basi classes = [_detect_host(connectivity_class, hostname, **args), 128a5522a35b55c7cac915cf0b4efc69ead32e26d35Simran Basi connectivity_class] 129a5522a35b55c7cac915cf0b4efc69ead32e26d35Simran Basi else: 130a5522a35b55c7cac915cf0b4efc69ead32e26d35Simran Basi classes = [host_class, connectivity_class] 131635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski 132635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski # create a custom host class for this machine and return an instance of it 133635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski host_class = type("%s_host" % hostname, tuple(classes), {}) 134d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski host_instance = host_class(hostname, **args) 135d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski 136d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski # call job_start if this is the first time this host is being used 137d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski if hostname not in _started_hostnames: 138d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski host_instance.job_start() 139d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski _started_hostnames.add(hostname) 140d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski 141d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski return host_instance 142549beb41550bf954394ca8c3a611397c97745759Kevin Cheng 143549beb41550bf954394ca8c3a611397c97745759Kevin Cheng 144debeb68446967a4319e1d7f9868a8b9abafce944Simran Basidef create_testbed(hostname, **kwargs): 145549beb41550bf954394ca8c3a611397c97745759Kevin Cheng """Create the testbed object. 146549beb41550bf954394ca8c3a611397c97745759Kevin Cheng 147549beb41550bf954394ca8c3a611397c97745759Kevin Cheng @param hostname: The hostname of the test station for this testbed. 148debeb68446967a4319e1d7f9868a8b9abafce944Simran Basi @param kwargs: Keyword args to pass to the testbed initialization. 149549beb41550bf954394ca8c3a611397c97745759Kevin Cheng 150549beb41550bf954394ca8c3a611397c97745759Kevin Cheng @returns: The testbed object with all associated host objects instantiated. 151549beb41550bf954394ca8c3a611397c97745759Kevin Cheng """ 152debeb68446967a4319e1d7f9868a8b9abafce944Simran Basi return testbed.TestBed(hostname, kwargs) 153