1adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi# Copyright 2016 The Chromium OS Authors. All rights reserved.
2adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi# Use of this source code is governed by a BSD-style license that can be
3adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi# found in the LICENSE file.
4adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi
5adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basiimport logging
6adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi
7adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basifrom autotest_lib.client.common_lib import error
8adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basifrom autotest_lib.server import afe_utils
9adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basifrom autotest_lib.server import test
10adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi
11adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi
12adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basiclass provision_TestbedUpdate(test.test):
13adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi    """A test that can provision a machine to the correct Android version."""
14adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi    version = 1
15adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi
16adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi    def _builds_to_set(self, builds):
17adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        """Helper function to convert a build string into a set of builds.
18adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi
19adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        @param builds: Testbed build string to convert into a set.
20adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi
21adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        @returns: A set of the different builds in the build string.
22adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        """
23adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        result = set()
24adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        if not builds:
25adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi            return result
26adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        builds = builds.split(',')
27adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        for build in builds:
28adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi            # Remove any build multipliers, i.e. <build>#2
29adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi            build = build.split('#')[0]
30adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi            result.add(build)
31adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        return result
32adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi
33adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi
34adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi    def initialize(self, host, value, force=False, is_test_na=False,
35adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi                   repair=False):
36adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        """Initialize.
37adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi
38adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        @param host: The testbed object to update to |value|.
39adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi                     NOTE: This arg must be called host to align with the other
40adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi                           provision actions.
41adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        @param value: String of the image we want to install on the testbed.
42adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        @param force: not used by initialize.
43adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        @param is_test_na: boolean, if True, will simply skip the test
44adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi                           and emit TestNAError. The control file
45adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi                           determines whether the test should be skipped
46adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi                           and passes the decision via this argument. Note
47adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi                           we can't raise TestNAError in control file as it won't
48adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi                           be caught and handled properly.
49adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        @param repair: not used by initialize.
50adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        """
51adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        if is_test_na:
52adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi            raise error.TestNAError('Provisioning not applicable.')
53adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        # We check value in initialize so that it fails faster.
54adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        if not (value or repair):
55adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi            raise error.TestFail('No build version specified.')
56adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi
57adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi
58adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi    def run_once(self, host, value=None, force=False, repair=False):
59adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        """The method called by the control file to start the test.
60adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi
61adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        @param host: The testbed object to update to |value|.
62adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi                     NOTE: This arg must be called host to align with the other
63adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi                           provision actions.
64adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        @param value: The testbed object to provision with a build
65adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi                      corresponding to |value|.
66adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        @param force: True iff we should re-provision the machine regardless of
67adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi                      the current image version.  If False and the image
68adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi                      version matches our expected image version, no
69adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi                      provisioning will be done.
70adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        @param repair: Not yet supported for testbeds.
71adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi
72adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        """
73adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        testbed = host
74adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        logging.debug('Start provisioning %s to %s', testbed, value)
75adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi
76adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        if not value and not repair:
77adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi            raise error.TestFail('No build provided and this is not a repair '
78adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi                                 ' job.')
79adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi
80c8aa41a23c9e1d1826a8ac6779ed059ef7155c01Prathmesh Prabhu        if not force:
81c8aa41a23c9e1d1826a8ac6779ed059ef7155c01Prathmesh Prabhu            info = testbed.host_info_store.get()
82c8aa41a23c9e1d1826a8ac6779ed059ef7155c01Prathmesh Prabhu            # If the host is already on the correct build, we have nothing to
83c8aa41a23c9e1d1826a8ac6779ed059ef7155c01Prathmesh Prabhu            # do.
84c8aa41a23c9e1d1826a8ac6779ed059ef7155c01Prathmesh Prabhu            if self._builds_to_set(info.build) == self._builds_to_set(value):
85c8aa41a23c9e1d1826a8ac6779ed059ef7155c01Prathmesh Prabhu                # We can't raise a TestNA, as would make sense, as that makes
86c8aa41a23c9e1d1826a8ac6779ed059ef7155c01Prathmesh Prabhu                # job.run_test return False as if the job failed.  However, it'd
87c8aa41a23c9e1d1826a8ac6779ed059ef7155c01Prathmesh Prabhu                # still be nice to get this into the status.log, so we manually
88c8aa41a23c9e1d1826a8ac6779ed059ef7155c01Prathmesh Prabhu                # emit an INFO line instead.
89c8aa41a23c9e1d1826a8ac6779ed059ef7155c01Prathmesh Prabhu                self.job.record('INFO', None, None,
90c8aa41a23c9e1d1826a8ac6779ed059ef7155c01Prathmesh Prabhu                                'Testbed already running %s' % value)
91c8aa41a23c9e1d1826a8ac6779ed059ef7155c01Prathmesh Prabhu                return
92c8aa41a23c9e1d1826a8ac6779ed059ef7155c01Prathmesh Prabhu
93adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        try:
94adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi            afe_utils.machine_install_and_update_labels(
95adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi                    host, image=value)
96adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi        except error.InstallError as e:
97adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi            logging.exception(e)
98adf313165f835de2e47ad9e8d4ee9fab388e6a7cSimran Basi            raise error.TestFail(str(e))
99c8aa41a23c9e1d1826a8ac6779ed059ef7155c01Prathmesh Prabhu        logging.debug('Finished provisioning %s to %s', host, value)
100