provision_AutoUpdate.py revision 9a02729492e28168aebec0cc18c6a581e1c45717
1# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import logging
6
7from autotest_lib.client.common_lib import error
8from autotest_lib.client.common_lib import global_config
9from autotest_lib.client.common_lib.cros import dev_server
10from autotest_lib.server import test
11from autotest_lib.server.cros import provision
12
13
14_CONFIG = global_config.global_config
15# pylint: disable-msg=E1120
16_IMAGE_URL_PATTERN = _CONFIG.get_config_value(
17        'CROS', 'image_url_pattern', type=str)
18
19
20class provision_AutoUpdate(test.test):
21    """A test that can provision a machine to the correct ChromeOS version."""
22    version = 1
23
24    def run_once(self, host, value):
25        """The method called by the control file to start the test.
26
27        @param host: The host object to update to |value|.
28        @param value: The build type and version to install on the host.
29
30        """
31        image = value
32
33        # If the host is already on the correct build, we have nothing to do.
34        # Note that this means we're not doing any sort of stateful-only
35        # update, and that we're relying more on cleanup to do cleanup.
36        # We could just not pass |force_update=True| to |machine_install|,
37        # but I'd like the semantics that a provision test 'returns' TestNA
38        # if the machine is already properly provisioned.
39        if host.get_build() == value:
40            # We can't raise a TestNA, as would make sense, as that makes
41            # job.run_test return False as if the job failed.  However, it'd
42            # still be nice to get this into the status.log, so we manually
43            # emit an INFO line instead.
44            self.job.record('INFO', None, None,
45                            'Host already running %s' % value)
46            return
47
48        # We're about to reimage a machine, so we need full_payload and
49        # stateful.  If something happened where the devserver doesn't have one
50        # of these, then it's also likely that it'll be missing autotest.
51        # Therefore, we require the devserver to also have autotest staged, so
52        # that the test that runs after this provision finishes doesn't error
53        # out because the devserver that its job_repo_url is set to is missing
54        # autotest test code.
55        # TODO(milleral): http://crbug.com/249426
56        # Add an asynchronous staging call so that we can ask the devserver to
57        # fetch autotest in the background here, and then wait on it after
58        # reimaging finishes or at some other point in the provisioning.
59        try:
60            ds = dev_server.ImageServer.resolve(image)
61            ds.stage_artifacts(image, ['full_payload', 'stateful', 'autotest'])
62        except dev_server.DevServerException as e:
63            raise error.TestFail(str(e))
64
65        url = _IMAGE_URL_PATTERN % (ds.url(), image)
66
67        # Installing a build on a host assumes that a label of
68        # 'cros-version:<build>' has already been created, so we need to make
69        # sure that one exists.
70        # TODO(milleral):  http://crbug.com/249424
71        # Consider making the add-a-label-to-a-host call automatically create a
72        # label if it does not already exist.
73        provision.ensure_label_exists(provision.cros_version_to_label(image))
74
75        try:
76            host.machine_install(force_update=True, update_url=url)
77        except error.InstallError as e:
78            logging.error(e)
79            raise error.TestFail(str(e))
80