factory.py revision 724b8a50f34b85dda9f1990e3e8c5b68edbdb37b
1d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng"""Provides a factory method to create a host object."""
2d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng
3d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng
4c5947faa755945f81537c6c33c322dccacac0adeAviv Keshetfrom autotest_lib.client.common_lib import error, global_config
5c6136e92bb5aef1acda979fd303fc855cf704434jadmanskifrom autotest_lib.server import autotest, utils as server_utils
60ca40e28b664c76d62909b1a344738dfb6f7e936Fang Dengfrom autotest_lib.server.hosts import site_factory, cros_host, ssh_host, serial
7431010f31bceddcf92f36e1b82397b9a56ffee54Simran Basifrom autotest_lib.server.hosts import adb_host, logfile_monitor
8431010f31bceddcf92f36e1b82397b9a56ffee54Simran Basi
9e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh
10d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng
11e48bcfb879c943df72a866e3db8b2df8e930b2c1mblighDEFAULT_FOLLOW_PATH = '/var/log/kern.log'
12e48bcfb879c943df72a866e3db8b2df8e930b2c1mblighDEFAULT_PATTERNS_PATH = 'console_patterns'
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
27d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng
28d0672689266d3d63901f3a35fb7e0a2d96d6e39abeepsdef _get_host_arguments():
29d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps    """Returns parameters needed to ssh into a host.
30d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps
31d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps    There are currently 2 use cases for creating a host.
32d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps    1. Through the server_job, in which case the server_job injects
33d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps       the appropriate ssh parameters into our name space and they
34d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps       are available as the variables ssh_user, ssh_pass etc.
35d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps    2. Directly through factory.create_host, in which case we use
36d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps       the same defaults as used in the server job to create a host.
37d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps
38d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps    @returns: A tuple of parameters needed to create an ssh connection, ordered
39d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps              as: ssh_user, ssh_pass, ssh_port, ssh_verbosity, ssh_options.
40d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps    """
41d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps    g = globals()
42d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps    return (g.get('ssh_user', DEFAULT_SSH_USER),
43d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps            g.get('ssh_pass', DEFAULT_SSH_PASS),
44d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps            g.get('ssh_port', DEFAULT_SSH_PORT),
45d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps            g.get('ssh_verbosity_flag', DEFAULT_SSH_VERBOSITY),
46d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps            g.get('ssh_options', DEFAULT_SSH_OPTIONS))
47d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps
48d0672689266d3d63901f3a35fb7e0a2d96d6e39abeeps
49724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basidef _detect_host(connectivity_class, hostname, **args):
50724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi    """Detect host type.
51724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi
52724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi    Currently checks if adb is on the host and if so returns ADBHost if not or
53724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi    if the check fails, it will return CrosHost.
54724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi
55724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi    @param connectivity_class: connectivity class to use to talk to the host
56724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi                               (ParamikoHost or SSHHost)
57724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi    @param hostname: A string representing the host name of the device.
58724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi    @param args: Args that will be passed to the constructor of
59724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi                 the host class.
60724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi
61724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi    @returns Class type to use for this host.
62724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi    """
63724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi    # Detect if adb is on the host. If so we are using an ADBHost. If not use,
64724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi    # CrosHost.
65724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi    try:
66724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi        # Attempt to find adb on the system. If that succeeds use ADBHost.
67724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi        host = connectivity_class(hostname, **args)
68724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi        result = host.run('which adb', timeout=10)
69724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi        return adb_host.ADBHost
70724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi    except (error.AutoservRunError, error.AutoservSSHTimeout):
71724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi        # If any errors occur use CrosHost.
72724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi        # TODO(fdeng): this method should should dynamically discover
73724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi        # and allocate host types, crbug.com/273843
74724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi        # TODO crbug.com/302026 (sbasi) - adjust this pathway for ADBHost in
75724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi        # the future should a host require verify/repair.
76724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi        return cros_host.CrosHost
77724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi
78724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi
79e48bcfb879c943df72a866e3db8b2df8e930b2c1mblighdef create_host(
803693fc8d1136f17c47bac3e4a2faeb525301e05aDale Curtis    hostname, auto_monitor=False, follow_paths=None, pattern_paths=None,
81724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi    netconsole=False, **args):
82d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng    """Create a host object.
83d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng
84d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng    This method mixes host classes that are needed into a new subclass
85d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng    and creates a instance of the new class.
86d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng
87d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng    @param hostname: A string representing the host name of the device.
88d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng    @param auto_monitor: A boolean value, if True, will try to mix
89d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng                         SerialHost in. If the host supports use as SerialHost,
90d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng                         will not mix in LogfileMonitorMixin anymore.
91d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng                         If the host doesn't support it, will
92d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng                         fall back to direct demesg logging and mix
93d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng                         LogfileMonitorMixin in.
94d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng    @param follow_paths: A list, passed to LogfileMonitorMixin,
95d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng                         remote paths to monitor.
96d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng    @param pattern_paths: A list, passed to LogfileMonitorMixin,
97d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng                          local paths to alert pattern definition files.
98d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng    @param netconsole: A boolean value, if True, will mix NetconsoleHost in.
99d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng    @param args: Args that will be passed to the constructor of
100d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng                 the new host class.
101431010f31bceddcf92f36e1b82397b9a56ffee54Simran Basi    @param adb: If True creates an instance of adb_host not cros_host.
102d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng
103d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng    @returns: A host object which is an instance of the newly created
104d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng              host class.
105d1c2b73b7a1cbc74701ddc2b6bbbb3a162ace047Fang Deng    """
10696667caad23538696f737100803e68a1c1ecf357Fang Deng
107724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi    ssh_user, ssh_pass, ssh_port, ssh_verbosity_flag, ssh_options = \
108724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi            _get_host_arguments()
109724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi
110724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi    hostname, args['user'], args['password'], args['port'] = \
111724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi            server_utils.parse_machine(hostname, ssh_user, ssh_pass, ssh_port)
112724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi    args['ssh_verbosity_flag'] = ssh_verbosity_flag
113724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi    args['ssh_options'] = ssh_options
114431010f31bceddcf92f36e1b82397b9a56ffee54Simran Basi
115635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski    # by default assume we're using SSH support
11655552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh    if SSH_ENGINE == 'paramiko':
11755552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh        from autotest_lib.server.hosts import paramiko_host
118724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi        connectivity_class = paramiko_host.ParamikoHost
11955552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh    elif SSH_ENGINE == 'raw_ssh':
120724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi        connectivity_class = ssh_host.SSHHost
12155552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh    else:
12255552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh        raise error.AutoServError("Unknown SSH engine %s. Please verify the "
12355552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh                                  "value of the configuration key 'ssh_engine' "
12455552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh                                  "on autotest's global_config.ini file." %
12555552bf4a54d847f2cc30b307b3636c2be2ad5a2mbligh                                  SSH_ENGINE)
126635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski
127724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi    classes = [_detect_host(connectivity_class, hostname, **args),
128724b8a50f34b85dda9f1990e3e8c5b68edbdb37bSimran Basi               connectivity_class]
129c6136e92bb5aef1acda979fd303fc855cf704434jadmanski    # by default mix in run_test support
130c6136e92bb5aef1acda979fd303fc855cf704434jadmanski    classes.append(autotest.AutotestHostMixin)
131c6136e92bb5aef1acda979fd303fc855cf704434jadmanski
132cb4aac7441db2fa1880d06ba57b1ab354fdbc18ajadmanski    # if the user really wants to use netconsole, let them
133cb4aac7441db2fa1880d06ba57b1ab354fdbc18ajadmanski    if netconsole:
134cb4aac7441db2fa1880d06ba57b1ab354fdbc18ajadmanski        classes.append(netconsole.NetconsoleHost)
135cb4aac7441db2fa1880d06ba57b1ab354fdbc18ajadmanski
13654f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski    if auto_monitor:
13754f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski        # use serial console support if it's available
13854f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski        conmux_args = {}
13954f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski        for key in ("conmux_server", "conmux_attach"):
14054f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski            if key in args:
14154f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski                conmux_args[key] = args[key]
14254f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski        if serial.SerialHost.host_is_supported(hostname, **conmux_args):
14354f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski            classes.append(serial.SerialHost)
144635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski        else:
145af959a4e2909cd0013cc58d22ca4527570995319jadmanski            # no serial available, fall back to direct dmesg logging
146af959a4e2909cd0013cc58d22ca4527570995319jadmanski            if follow_paths is None:
147af959a4e2909cd0013cc58d22ca4527570995319jadmanski                follow_paths = [DEFAULT_FOLLOW_PATH]
14854f90af69daac8a781678f0ccd42d6728d5d81d1jadmanski            else:
149af959a4e2909cd0013cc58d22ca4527570995319jadmanski                follow_paths = list(follow_paths) + [DEFAULT_FOLLOW_PATH]
150e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh
151af959a4e2909cd0013cc58d22ca4527570995319jadmanski            if pattern_paths is None:
152af959a4e2909cd0013cc58d22ca4527570995319jadmanski                pattern_paths = [DEFAULT_PATTERNS_PATH]
153af959a4e2909cd0013cc58d22ca4527570995319jadmanski            else:
154af959a4e2909cd0013cc58d22ca4527570995319jadmanski                pattern_paths = (
155af959a4e2909cd0013cc58d22ca4527570995319jadmanski                    list(pattern_paths) + [DEFAULT_PATTERNS_PATH])
156e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh
157af959a4e2909cd0013cc58d22ca4527570995319jadmanski            logfile_monitor_class = logfile_monitor.NewLogfileMonitorMixin(
158af959a4e2909cd0013cc58d22ca4527570995319jadmanski                follow_paths, pattern_paths)
159af959a4e2909cd0013cc58d22ca4527570995319jadmanski            classes.append(logfile_monitor_class)
160e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh
161e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh    elif follow_paths:
162e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh        logfile_monitor_class = logfile_monitor.NewLogfileMonitorMixin(
163e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh            follow_paths, pattern_paths)
164e48bcfb879c943df72a866e3db8b2df8e930b2c1mbligh        classes.append(logfile_monitor_class)
165635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski
166635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski    # do any site-specific processing of the classes list
167d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski    site_factory.postprocess_classes(classes, hostname,
168ea90226c42c24de00839d2c68a04909b233e9a4fjadmanski                                     auto_monitor=auto_monitor, **args)
169635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski
170635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski    # create a custom host class for this machine and return an instance of it
171635b06f6c016fd5e4e14e98c471e92b1f435ac46jadmanski    host_class = type("%s_host" % hostname, tuple(classes), {})
172d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski    host_instance = host_class(hostname, **args)
173d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski
174d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski    # call job_start if this is the first time this host is being used
175d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski    if hostname not in _started_hostnames:
176d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski        host_instance.job_start()
177d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski        _started_hostnames.add(hostname)
178d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski
179d60321a8b012aa6101bcb237341fab5bd2d25a04jadmanski    return host_instance
180