1*800a58d9SAndroid Build Coastguard Worker#!/usr/bin/env python 2*800a58d9SAndroid Build Coastguard Worker# 3*800a58d9SAndroid Build Coastguard Worker# Copyright 2018 - The Android Open Source Project 4*800a58d9SAndroid Build Coastguard Worker# 5*800a58d9SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*800a58d9SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*800a58d9SAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*800a58d9SAndroid Build Coastguard Worker# 9*800a58d9SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*800a58d9SAndroid Build Coastguard Worker# 11*800a58d9SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*800a58d9SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*800a58d9SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*800a58d9SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*800a58d9SAndroid Build Coastguard Worker# limitations under the License. 16*800a58d9SAndroid Build Coastguard Worker"""google SDK tools installer. 17*800a58d9SAndroid Build Coastguard Worker 18*800a58d9SAndroid Build Coastguard WorkerThis class will return the path to the google sdk tools and download them into 19*800a58d9SAndroid Build Coastguard Workera temporary dir if they don't exist. The caller is expected to call cleanup 20*800a58d9SAndroid Build Coastguard Workerwhen they're done. 21*800a58d9SAndroid Build Coastguard Worker 22*800a58d9SAndroid Build Coastguard WorkerExample usage: 23*800a58d9SAndroid Build Coastguard Workergoogle_sdk = GoogleSDK() 24*800a58d9SAndroid Build Coastguard Workergoogle_sdk_bin_path = google_sdk.GetSDKBinPath() 25*800a58d9SAndroid Build Coastguard Worker 26*800a58d9SAndroid Build Coastguard Worker# Caller is done. 27*800a58d9SAndroid Build Coastguard Workergoogle_sdk.CleanUp() 28*800a58d9SAndroid Build Coastguard Worker""" 29*800a58d9SAndroid Build Coastguard Worker 30*800a58d9SAndroid Build Coastguard Workerimport logging 31*800a58d9SAndroid Build Coastguard Workerimport os 32*800a58d9SAndroid Build Coastguard Workerimport platform 33*800a58d9SAndroid Build Coastguard Workerimport shutil 34*800a58d9SAndroid Build Coastguard Workerimport sys 35*800a58d9SAndroid Build Coastguard Workerimport tempfile 36*800a58d9SAndroid Build Coastguard Workerfrom six.moves import urllib 37*800a58d9SAndroid Build Coastguard Worker 38*800a58d9SAndroid Build Coastguard Workerfrom acloud import errors 39*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import utils 40*800a58d9SAndroid Build Coastguard Worker 41*800a58d9SAndroid Build Coastguard Worker 42*800a58d9SAndroid Build Coastguard Workerlogger = logging.getLogger(__name__) 43*800a58d9SAndroid Build Coastguard Worker 44*800a58d9SAndroid Build Coastguard WorkerSDK_BIN_PATH = os.path.join("google-cloud-sdk", "bin") 45*800a58d9SAndroid Build Coastguard WorkerGCLOUD_BIN = "gcloud" 46*800a58d9SAndroid Build Coastguard WorkerGCLOUD_COMPONENT_NOT_INSTALLED = "Not Installed" 47*800a58d9SAndroid Build Coastguard WorkerGCP_SDK_VERSION = "209.0.0" 48*800a58d9SAndroid Build Coastguard WorkerGCP_SDK_TOOLS_URL = "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads" 49*800a58d9SAndroid Build Coastguard WorkerLINUX_GCP_SDK_64_URL = "%s/google-cloud-sdk-%s-linux-x86_64.tar.gz" % ( 50*800a58d9SAndroid Build Coastguard Worker GCP_SDK_TOOLS_URL, GCP_SDK_VERSION) 51*800a58d9SAndroid Build Coastguard WorkerLINUX_GCP_SDK_32_URL = "%s/google-cloud-sdk-%s-linux-x86.tar.gz" % ( 52*800a58d9SAndroid Build Coastguard Worker GCP_SDK_TOOLS_URL, GCP_SDK_VERSION) 53*800a58d9SAndroid Build Coastguard WorkerWIN_GCP_SDK_64_URL = "%s/google-cloud-sdk-%s-windows-x86_64.zip" % ( 54*800a58d9SAndroid Build Coastguard Worker GCP_SDK_TOOLS_URL, GCP_SDK_VERSION) 55*800a58d9SAndroid Build Coastguard WorkerWIN_GCP_SDK_32_URL = "%s/google-cloud-sdk-%s-windows-x86.zip" % ( 56*800a58d9SAndroid Build Coastguard Worker GCP_SDK_TOOLS_URL, GCP_SDK_VERSION) 57*800a58d9SAndroid Build Coastguard WorkerMAC_GCP_SDK_64_URL = "%s/google-cloud-sdk-%s-darwin-x86_64.tar.gz" % ( 58*800a58d9SAndroid Build Coastguard Worker GCP_SDK_TOOLS_URL, GCP_SDK_VERSION) 59*800a58d9SAndroid Build Coastguard WorkerMAC_GCP_SDK_32_URL = "%s/google-cloud-sdk-%s-darwin-x86.tar.gz" % ( 60*800a58d9SAndroid Build Coastguard Worker GCP_SDK_TOOLS_URL, GCP_SDK_VERSION) 61*800a58d9SAndroid Build Coastguard WorkerLINUX = "linux" 62*800a58d9SAndroid Build Coastguard WorkerWIN = "windows" 63*800a58d9SAndroid Build Coastguard WorkerMAC = "darwin" 64*800a58d9SAndroid Build Coastguard Worker 65*800a58d9SAndroid Build Coastguard Worker 66*800a58d9SAndroid Build Coastguard Workerdef GetSdkUrl(): 67*800a58d9SAndroid Build Coastguard Worker """Get google SDK tool url. 68*800a58d9SAndroid Build Coastguard Worker 69*800a58d9SAndroid Build Coastguard Worker Return: 70*800a58d9SAndroid Build Coastguard Worker String, a URL of google SDK tools. 71*800a58d9SAndroid Build Coastguard Worker 72*800a58d9SAndroid Build Coastguard Worker Raises: 73*800a58d9SAndroid Build Coastguard Worker OSTypeError when OS type is neither linux, mac, or windows. 74*800a58d9SAndroid Build Coastguard Worker """ 75*800a58d9SAndroid Build Coastguard Worker is_64bits = sys.maxsize > 2**32 76*800a58d9SAndroid Build Coastguard Worker os_type = platform.system().lower() 77*800a58d9SAndroid Build Coastguard Worker if is_64bits: 78*800a58d9SAndroid Build Coastguard Worker if os_type == LINUX: 79*800a58d9SAndroid Build Coastguard Worker return LINUX_GCP_SDK_64_URL 80*800a58d9SAndroid Build Coastguard Worker if os_type == MAC: 81*800a58d9SAndroid Build Coastguard Worker return MAC_GCP_SDK_64_URL 82*800a58d9SAndroid Build Coastguard Worker if os_type == WIN: 83*800a58d9SAndroid Build Coastguard Worker return WIN_GCP_SDK_64_URL 84*800a58d9SAndroid Build Coastguard Worker else: 85*800a58d9SAndroid Build Coastguard Worker if os_type == LINUX: 86*800a58d9SAndroid Build Coastguard Worker return LINUX_GCP_SDK_32_URL 87*800a58d9SAndroid Build Coastguard Worker if os_type == MAC: 88*800a58d9SAndroid Build Coastguard Worker return MAC_GCP_SDK_32_URL 89*800a58d9SAndroid Build Coastguard Worker if os_type == WIN: 90*800a58d9SAndroid Build Coastguard Worker return WIN_GCP_SDK_32_URL 91*800a58d9SAndroid Build Coastguard Worker raise errors.OSTypeError("no gcloud for os type: %s" % (os_type)) 92*800a58d9SAndroid Build Coastguard Worker 93*800a58d9SAndroid Build Coastguard Worker 94*800a58d9SAndroid Build Coastguard Workerdef SDKInstalled(): 95*800a58d9SAndroid Build Coastguard Worker """Check google SDK tools installed. 96*800a58d9SAndroid Build Coastguard Worker 97*800a58d9SAndroid Build Coastguard Worker We'll try to find where gcloud is and assume the other google sdk tools 98*800a58d9SAndroid Build Coastguard Worker live in the same location. 99*800a58d9SAndroid Build Coastguard Worker 100*800a58d9SAndroid Build Coastguard Worker Return: 101*800a58d9SAndroid Build Coastguard Worker Boolean, return True if gcloud is installed, False otherwise. 102*800a58d9SAndroid Build Coastguard Worker """ 103*800a58d9SAndroid Build Coastguard Worker if utils.FindExecutable(GCLOUD_BIN): 104*800a58d9SAndroid Build Coastguard Worker return True 105*800a58d9SAndroid Build Coastguard Worker return False 106*800a58d9SAndroid Build Coastguard Worker 107*800a58d9SAndroid Build Coastguard Worker 108*800a58d9SAndroid Build Coastguard Workerclass GoogleSDK(): 109*800a58d9SAndroid Build Coastguard Worker """Google SDK tools installer.""" 110*800a58d9SAndroid Build Coastguard Worker 111*800a58d9SAndroid Build Coastguard Worker def __init__(self): 112*800a58d9SAndroid Build Coastguard Worker """GoogleSDKInstaller initialize. 113*800a58d9SAndroid Build Coastguard Worker 114*800a58d9SAndroid Build Coastguard Worker Make sure the GCloud SDK is installed. If not, this function will assist 115*800a58d9SAndroid Build Coastguard Worker users to install. 116*800a58d9SAndroid Build Coastguard Worker """ 117*800a58d9SAndroid Build Coastguard Worker self._tmp_path = None 118*800a58d9SAndroid Build Coastguard Worker self._tmp_sdk_path = None 119*800a58d9SAndroid Build Coastguard Worker if not SDKInstalled(): 120*800a58d9SAndroid Build Coastguard Worker self.DownloadGcloudSDKAndExtract() 121*800a58d9SAndroid Build Coastguard Worker 122*800a58d9SAndroid Build Coastguard Worker @staticmethod 123*800a58d9SAndroid Build Coastguard Worker def InstallGcloudComponent(gcloud_runner, component): 124*800a58d9SAndroid Build Coastguard Worker """Install gcloud component. 125*800a58d9SAndroid Build Coastguard Worker 126*800a58d9SAndroid Build Coastguard Worker Args: 127*800a58d9SAndroid Build Coastguard Worker gcloud_runner: A GcloudRunner class to run "gcloud" command. 128*800a58d9SAndroid Build Coastguard Worker component: String, name of gcloud component. 129*800a58d9SAndroid Build Coastguard Worker """ 130*800a58d9SAndroid Build Coastguard Worker result = gcloud_runner.RunGcloud([ 131*800a58d9SAndroid Build Coastguard Worker "components", "list", "--format", "get(state.name)", "--filter", 132*800a58d9SAndroid Build Coastguard Worker "ID=%s" % component 133*800a58d9SAndroid Build Coastguard Worker ]) 134*800a58d9SAndroid Build Coastguard Worker if result.strip() == GCLOUD_COMPONENT_NOT_INSTALLED: 135*800a58d9SAndroid Build Coastguard Worker gcloud_runner.RunGcloud( 136*800a58d9SAndroid Build Coastguard Worker ["components", "install", "--quiet", component]) 137*800a58d9SAndroid Build Coastguard Worker 138*800a58d9SAndroid Build Coastguard Worker def GetSDKBinPath(self): 139*800a58d9SAndroid Build Coastguard Worker """Get google SDK tools bin path. 140*800a58d9SAndroid Build Coastguard Worker 141*800a58d9SAndroid Build Coastguard Worker We assumed there are google sdk tools somewhere and will raise if we 142*800a58d9SAndroid Build Coastguard Worker can't find it. The order we're looking for is: 143*800a58d9SAndroid Build Coastguard Worker 1. Builtin gcloud (usually /usr/bin), we'll return /usr/bin with the 144*800a58d9SAndroid Build Coastguard Worker assumption other sdk tools live there. 145*800a58d9SAndroid Build Coastguard Worker 2. Downloaded google sdk (self._tmp_dir), we assumed the caller already 146*800a58d9SAndroid Build Coastguard Worker downloaded/extracted and set the self._tmp_sdk_path for us to return. 147*800a58d9SAndroid Build Coastguard Worker We'll make sure it exists prior to returning it. 148*800a58d9SAndroid Build Coastguard Worker 149*800a58d9SAndroid Build Coastguard Worker Return: 150*800a58d9SAndroid Build Coastguard Worker String, return google SDK tools bin path. 151*800a58d9SAndroid Build Coastguard Worker 152*800a58d9SAndroid Build Coastguard Worker Raise: 153*800a58d9SAndroid Build Coastguard Worker NoGoogleSDKDetected if we can't find the sdk path. 154*800a58d9SAndroid Build Coastguard Worker """ 155*800a58d9SAndroid Build Coastguard Worker builtin_gcloud = utils.FindExecutable(GCLOUD_BIN) 156*800a58d9SAndroid Build Coastguard Worker if builtin_gcloud: 157*800a58d9SAndroid Build Coastguard Worker return os.path.dirname(builtin_gcloud) 158*800a58d9SAndroid Build Coastguard Worker if os.path.exists(self._tmp_sdk_path): 159*800a58d9SAndroid Build Coastguard Worker return self._tmp_sdk_path 160*800a58d9SAndroid Build Coastguard Worker raise errors.NoGoogleSDKDetected("no sdk path.") 161*800a58d9SAndroid Build Coastguard Worker 162*800a58d9SAndroid Build Coastguard Worker def DownloadGcloudSDKAndExtract(self): 163*800a58d9SAndroid Build Coastguard Worker """Download the google SDK tools and decompress it. 164*800a58d9SAndroid Build Coastguard Worker 165*800a58d9SAndroid Build Coastguard Worker Download the google SDK from the GCP web. 166*800a58d9SAndroid Build Coastguard Worker Reference https://cloud.google.com/sdk/docs/downloads-versioned-archives. 167*800a58d9SAndroid Build Coastguard Worker """ 168*800a58d9SAndroid Build Coastguard Worker self._tmp_path = tempfile.mkdtemp(prefix="gcloud") 169*800a58d9SAndroid Build Coastguard Worker url = GetSdkUrl() 170*800a58d9SAndroid Build Coastguard Worker filename = url[url.rfind("/") + 1:] 171*800a58d9SAndroid Build Coastguard Worker file_path = os.path.join(self._tmp_path, filename) 172*800a58d9SAndroid Build Coastguard Worker logger.info("Download file from: %s", url) 173*800a58d9SAndroid Build Coastguard Worker logger.info("Save the file to: %s", file_path) 174*800a58d9SAndroid Build Coastguard Worker url_stream = urllib.request.urlopen(url) 175*800a58d9SAndroid Build Coastguard Worker metadata = url_stream.info() 176*800a58d9SAndroid Build Coastguard Worker file_size = int(metadata.get("Content-Length")) 177*800a58d9SAndroid Build Coastguard Worker logger.info("Downloading google SDK: %s bytes.", file_size) 178*800a58d9SAndroid Build Coastguard Worker with open(file_path, 'wb') as output: 179*800a58d9SAndroid Build Coastguard Worker output.write(url_stream.read()) 180*800a58d9SAndroid Build Coastguard Worker utils.Decompress(file_path, self._tmp_path) 181*800a58d9SAndroid Build Coastguard Worker self._tmp_sdk_path = os.path.join(self._tmp_path, SDK_BIN_PATH) 182*800a58d9SAndroid Build Coastguard Worker 183*800a58d9SAndroid Build Coastguard Worker def CleanUp(self): 184*800a58d9SAndroid Build Coastguard Worker """Clean google sdk tools install folder.""" 185*800a58d9SAndroid Build Coastguard Worker if self._tmp_path and os.path.exists(self._tmp_path): 186*800a58d9SAndroid Build Coastguard Worker shutil.rmtree(self._tmp_path) 187