local_host.py revision 81de1f4c64c466e2e3f2a2eee1747dff52c80412
1# Copyright 2009 Google Inc. Released under the GPL v2
2
3"""
4This file contains the implementation of a host object for the local machine.
5"""
6
7import httplib, glob, logging, os, platform, socket, urlparse
8from autotest_lib.client.bin import utils
9from autotest_lib.client.common_lib import error, hosts
10
11
12STATEFULDEV_UPDATER='/usr/local/bin/stateful_update'
13UPDATER_BIN='/opt/google/memento_updater/memento_updater.sh'
14UPDATER_CONFIG='/etc/lsb-release'
15
16class LocalHost(hosts.Host):
17    def _initialize(self, hostname=None, bootloader=None, *args, **dargs):
18        super(LocalHost, self)._initialize(*args, **dargs)
19
20        # hostname will be an actual hostname when this client was created
21        # by an autoserv process
22        if not hostname:
23            hostname = platform.node()
24        self.hostname = hostname
25        self.bootloader = bootloader
26
27
28    def wait_up(self, timeout=None):
29        # a local host is always up
30        return True
31
32
33    def run(self, command, timeout=3600, ignore_status=False,
34            stdout_tee=utils.TEE_TO_LOGS, stderr_tee=utils.TEE_TO_LOGS,
35            stdin=None, args=()):
36        """
37        @see common_lib.hosts.Host.run()
38        """
39        try:
40            result = utils.run(
41                command, timeout=timeout, ignore_status=True,
42                stdout_tee=stdout_tee, stderr_tee=stderr_tee, stdin=stdin,
43                args=args)
44        except error.CmdError, e:
45            # this indicates a timeout exception
46            raise error.AutotestHostRunError('command timed out', e.result_obj)
47
48        if not ignore_status and result.exit_status > 0:
49            raise error.AutotestHostRunError('command execution error', result)
50
51        return result
52
53
54    def list_files_glob(self, path_glob):
55        """
56        Get a list of files on a remote host given a glob pattern path.
57        """
58        return glob.glob(path_glob)
59
60
61    def machine_install(self, update_url=None):
62        if not update_url:
63            return False
64
65        # Check that devserver is accepting connections (from autoserv's host)
66        # If we can't talk to it, the machine host probably can't either.
67        auserver_host = urlparse.urlparse(update_url)[1]
68        try:
69            httplib.HTTPConnection(auserver_host).connect()
70        except socket.error:
71            raise error.InstallError('Update server at %s not available' %
72                                     auserver_host)
73
74        logging.info('Installing from %s to: %s' % (update_url, self.hostname))
75
76        self.run('echo "CHROMEOS_DEVSERVER=http://chromeosbuild_server" >> '
77                 '/mnt/stateful_partition/etc/lsb-release')
78
79        # First, attempt dev & test tools update (which don't live on
80        # the rootfs). This must succeed so that the newly installed
81        # host is testable after we run the autoupdater.
82        statefuldev_cmd = ' '.join([STATEFULDEV_UPDATER, update_url])
83        logging.info(statefuldev_cmd)
84        try:
85            self.run(statefuldev_cmd, timeout=1200)
86        except error.AutoservRunError, e:
87            raise error.InstallError('stateful_update failed on %s',
88                                     self.hostname)
89
90        # Run autoupdate command. This tells the autoupdate process on
91        # the host to look for an update at a specific URL and version
92        # string.
93        autoupdate_cmd = ' '.join([UPDATER_BIN, '--omaha_url=%s' % update_url,
94                          '--force_update'])
95        logging.info(autoupdate_cmd)
96        try:
97           self.run('rm -f /tmp/mememto_complete') # Ignore previous updates.
98           self.run(autoupdate_cmd, timeout=1200)
99        except error.AutoservRunError, e:
100            raise error.InstallError('OS Updater failed on %s', self.hostname)
101
102        # Check that the installer completed as expected.
103        # TODO(seano) verify installer completed in logs.
104
105
106    def symlink_closure(self, paths):
107        """
108        Given a sequence of path strings, return the set of all paths that
109        can be reached from the initial set by following symlinks.
110
111        @param paths: sequence of path strings.
112        @return: a sequence of path strings that are all the unique paths that
113                can be reached from the given ones after following symlinks.
114        """
115        paths = set(paths)
116        closure = set()
117
118        while paths:
119            path = paths.pop()
120            if not os.path.exists(path):
121                continue
122            closure.add(path)
123            if os.path.islink(path):
124                link_to = os.path.join(os.path.dirname(path),
125                                       os.readlink(path))
126                if link_to not in closure:
127                    paths.add(link_to)
128
129        return closure
130