Acloud create: upload local images to instance with lzop.
Bug: 129376163
Test: acloud create --local-image
acloud create --local-image image_zip_path
Change-Id: Ie09ddf286b16194dd48d3b2f25c7b8fb93e5f085
diff --git a/create/avd_spec_test.py b/create/avd_spec_test.py
index 48b8038..551eaa7 100644
--- a/create/avd_spec_test.py
+++ b/create/avd_spec_test.py
@@ -21,7 +21,6 @@
from acloud import errors
from acloud.create import avd_spec
-from acloud.create import create_common
from acloud.internal import constants
from acloud.internal.lib import driver_test_lib
from acloud.internal.lib import utils
@@ -43,8 +42,6 @@
# pylint: disable=protected-access
def testProcessLocalImageArgs(self):
"""Test process args.local_image."""
- self.Patch(create_common, "ZipCFImageFiles",
- return_value="/path/cf_x86_phone-img-eng.user.zip")
self.Patch(glob, "glob", return_value=["fake.img"])
expected_image_artifact = "/path/cf_x86_phone-img-eng.user.zip"
expected_image_dir = "/path-to-image-dir"
diff --git a/create/create_common.py b/create/create_common.py
index 3480228..565a6d9 100644
--- a/create/create_common.py
+++ b/create/create_common.py
@@ -17,20 +17,7 @@
from __future__ import print_function
-import glob
-import logging
-import os
-import tempfile
-import time
-import zipfile
-
from acloud import errors
-from acloud.internal import constants
-from acloud.internal.lib import utils
-
-logger = logging.getLogger(__name__)
-
-_ACLOUD_IMAGE_ZIP_POSTFIX = "-local-img-%s.zip"
def ParseHWPropertyArgs(dict_str, item_separator=",", key_value_separator=":"):
@@ -66,42 +53,3 @@
hw_dict[key.strip()] = value.strip()
return hw_dict
-
-
-@utils.TimeExecute(function_description="Compressing images")
-def ZipCFImageFiles(basedir):
- """Zip images from basedir.
-
- TODO(b/129376163):Use lzop for fast sparse image upload when host image
- support it.
-
- Args:
- basedir: String of local images path.
-
- Return:
- Strings of zipped image path.
- """
- tmp_folder = os.path.join(tempfile.gettempdir(),
- constants.TEMP_ARTIFACTS_FOLDER)
- if not os.path.exists(tmp_folder):
- os.makedirs(tmp_folder)
- archive_name = "%s-local-%d.zip" % (os.environ.get(constants.ENV_BUILD_TARGET),
- int(time.time()))
- archive_file = os.path.join(tmp_folder, archive_name)
- if os.path.exists(archive_file):
- raise errors.ZipImageError("This file shouldn't exist, please delete: %s"
- % archive_file)
-
- zip_file = zipfile.ZipFile(archive_file, 'w', zipfile.ZIP_DEFLATED,
- allowZip64=True)
- required_files = ([os.path.join(basedir, "android-info.txt")] +
- glob.glob(os.path.join(basedir, "*.img")))
- logger.debug("archiving images: %s", required_files)
-
- for f in required_files:
- # Pass arcname arg to remove the directory structure.
- zip_file.write(f, arcname=os.path.basename(f))
-
- zip_file.close()
- logger.debug("zip images done:%s", archive_file)
- return archive_file
diff --git a/create/create_common_test.py b/create/create_common_test.py
index 2af3177..497dea0 100644
--- a/create/create_common_test.py
+++ b/create/create_common_test.py
@@ -13,19 +13,13 @@
# limitations under the License.
"""Tests for create_common."""
-import os
-import tempfile
-import time
import unittest
-import zipfile
from acloud import errors
from acloud.create import create_common
-from acloud.internal import constants
from acloud.internal.lib import driver_test_lib
-
class FakeZipFile(object):
"""Fake implementation of ZipFile()"""
@@ -65,26 +59,6 @@
result_dict = create_common.ParseHWPropertyArgs(args_str)
self.assertTrue(expected_dict == result_dict)
- def testZipCFImageFiles(self):
- """Test ZipCFImageFiles."""
- # Should raise error if zip file already exists
- fake_image_path = "/fake_image_dir/"
- self.Patch(os.path, "exists", return_value=True)
- self.Patch(os, "makedirs")
- self.assertRaises(errors.ZipImageError,
- create_common.ZipCFImageFiles,
- fake_image_path)
-
- # Test should get archive name by timestamp if zip file does not exist.
- self.Patch(zipfile, "ZipFile", return_value=FakeZipFile())
- self.Patch(os.path, "exists", return_value=False)
- self.Patch(os.environ, "get", return_value="fake_build_target")
- self.Patch(time, "time", return_value=12345)
- self.Patch(tempfile, "gettempdir", return_value="/fake_temp")
- self.assertEqual(create_common.ZipCFImageFiles(fake_image_path),
- "/fake_temp/%s/fake_build_target-local-12345.zip" %
- constants.TEMP_ARTIFACTS_FOLDER)
-
if __name__ == "__main__":
unittest.main()
diff --git a/create/local_image_remote_instance.py b/create/local_image_remote_instance.py
index e507fb4..7e428ef 100644
--- a/create/local_image_remote_instance.py
+++ b/create/local_image_remote_instance.py
@@ -21,13 +21,13 @@
from distutils.spawn import find_executable
import getpass
+import glob
import logging
import os
import subprocess
from acloud import errors
from acloud.create import base_avd_create
-from acloud.create import create_common
from acloud.internal import constants
from acloud.internal.lib import auth
from acloud.internal.lib import cvd_compute_client
@@ -92,7 +92,8 @@
self._SetAVDenv(_CVD_USER)
self._UploadArtifacts(_CVD_USER,
self._local_image_artifact,
- self._cvd_host_package_artifact)
+ self._cvd_host_package_artifact,
+ self._avd_spec.local_image_dir)
self._LaunchCvd(_CVD_USER, self._avd_spec.hw_property)
return instance
@@ -129,15 +130,16 @@
Override method from parent class.
build_target: The format is like "aosp_cf_x86_phone". We only get info
from the user build image file name. If the file name is
- not custom format (no "-"), We will use the original
- flavor as our build_target.
+ not custom format (no "-"), we will use $TARGET_PRODUCT
+ from environment variable as build_target.
Returns:
A string, representing instance name.
"""
- image_name = os.path.basename(self._local_image_artifact)
- build_target = self._avd_spec.flavor if "-" not in image_name else image_name.split(
- "-")[0]
+ image_name = os.path.basename(
+ self._local_image_artifact) if self._local_image_artifact else ""
+ build_target = (os.environ.get(constants.ENV_BUILD_TARGET) if "-" not
+ in image_name else image_name.split("-")[0])
instance = self._compute_client.GenerateInstanceName(
build_target=build_target, build_id=_USER_BUILD)
# Create an instance from Stable Host Image
@@ -171,23 +173,45 @@
logger.debug("remote_cmd:\n %s", remote_cmd)
self._ShellCmdWithRetry(self._ssh_cmd + remote_cmd)
- @utils.TimeExecute(function_description="Uploading local image")
+ @utils.TimeExecute(function_description="Processing and uploading local images")
def _UploadArtifacts(self,
cvd_user,
- local_image_artifact,
- cvd_host_package_artifact):
- """Upload local image and avd local host package to instance.
+ local_image_zip,
+ cvd_host_package_artifact,
+ images_dir):
+ """Upload local images and avd local host package to instance.
+
+ There are two ways to upload local images.
+ 1. Using local image zip, it would be decompressed by install_zip.sh.
+ 2. Using local image directory, this directory contains all images.
+ Images are compressed/decompressed by lzop during upload process.
Args:
- cvd_user: A string, user upload the artifacts to instance.
- local_image_artifact: A string, path to local image.
- cvd_host_package_artifact: A string, path to cvd host package.
+ cvd_user: String, user upload the artifacts to instance.
+ local_image_zip: String, path to zip of local images which
+ build from 'm dist'.
+ cvd_host_package_artifact: String, path to cvd host package.
+ images_dir: String, directory of local images which build
+ from 'm'.
"""
- # TODO(b/129376163) Use lzop for fast sparse image upload
- remote_cmd = ("\"sudo su -c '/usr/bin/install_zip.sh .' - '%s'\" < %s" %
- (cvd_user, local_image_artifact))
- logger.debug("remote_cmd:\n %s", remote_cmd)
- self._ShellCmdWithRetry(self._ssh_cmd + remote_cmd)
+ # TODO(b/133461252) Deprecate acloud create with local image zip.
+ # Upload local image zip file
+ if local_image_zip:
+ remote_cmd = ("\"sudo su -c '/usr/bin/install_zip.sh .' - '%s'\" < %s"
+ % (cvd_user, local_image_zip))
+ logger.debug("remote_cmd:\n %s", remote_cmd)
+ self._ShellCmdWithRetry(self._ssh_cmd + remote_cmd)
+ else:
+ # Compress image files for faster upload.
+ artifact_files = [os.path.basename(image) for image in glob.glob(
+ os.path.join(images_dir, "*.img"))]
+ cmd = ("tar -cf - --lzop -S -C {images_dir} {artifact_files} | "
+ "{ssh_cmd} -- tar -xf - --lzop -S".format(
+ images_dir=images_dir,
+ artifact_files=" ".join(artifact_files),
+ ssh_cmd=self._ssh_cmd))
+ logger.debug("cmd:\n %s", cmd)
+ self._ShellCmdWithRetry(cmd)
# host_package
remote_cmd = ("\"sudo su -c 'tar -x -z -f -' - '%s'\" < %s" %
@@ -272,16 +296,9 @@
no_prompts: Boolean, True to skip all prompts.
"""
self.cvd_host_package_artifact = self.VerifyHostPackageArtifactsExist()
-
- if avd_spec.local_image_artifact:
- local_image_artifact = avd_spec.local_image_artifact
- else:
- local_image_artifact = create_common.ZipCFImageFiles(
- avd_spec.local_image_dir)
-
device_factory = RemoteInstanceDeviceFactory(
avd_spec,
- local_image_artifact,
+ avd_spec.local_image_artifact,
self.cvd_host_package_artifact)
report = common_operations.CreateDevices(
"create_cf", avd_spec.cfg, device_factory, avd_spec.num,
diff --git a/create/local_image_remote_instance_test.py b/create/local_image_remote_instance_test.py
index 1509d9f..ce898b2 100644
--- a/create/local_image_remote_instance_test.py
+++ b/create/local_image_remote_instance_test.py
@@ -30,7 +30,6 @@
from acloud import errors
from acloud.create import avd_spec
-from acloud.create import create_common
from acloud.create import local_image_remote_instance
from acloud.internal import constants
from acloud.internal.lib import auth
@@ -103,13 +102,12 @@
self.assertEqual(factory._ShellCmdWithRetry("fake cmd"), True)
# pylint: disable=protected-access
+ @mock.patch.dict(os.environ, {constants.ENV_BUILD_TARGET:'fake-target'})
def testCreateGceInstanceName(self):
"""test create gce instance."""
self.Patch(utils, "GetBuildEnvironmentVariable",
return_value="test_environ")
self.Patch(glob, "glob", return_vale=["fake.img"])
- self.Patch(create_common, "ZipCFImageFiles",
- return_value="/fake/aosp_cf_x86_phone-img-eng.username.zip")
# Mock uuid
args = mock.MagicMock()
args.config_file = ""
@@ -130,12 +128,22 @@
fake_host_package_name)
self.assertEqual(factory._CreateGceInstance(), "ins-1234-userbuild-aosp-cf-x86-phone")
+ # Can't get target name from zip file name.
fake_image_name = "/fake/aosp_cf_x86_phone.username.zip"
factory = local_image_remote_instance.RemoteInstanceDeviceFactory(
fake_avd_spec,
fake_image_name,
fake_host_package_name)
- self.assertEqual(factory._CreateGceInstance(), "ins-1234-userbuild-phone")
+ self.assertEqual(factory._CreateGceInstance(), "ins-1234-userbuild-fake-target")
+
+ # No image zip path, it uses local build images.
+ fake_image_name = ""
+ factory = local_image_remote_instance.RemoteInstanceDeviceFactory(
+ fake_avd_spec,
+ fake_image_name,
+ fake_host_package_name)
+ self.assertEqual(factory._CreateGceInstance(), "ins-1234-userbuild-fake-target")
+
if __name__ == "__main__":
unittest.main()