blob: 925b77294ad63365cb15cf42ffb0d67160787415 [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
herbertxue0cf6cef2018-07-03 21:57:48 +080036import tempfile
chojoycef7f5c1e2019-10-25 15:14:44 +080037from six.moves import urllib
herbertxue0cf6cef2018-07-03 21:57:48 +080038
Sam Chiu7de3b232018-12-06 19:45:52 +080039from acloud import errors
chojoycecd004bc2018-09-13 10:39:00 +080040from acloud.internal.lib import utils
herbertxue0cf6cef2018-07-03 21:57:48 +080041
herbertxue1512f8a2019-06-27 13:56:23 +080042
43logger = logging.getLogger(__name__)
44
herbertxue0cf6cef2018-07-03 21:57:48 +080045SDK_BIN_PATH = os.path.join("google-cloud-sdk", "bin")
46GCLOUD_BIN = "gcloud"
47GCP_SDK_VERSION = "209.0.0"
48GCP_SDK_TOOLS_URL = "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads"
49LINUX_GCP_SDK_64_URL = "%s/google-cloud-sdk-%s-linux-x86_64.tar.gz" % (
50 GCP_SDK_TOOLS_URL, GCP_SDK_VERSION)
51LINUX_GCP_SDK_32_URL = "%s/google-cloud-sdk-%s-linux-x86.tar.gz" % (
52 GCP_SDK_TOOLS_URL, GCP_SDK_VERSION)
53WIN_GCP_SDK_64_URL = "%s/google-cloud-sdk-%s-windows-x86_64.zip" % (
54 GCP_SDK_TOOLS_URL, GCP_SDK_VERSION)
55WIN_GCP_SDK_32_URL = "%s/google-cloud-sdk-%s-windows-x86.zip" % (
56 GCP_SDK_TOOLS_URL, GCP_SDK_VERSION)
57MAC_GCP_SDK_64_URL = "%s/google-cloud-sdk-%s-darwin-x86_64.tar.gz" % (
58 GCP_SDK_TOOLS_URL, GCP_SDK_VERSION)
59MAC_GCP_SDK_32_URL = "%s/google-cloud-sdk-%s-darwin-x86.tar.gz" % (
60 GCP_SDK_TOOLS_URL, GCP_SDK_VERSION)
61LINUX = "linux"
62WIN = "windows"
63MAC = "darwin"
64
herbertxue0cf6cef2018-07-03 21:57:48 +080065
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
herbertxued69dc512019-05-30 15:37:15 +0800122 @staticmethod
123 def InstallGcloudComponent(gcloud_runner, component):
124 """Install gcloud component.
125
126 Args:
127 gcloud_runner: A GcloudRunner class to run "gcloud" command.
128 component: String, name of gcloud component.
129 """
130 gcloud_runner.RunGcloud(["components", "install", "--quiet", component])
131
herbertxue0cf6cef2018-07-03 21:57:48 +0800132 def GetSDKBinPath(self):
133 """Get google SDK tools bin path.
134
135 We assumed there are google sdk tools somewhere and will raise if we
136 can't find it. The order we're looking for is:
137 1. Builtin gcloud (usually /usr/bin), we'll return /usr/bin with the
138 assumption other sdk tools live there.
139 2. Downloaded google sdk (self._tmp_dir), we assumed the caller already
140 downloaded/extracted and set the self._tmp_sdk_path for us to return.
141 We'll make sure it exists prior to returning it.
142
143 Return:
144 String, return google SDK tools bin path.
145
146 Raise:
147 NoGoogleSDKDetected if we can't find the sdk path.
148 """
149 builtin_gcloud = find_executable(GCLOUD_BIN)
150 if builtin_gcloud:
151 return os.path.dirname(builtin_gcloud)
152 elif os.path.exists(self._tmp_sdk_path):
153 return self._tmp_sdk_path
154 raise errors.NoGoogleSDKDetected("no sdk path.")
155
156 def DownloadGcloudSDKAndExtract(self):
157 """Download the google SDK tools and decompress it.
158
159 Download the google SDK from the GCP web.
160 Reference https://cloud.google.com/sdk/docs/downloads-versioned-archives.
herbertxue0cf6cef2018-07-03 21:57:48 +0800161 """
162 self._tmp_path = tempfile.mkdtemp(prefix="gcloud")
163 url = GetSdkUrl()
164 filename = url[url.rfind("/") + 1:]
165 file_path = os.path.join(self._tmp_path, filename)
166 logger.info("Download file from: %s", url)
167 logger.info("Save the file to: %s", file_path)
chojoycef7f5c1e2019-10-25 15:14:44 +0800168 url_stream = urllib.request.urlopen(url)
herbertxue0cf6cef2018-07-03 21:57:48 +0800169 metadata = url_stream.info()
chojoycef7f5c1e2019-10-25 15:14:44 +0800170 file_size = int(metadata.get("Content-Length"))
herbertxue0cf6cef2018-07-03 21:57:48 +0800171 logger.info("Downloading google SDK: %s bytes.", file_size)
172 with open(file_path, 'wb') as output:
173 output.write(url_stream.read())
chojoycecd004bc2018-09-13 10:39:00 +0800174 utils.Decompress(file_path, self._tmp_path)
herbertxue0cf6cef2018-07-03 21:57:48 +0800175 self._tmp_sdk_path = os.path.join(self._tmp_path, SDK_BIN_PATH)
176
177 def CleanUp(self):
178 """Clean google sdk tools install folder."""
179 if self._tmp_path and os.path.exists(self._tmp_path):
180 shutil.rmtree(self._tmp_path)