download_images.py revision 4b133961b76c2cb8bc58f0ea2cded9e3438ffb6f
1# Copyright (c) 2014-2015 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"""Download images from Cloud Storage."""
5
6from __future__ import print_function
7
8import ast
9import os
10
11import test_flag
12
13from cros_utils import command_executer
14
15
16class MissingImage(Exception):
17  """Raised when the requested image does not exist in gs://"""
18
19
20class MissingFile(Exception):
21  """Raised when the requested file does not exist in gs://"""
22
23
24class ImageDownloader(object):
25  """Download images from Cloud Storage."""
26
27  def __init__(self, logger_to_use=None, log_level='verbose', cmd_exec=None):
28    self._logger = logger_to_use
29    self.log_level = log_level
30    self._ce = cmd_exec or command_executer.GetCommandExecuter(
31        self._logger, log_level=self.log_level)
32
33  def GetBuildID(self, chromeos_root, xbuddy_label):
34    # Get the translation of the xbuddy_label into the real Google Storage
35    # image name.
36    command = ('cd ~/trunk/src/third_party/toolchain-utils/crosperf; '
37               "python translate_xbuddy.py '%s'" % xbuddy_label)
38    _, build_id_tuple_str, _ = self._ce.ChrootRunCommandWOutput(chromeos_root,
39                                                                command)
40    if not build_id_tuple_str:
41      raise MissingImage("Unable to find image for '%s'" % xbuddy_label)
42
43    build_id_tuple = ast.literal_eval(build_id_tuple_str)
44    build_id = build_id_tuple[0]
45
46    return build_id
47
48  def DownloadImage(self, chromeos_root, build_id, image_name):
49    if self.log_level == 'average':
50      self._logger.LogOutput('Preparing to download %s image to local '
51                             'directory.' % build_id)
52
53    # Make sure the directory for downloading the image exists.
54    download_path = os.path.join(chromeos_root, 'chroot/tmp', build_id)
55    image_path = os.path.join(download_path, 'chromiumos_test_image.bin')
56    if not os.path.exists(download_path):
57      os.makedirs(download_path)
58
59    # Check to see if the image has already been downloaded.  If not,
60    # download the image.
61    if not os.path.exists(image_path):
62      command = 'gsutil cp %s /tmp/%s' % (image_name, build_id)
63
64      if self.log_level != 'verbose':
65        self._logger.LogOutput('CMD: %s' % command)
66      status = self._ce.ChrootRunCommand(chromeos_root, command)
67      downloaded_image_name = os.path.join(download_path,
68                                           'chromiumos_test_image.tar.xz')
69      if status != 0 or not os.path.exists(downloaded_image_name):
70        raise MissingImage('Cannot download image: %s.' % downloaded_image_name)
71
72    return image_path
73
74  def UncompressImage(self, chromeos_root, build_id):
75    # Check to see if the file has already been uncompresssed, etc.
76    if os.path.exists(
77        os.path.join(chromeos_root, 'chroot/tmp', build_id,
78                     'chromiumos_test_image.bin')):
79      return
80
81    # Uncompress and untar the downloaded image.
82    command = ('cd /tmp/%s ;unxz chromiumos_test_image.tar.xz; '
83               'tar -xvf chromiumos_test_image.tar' % build_id)
84    if self.log_level != 'verbose':
85      self._logger.LogOutput('CMD: %s' % command)
86      print('(Uncompressing and un-tarring may take a couple of minutes...'
87            'please be patient.)')
88    retval = self._ce.ChrootRunCommand(chromeos_root, command)
89    if retval != 0:
90      raise MissingImage('Cannot uncompress image: %s.' % build_id)
91
92  def DownloadSingleAutotestFile(self, chromeos_root, build_id,
93                                 package_file_name):
94    # Verify if package files exist
95    status = 0
96    gs_package_name = ('gs://chromeos-image-archive/%s/%s' %
97                       (build_id, package_file_name))
98    if not test_flag.GetTestMode():
99      cmd = 'gsutil ls %s' % gs_package_name
100      status = self._ce.ChrootRunCommand(chromeos_root, cmd)
101    if status != 0:
102      raise MissingFile('Cannot find autotest package file: %s.' %
103                        package_file_name)
104
105    if self.log_level == 'average':
106      self._logger.LogOutput('Preparing to download %s package to local '
107                             'directory.' % package_file_name)
108
109    # Make sure the directory for downloading the package exists.
110    download_path = os.path.join(chromeos_root, 'chroot/tmp', build_id)
111    package_path = os.path.join(download_path, package_file_name)
112    if not os.path.exists(download_path):
113      os.makedirs(download_path)
114
115    # Check to see if the package file has already been downloaded.  If not,
116    # download it.
117    if not os.path.exists(package_path):
118      command = 'gsutil cp %s /tmp/%s' % (gs_package_name, build_id)
119
120      if self.log_level != 'verbose':
121        self._logger.LogOutput('CMD: %s' % command)
122      status = self._ce.ChrootRunCommand(chromeos_root, command)
123      if status != 0 or not os.path.exists(package_path):
124        raise MissingFile('Cannot download package: %s .' % package_path)
125
126  def UncompressSingleAutotestFile(self, chromeos_root, build_id,
127                                   package_file_name, uncompress_cmd):
128    # Uncompress file
129    command = ('cd /tmp/%s ; %s %s' %
130               (build_id, uncompress_cmd, package_file_name))
131
132    if self.log_level != 'verbose':
133      self._logger.LogOutput('CMD: %s' % command)
134      print('(Uncompressing autotest file %s .)' % package_file_name)
135    retval = self._ce.ChrootRunCommand(chromeos_root, command)
136    if retval != 0:
137      raise MissingFile('Cannot uncompress file: %s.' % package_file_name)
138    # Remove uncompressed downloaded file
139    command = ('cd /tmp/%s ; rm -f %s' % (build_id, package_file_name))
140    if self.log_level != 'verbose':
141      self._logger.LogOutput('CMD: %s' % command)
142      print('(Removing processed autotest file %s .)' % package_file_name)
143    # try removing file, its ok to have an error, print if encountered
144    retval = self._ce.ChrootRunCommand(chromeos_root, command)
145    if retval != 0:
146      print('(Warning: Could not remove file %s .)' % package_file_name)
147
148  def DownloadAutotestFiles(self, chromeos_root, build_id):
149    # Download autest package files (3 files)
150    autotest_packages_name = ('autotest_packages.tar')
151    autotest_server_package_name = ('autotest_server_package.tar.bz2')
152    autotest_control_files_name = ('control_files.tar')
153
154    # Autotest directory relative path wrt chroot
155    autotest_rel_path = os.path.join('/tmp', build_id, 'autotest_files')
156    # Absolute Path to download files
157    autotest_path = os.path.join(chromeos_root, 'chroot/tmp', build_id,
158                                 'autotest_files')
159
160    if not os.path.exists(autotest_path):
161      self.DownloadSingleAutotestFile(chromeos_root, build_id,
162                                      autotest_packages_name)
163      self.DownloadSingleAutotestFile(chromeos_root, build_id,
164                                      autotest_server_package_name)
165      self.DownloadSingleAutotestFile(chromeos_root, build_id,
166                                      autotest_control_files_name)
167
168      self.UncompressSingleAutotestFile(chromeos_root, build_id,
169                                        autotest_packages_name, 'tar -xvf ')
170      self.UncompressSingleAutotestFile(chromeos_root, build_id,
171                                        autotest_server_package_name,
172                                        'tar -jxvf ')
173      self.UncompressSingleAutotestFile(chromeos_root, build_id,
174                                        autotest_control_files_name,
175                                        'tar -xvf ')
176      # Rename created autotest directory to autotest_files
177      command = ('cd /tmp/%s ; mv autotest autotest_files' % build_id)
178      if self.log_level != 'verbose':
179        self._logger.LogOutput('CMD: %s' % command)
180        print('(Moving downloaded autotest files to autotest_files)')
181      retval = self._ce.ChrootRunCommand(chromeos_root, command)
182      if retval != 0:
183        raise MissingFile('Could not create directory autotest_files')
184
185    return autotest_rel_path
186
187  def Run(self, chromeos_root, xbuddy_label, autotest_path):
188    build_id = self.GetBuildID(chromeos_root, xbuddy_label)
189    image_name = ('gs://chromeos-image-archive/%s/chromiumos_test_image.tar.xz'
190                  % build_id)
191
192    # Verify that image exists for build_id, before attempting to
193    # download it.
194    status = 0
195    if not test_flag.GetTestMode():
196      cmd = 'gsutil ls %s' % image_name
197      status = self._ce.ChrootRunCommand(chromeos_root, cmd)
198    if status != 0:
199      raise MissingImage('Cannot find official image: %s.' % image_name)
200
201    image_path = self.DownloadImage(chromeos_root, build_id, image_name)
202    self.UncompressImage(chromeos_root, build_id)
203
204    if self.log_level != 'quiet':
205      self._logger.LogOutput('Using image from %s.' % image_path)
206
207    if autotest_path == '':
208      autotest_path = self.DownloadAutotestFiles(chromeos_root, build_id)
209
210    return image_path, autotest_path
211