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