blob: 9a46280df25bbca89e612c74f3d22b98c5d8e787 [file] [log] [blame]
# -*- coding: utf-8 -*-
# Copyright 2014-2015 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Download images from Cloud Storage."""
import ast
import os
from cros_utils import command_executer
import test_flag
GS_UTIL = "src/chromium/depot_tools/gsutil.py"
class MissingImage(Exception):
"""Raised when the requested image does not exist in gs://"""
class MissingFile(Exception):
"""Raised when the requested file does not exist in gs://"""
class RunCommandExceptionHandler(object):
"""Handle Exceptions from calls to RunCommand"""
def __init__(self, logger_to_use, log_level, cmd_exec, command):
self.logger = logger_to_use
self.log_level = log_level
self.ce = cmd_exec
self.cleanup_command = command
def HandleException(self, _, e):
# Exception handler, Run specified command
if self.log_level != "verbose" and self.cleanup_command is not None:
self.logger.LogOutput("CMD: %s" % self.cleanup_command)
if self.cleanup_command is not None:
_ = self.ce.RunCommand(self.cleanup_command)
# Raise exception again
raise e
class ImageDownloader(object):
"""Download images from Cloud Storage."""
def __init__(self, logger_to_use=None, log_level="verbose", cmd_exec=None):
self._logger = logger_to_use
self.log_level = log_level
self._ce = cmd_exec or command_executer.GetCommandExecuter(
self._logger, log_level=self.log_level
)
def GetBuildID(self, chromeos_root, xbuddy_label):
# Get the translation of the xbuddy_label into the real Google Storage
# image name.
command = (
"cd /mnt/host/source/src/third_party/toolchain-utils/crosperf; "
"./translate_xbuddy.py '%s'" % xbuddy_label
)
_, build_id_tuple_str, _ = self._ce.ChrootRunCommandWOutput(
chromeos_root, command
)
if not build_id_tuple_str:
raise MissingImage("Unable to find image for '%s'" % xbuddy_label)
build_id_tuple = ast.literal_eval(build_id_tuple_str)
build_id = build_id_tuple[0]
return build_id
def DownloadImage(self, chromeos_root, build_id, image_name):
if self.log_level == "average":
self._logger.LogOutput(
"Preparing to download %s image to local "
"directory." % build_id
)
# Make sure the directory for downloading the image exists.
download_path = os.path.join(chromeos_root, "chroot/tmp", build_id)
image_path = os.path.join(download_path, "chromiumos_test_image.bin")
if not os.path.exists(download_path):
os.makedirs(download_path)
# Check to see if the image has already been downloaded. If not,
# download the image.
if not os.path.exists(image_path):
gsutil_cmd = os.path.join(chromeos_root, GS_UTIL)
command = "%s cp %s %s" % (gsutil_cmd, image_name, download_path)
if self.log_level != "verbose":
self._logger.LogOutput("CMD: %s" % command)
status = self._ce.RunCommand(command)
downloaded_image_name = os.path.join(
download_path, "chromiumos_test_image.tar.xz"
)
if status != 0 or not os.path.exists(downloaded_image_name):
raise MissingImage(
"Cannot download image: %s." % downloaded_image_name
)
return image_path
def UncompressImage(self, chromeos_root, build_id):
# Check to see if the file has already been uncompresssed, etc.
if os.path.exists(
os.path.join(
chromeos_root,
"chroot/tmp",
build_id,
"chromiumos_test_image.bin",
)
):
return
# Uncompress and untar the downloaded image.
download_path = os.path.join(chromeos_root, "chroot/tmp", build_id)
command = (
"cd %s ; tar -Jxf chromiumos_test_image.tar.xz " % download_path
)
# Cleanup command for exception handler
clean_cmd = "cd %s ; rm -f chromiumos_test_image.bin " % download_path
exception_handler = RunCommandExceptionHandler(
self._logger, self.log_level, self._ce, clean_cmd
)
if self.log_level != "verbose":
self._logger.LogOutput("CMD: %s" % command)
print(
"(Uncompressing and un-tarring may take a couple of minutes..."
"please be patient.)"
)
retval = self._ce.RunCommand(
command, except_handler=exception_handler.HandleException
)
if retval != 0:
if self.log_level != "verbose":
self._logger.LogOutput("CMD: %s" % clean_cmd)
print("(Removing file chromiumos_test_image.bin.)")
# Remove partially uncompressed file
_ = self._ce.RunCommand(clean_cmd)
# Raise exception for failure to uncompress
raise MissingImage("Cannot uncompress image: %s." % build_id)
# Remove compressed image
command = "cd %s ; rm -f chromiumos_test_image.tar.xz; " % download_path
if self.log_level != "verbose":
self._logger.LogOutput("CMD: %s" % command)
print("(Removing file chromiumos_test_image.tar.xz.)")
# try removing file, its ok to have an error, print if encountered
retval = self._ce.RunCommand(command)
if retval != 0:
print(
"(Warning: Could not remove file chromiumos_test_image.tar.xz .)"
)
def DownloadSingleFile(self, chromeos_root, build_id, package_file_name):
# Verify if package files exist
status = 0
gs_package_name = "gs://chromeos-image-archive/%s/%s" % (
build_id,
package_file_name,
)
gsutil_cmd = os.path.join(chromeos_root, GS_UTIL)
if not test_flag.GetTestMode():
cmd = "%s ls %s" % (gsutil_cmd, gs_package_name)
status = self._ce.RunCommand(cmd)
if status != 0:
raise MissingFile(
"Cannot find package file: %s." % package_file_name
)
if self.log_level == "average":
self._logger.LogOutput(
"Preparing to download %s package to local "
"directory." % package_file_name
)
# Make sure the directory for downloading the package exists.
download_path = os.path.join(chromeos_root, "chroot/tmp", build_id)
package_path = os.path.join(download_path, package_file_name)
if not os.path.exists(download_path):
os.makedirs(download_path)
# Check to see if the package file has already been downloaded. If not,
# download it.
if not os.path.exists(package_path):
command = "%s cp %s %s" % (
gsutil_cmd,
gs_package_name,
download_path,
)
if self.log_level != "verbose":
self._logger.LogOutput("CMD: %s" % command)
status = self._ce.RunCommand(command)
if status != 0 or not os.path.exists(package_path):
raise MissingFile(
"Cannot download package: %s ." % package_path
)
def UncompressSingleFile(
self, chromeos_root, build_id, package_file_name, uncompress_cmd
):
# Uncompress file
download_path = os.path.join(chromeos_root, "chroot/tmp", build_id)
command = "cd %s ; %s %s" % (
download_path,
uncompress_cmd,
package_file_name,
)
if self.log_level != "verbose":
self._logger.LogOutput("CMD: %s" % command)
print("(Uncompressing file %s .)" % package_file_name)
retval = self._ce.RunCommand(command)
if retval != 0:
raise MissingFile("Cannot uncompress file: %s." % package_file_name)
# Remove uncompressed downloaded file
command = "cd %s ; rm -f %s" % (download_path, package_file_name)
if self.log_level != "verbose":
self._logger.LogOutput("CMD: %s" % command)
print("(Removing processed file %s .)" % package_file_name)
# try removing file, its ok to have an error, print if encountered
retval = self._ce.RunCommand(command)
if retval != 0:
print("(Warning: Could not remove file %s .)" % package_file_name)
def VerifyFileExists(self, chromeos_root, build_id, package_file):
# Quickly verify if the files are there
status = 0
gs_package_name = "gs://chromeos-image-archive/%s/%s" % (
build_id,
package_file,
)
gsutil_cmd = os.path.join(chromeos_root, GS_UTIL)
if not test_flag.GetTestMode():
cmd = "%s ls %s" % (gsutil_cmd, gs_package_name)
if self.log_level != "verbose":
self._logger.LogOutput("CMD: %s" % cmd)
status = self._ce.RunCommand(cmd)
if status != 0:
print("(Warning: Could not find file %s )" % gs_package_name)
return 1
# Package exists on server
return 0
def DownloadAutotestFiles(self, chromeos_root, build_id):
# Download autest package files (3 files)
autotest_packages_name = "autotest_packages.tar"
autotest_server_package_name = "autotest_server_package.tar.bz2"
autotest_control_files_name = "control_files.tar"
download_path = os.path.join(chromeos_root, "chroot/tmp", build_id)
# Autotest directory relative path wrt chroot
autotest_rel_path = os.path.join("/tmp", build_id, "autotest_files")
# Absolute Path to download files
autotest_path = os.path.join(
chromeos_root, "chroot/tmp", build_id, "autotest_files"
)
if not os.path.exists(autotest_path):
# Quickly verify if the files are present on server
# If not, just exit with warning
status = self.VerifyFileExists(
chromeos_root, build_id, autotest_packages_name
)
if status != 0:
default_autotest_dir = (
"/mnt/host/source/src/third_party/autotest/files"
)
print(
"(Warning: Could not find autotest packages .)\n"
"(Warning: Defaulting autotest path to %s ."
% default_autotest_dir
)
return default_autotest_dir
# Files exist on server, download and uncompress them
self.DownloadSingleFile(
chromeos_root, build_id, autotest_packages_name
)
self.DownloadSingleFile(
chromeos_root, build_id, autotest_server_package_name
)
self.DownloadSingleFile(
chromeos_root, build_id, autotest_control_files_name
)
self.UncompressSingleFile(
chromeos_root, build_id, autotest_packages_name, "tar -xf "
)
self.UncompressSingleFile(
chromeos_root,
build_id,
autotest_server_package_name,
"tar -jxf ",
)
self.UncompressSingleFile(
chromeos_root, build_id, autotest_control_files_name, "tar -xf "
)
# Rename created autotest directory to autotest_files
command = "cd %s ; mv autotest autotest_files" % download_path
if self.log_level != "verbose":
self._logger.LogOutput("CMD: %s" % command)
print("(Moving downloaded autotest files to autotest_files)")
retval = self._ce.RunCommand(command)
if retval != 0:
raise MissingFile("Could not create directory autotest_files")
return autotest_rel_path
def DownloadDebugFile(self, chromeos_root, build_id):
# Download autest package files (3 files)
debug_archive_name = "debug.tgz"
download_path = os.path.join(chromeos_root, "chroot/tmp", build_id)
# Debug directory relative path wrt chroot
debug_rel_path = os.path.join("/tmp", build_id, "debug_files")
# Debug path to download files
debug_path = os.path.join(
chromeos_root, "chroot/tmp", build_id, "debug_files"
)
if not os.path.exists(debug_path):
# Quickly verify if the file is present on server
# If not, just exit with warning
status = self.VerifyFileExists(
chromeos_root, build_id, debug_archive_name
)
if status != 0:
self._logger.LogOutput(
"WARNING: Could not find debug archive on gs"
)
return ""
# File exists on server, download and uncompress it
self.DownloadSingleFile(chromeos_root, build_id, debug_archive_name)
self.UncompressSingleFile(
chromeos_root, build_id, debug_archive_name, "tar -xf "
)
# Extract and move debug files into the proper location.
debug_dir = "debug_files/usr/lib"
command = "cd %s ; mkdir -p %s; mv debug %s" % (
download_path,
debug_dir,
debug_dir,
)
if self.log_level != "verbose":
self._logger.LogOutput("CMD: %s" % command)
print("Moving downloaded debug files to %s" % debug_dir)
retval = self._ce.RunCommand(command)
if retval != 0:
raise MissingFile(
"Could not create directory %s"
% os.path.join(debug_dir, "debug")
)
return debug_rel_path
def Run(
self,
chromeos_root,
xbuddy_label,
autotest_path,
debug_path,
download_debug,
):
build_id = self.GetBuildID(chromeos_root, xbuddy_label)
image_name = (
"gs://chromeos-image-archive/%s/chromiumos_test_image.tar.xz"
% build_id
)
# Verify that image exists for build_id, before attempting to
# download it.
status = 0
if not test_flag.GetTestMode():
gsutil_cmd = os.path.join(chromeos_root, GS_UTIL)
cmd = "%s ls %s" % (gsutil_cmd, image_name)
status = self._ce.RunCommand(cmd)
if status != 0:
raise MissingImage("Cannot find official image: %s." % image_name)
image_path = self.DownloadImage(chromeos_root, build_id, image_name)
self.UncompressImage(chromeos_root, build_id)
if self.log_level != "quiet":
self._logger.LogOutput("Using image from %s." % image_path)
if autotest_path == "":
autotest_path = self.DownloadAutotestFiles(chromeos_root, build_id)
if debug_path == "" and download_debug:
debug_path = self.DownloadDebugFile(chromeos_root, build_id)
return image_path, autotest_path, debug_path