| #!/usr/bin/env python |
| # |
| # Copyright 2018 - 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. |
| """google SDK tools installer. |
| |
| This class will return the path to the google sdk tools and download them into |
| a temporary dir if they don't exist. The caller is expected to call cleanup |
| when they're done. |
| |
| Example usage: |
| google_sdk = GoogleSDK() |
| google_sdk_bin_path = google_sdk.GetSDKBinPath() |
| |
| # Caller is done. |
| google_sdk.CleanUp() |
| """ |
| |
| from distutils.spawn import find_executable |
| import logging |
| import os |
| import platform |
| import shutil |
| import sys |
| import tempfile |
| import urllib2 |
| |
| from acloud import errors |
| from acloud.internal.lib import utils |
| |
| SDK_BIN_PATH = os.path.join("google-cloud-sdk", "bin") |
| GCLOUD_BIN = "gcloud" |
| GCP_SDK_VERSION = "209.0.0" |
| GCP_SDK_TOOLS_URL = "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads" |
| LINUX_GCP_SDK_64_URL = "%s/google-cloud-sdk-%s-linux-x86_64.tar.gz" % ( |
| GCP_SDK_TOOLS_URL, GCP_SDK_VERSION) |
| LINUX_GCP_SDK_32_URL = "%s/google-cloud-sdk-%s-linux-x86.tar.gz" % ( |
| GCP_SDK_TOOLS_URL, GCP_SDK_VERSION) |
| WIN_GCP_SDK_64_URL = "%s/google-cloud-sdk-%s-windows-x86_64.zip" % ( |
| GCP_SDK_TOOLS_URL, GCP_SDK_VERSION) |
| WIN_GCP_SDK_32_URL = "%s/google-cloud-sdk-%s-windows-x86.zip" % ( |
| GCP_SDK_TOOLS_URL, GCP_SDK_VERSION) |
| MAC_GCP_SDK_64_URL = "%s/google-cloud-sdk-%s-darwin-x86_64.tar.gz" % ( |
| GCP_SDK_TOOLS_URL, GCP_SDK_VERSION) |
| MAC_GCP_SDK_32_URL = "%s/google-cloud-sdk-%s-darwin-x86.tar.gz" % ( |
| GCP_SDK_TOOLS_URL, GCP_SDK_VERSION) |
| LINUX = "linux" |
| WIN = "windows" |
| MAC = "darwin" |
| |
| logger = logging.getLogger(__name__) |
| |
| |
| def GetSdkUrl(): |
| """Get google SDK tool url. |
| |
| Return: |
| String, a URL of google SDK tools. |
| |
| Raises: |
| OSTypeError when OS type is neither linux, mac, or windows. |
| """ |
| is_64bits = sys.maxsize > 2**32 |
| os_type = platform.system().lower() |
| if is_64bits: |
| if os_type == LINUX: |
| return LINUX_GCP_SDK_64_URL |
| elif os_type == MAC: |
| return MAC_GCP_SDK_64_URL |
| elif os_type == WIN: |
| return WIN_GCP_SDK_64_URL |
| else: |
| if os_type == LINUX: |
| return LINUX_GCP_SDK_32_URL |
| elif os_type == MAC: |
| return MAC_GCP_SDK_32_URL |
| elif os_type == WIN: |
| return WIN_GCP_SDK_32_URL |
| raise errors.OSTypeError("no gcloud for os type: %s" % (os_type)) |
| |
| |
| def SDKInstalled(): |
| """Check google SDK tools installed. |
| |
| We'll try to find where gcloud is and assume the other google sdk tools |
| live in the same location. |
| |
| Return: |
| Boolean, return True if gcloud is installed, False otherwise. |
| """ |
| if find_executable(GCLOUD_BIN): |
| return True |
| return False |
| |
| |
| class GoogleSDK(object): |
| """Google SDK tools installer.""" |
| |
| def __init__(self): |
| """GoogleSDKInstaller initialize. |
| |
| Make sure the GCloud SDK is installed. If not, this function will assist |
| users to install. |
| """ |
| self._tmp_path = None |
| self._tmp_sdk_path = None |
| if not SDKInstalled(): |
| self.DownloadGcloudSDKAndExtract() |
| |
| def GetSDKBinPath(self): |
| """Get google SDK tools bin path. |
| |
| We assumed there are google sdk tools somewhere and will raise if we |
| can't find it. The order we're looking for is: |
| 1. Builtin gcloud (usually /usr/bin), we'll return /usr/bin with the |
| assumption other sdk tools live there. |
| 2. Downloaded google sdk (self._tmp_dir), we assumed the caller already |
| downloaded/extracted and set the self._tmp_sdk_path for us to return. |
| We'll make sure it exists prior to returning it. |
| |
| Return: |
| String, return google SDK tools bin path. |
| |
| Raise: |
| NoGoogleSDKDetected if we can't find the sdk path. |
| """ |
| builtin_gcloud = find_executable(GCLOUD_BIN) |
| if builtin_gcloud: |
| return os.path.dirname(builtin_gcloud) |
| elif os.path.exists(self._tmp_sdk_path): |
| return self._tmp_sdk_path |
| raise errors.NoGoogleSDKDetected("no sdk path.") |
| |
| def DownloadGcloudSDKAndExtract(self): |
| """Download the google SDK tools and decompress it. |
| |
| Download the google SDK from the GCP web. |
| Reference https://cloud.google.com/sdk/docs/downloads-versioned-archives. |
| """ |
| self._tmp_path = tempfile.mkdtemp(prefix="gcloud") |
| url = GetSdkUrl() |
| filename = url[url.rfind("/") + 1:] |
| file_path = os.path.join(self._tmp_path, filename) |
| logger.info("Download file from: %s", url) |
| logger.info("Save the file to: %s", file_path) |
| url_stream = urllib2.urlopen(url) |
| metadata = url_stream.info() |
| file_size = int(metadata.getheaders("Content-Length")[0]) |
| logger.info("Downloading google SDK: %s bytes.", file_size) |
| with open(file_path, 'wb') as output: |
| output.write(url_stream.read()) |
| utils.Decompress(file_path, self._tmp_path) |
| self._tmp_sdk_path = os.path.join(self._tmp_path, SDK_BIN_PATH) |
| |
| def CleanUp(self): |
| """Clean google sdk tools install folder.""" |
| if self._tmp_path and os.path.exists(self._tmp_path): |
| shutil.rmtree(self._tmp_path) |