# # Copyright (C) 2017 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # import logging import os import re import zipfile from host_controller.build import build_provider from vts.utils.python.common import cmd_utils _GCLOUD_AUTH_ENV_KEY = "run_gcs_key" class BuildProviderGCS(build_provider.BuildProvider): """A build provider for GCS (Google Cloud Storage).""" def __init__(self): super(BuildProviderGCS, self).__init__() if _GCLOUD_AUTH_ENV_KEY in os.environ: gcloud_path = BuildProviderGCS.GetGcloudPath() if gcloud_path is not None: auth_cmd = "%s auth activate-service-account --key-file=%s" % ( gcloud_path, os.environ[_GCLOUD_AUTH_ENV_KEY]) _, stderr, ret_code = cmd_utils.ExecuteOneShellCommand( auth_cmd) if ret_code == 0: logging.info(stderr) else: print(stderr) logging.error(stderr) @staticmethod def GetGcloudPath(): """Returns the gcloud file path if found; None otherwise.""" sh_stdout, _, ret_code = cmd_utils.ExecuteOneShellCommand( "which gcloud") if ret_code == 0: return sh_stdout.strip() else: logging.error("`gcloud` doesn't exist on the host; " "please install Google Cloud SDK before retrying.") return None @staticmethod def GetGsutilPath(): """Returns the gsutil file path if found; None otherwise.""" sh_stdout, sh_stderr, ret_code = cmd_utils.ExecuteOneShellCommand( "which gsutil") if ret_code == 0: return sh_stdout.strip() else: logging.fatal("`gsutil` doesn't exist on the host; " "please install Google Cloud SDK before retrying.") return None @staticmethod def IsGcsFile(gsutil_path, gs_path): """Checks whether a given path is for a GCS file. Args: gsutil_path: string, the path of a gsutil binary. gs_path: string, the GCS file path (e.g., gs://<bucket>/<file>. Returns: True if gs_path is a file, False otherwise. """ check_command = "%s stat %s" % (gsutil_path, gs_path) _, _, ret_code = cmd_utils.ExecuteOneShellCommand(check_command) return ret_code == 0 def Fetch(self, path): """Fetches Android device artifact file(s) from GCS. Args: path: string, the path of a directory which keeps artifacts. Returns: a dict containing the device image info. a dict containing the test suite package info. a dict containing the info about custom tool files. """ if not path.startswith("gs://"): path = "gs://" + re.sub("^/*", "", path) path = re.sub("/*$", "", path) # make sure gsutil is available. Instead of a Python library, # gsutil binary is used that is to avoid packaging GCS PIP package # as part of VTS HC (Host Controller). gsutil_path = BuildProviderGCS.GetGsutilPath() if gsutil_path: temp_dir_path = self.CreateNewTmpDir() # IsGcsFile returns False if path is directory or doesn't exist. # cp command returns non-zero if path doesn't exist. if not BuildProviderGCS.IsGcsFile(gsutil_path, path): dest_path = temp_dir_path copy_command = "%s cp -r %s/* %s" % (gsutil_path, path, temp_dir_path) else: dest_path = os.path.join(temp_dir_path, os.path.basename(path)) copy_command = "%s cp %s %s" % (gsutil_path, path, temp_dir_path) _, _, ret_code = cmd_utils.ExecuteOneShellCommand(copy_command) if ret_code == 0: self.SetFetchedFile(dest_path, temp_dir_path) else: logging.error("Error in copy file from GCS (code %s)." % ret_code) return (self.GetDeviceImage(), self.GetTestSuitePackage(), self.GetAdditionalFile())