blob: d9183c50b7e218a9cf1fa1c0c9d220faafa01343 [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
37import urllib2
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
42SDK_BIN_PATH = os.path.join("google-cloud-sdk", "bin")
43GCLOUD_BIN = "gcloud"
44GCP_SDK_VERSION = "209.0.0"
45GCP_SDK_TOOLS_URL = "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads"
46LINUX_GCP_SDK_64_URL = "%s/google-cloud-sdk-%s-linux-x86_64.tar.gz" % (
47 GCP_SDK_TOOLS_URL, GCP_SDK_VERSION)
48LINUX_GCP_SDK_32_URL = "%s/google-cloud-sdk-%s-linux-x86.tar.gz" % (
49 GCP_SDK_TOOLS_URL, GCP_SDK_VERSION)
50WIN_GCP_SDK_64_URL = "%s/google-cloud-sdk-%s-windows-x86_64.zip" % (
51 GCP_SDK_TOOLS_URL, GCP_SDK_VERSION)
52WIN_GCP_SDK_32_URL = "%s/google-cloud-sdk-%s-windows-x86.zip" % (
53 GCP_SDK_TOOLS_URL, GCP_SDK_VERSION)
54MAC_GCP_SDK_64_URL = "%s/google-cloud-sdk-%s-darwin-x86_64.tar.gz" % (
55 GCP_SDK_TOOLS_URL, GCP_SDK_VERSION)
56MAC_GCP_SDK_32_URL = "%s/google-cloud-sdk-%s-darwin-x86.tar.gz" % (
57 GCP_SDK_TOOLS_URL, GCP_SDK_VERSION)
58LINUX = "linux"
59WIN = "windows"
60MAC = "darwin"
61
62logger = logging.getLogger(__name__)
63
64
65def GetSdkUrl():
66 """Get google SDK tool url.
67
68 Return:
69 String, a URL of google SDK tools.
70
71 Raises:
72 OSTypeError when OS type is neither linux, mac, or windows.
73 """
74 is_64bits = sys.maxsize > 2**32
75 os_type = platform.system().lower()
76 if is_64bits:
77 if os_type == LINUX:
78 return LINUX_GCP_SDK_64_URL
79 elif os_type == MAC:
80 return MAC_GCP_SDK_64_URL
81 elif os_type == WIN:
82 return WIN_GCP_SDK_64_URL
83 else:
84 if os_type == LINUX:
85 return LINUX_GCP_SDK_32_URL
86 elif os_type == MAC:
87 return MAC_GCP_SDK_32_URL
88 elif os_type == WIN:
89 return WIN_GCP_SDK_32_URL
90 raise errors.OSTypeError("no gcloud for os type: %s" % (os_type))
91
92
93def SDKInstalled():
94 """Check google SDK tools installed.
95
96 We'll try to find where gcloud is and assume the other google sdk tools
97 live in the same location.
98
99 Return:
100 Boolean, return True if gcloud is installed, False otherwise.
101 """
102 if find_executable(GCLOUD_BIN):
103 return True
104 return False
105
106
107class GoogleSDK(object):
108 """Google SDK tools installer."""
109
110 def __init__(self):
111 """GoogleSDKInstaller initialize.
112
113 Make sure the GCloud SDK is installed. If not, this function will assist
114 users to install.
115 """
116 self._tmp_path = None
117 self._tmp_sdk_path = None
118 if not SDKInstalled():
119 self.DownloadGcloudSDKAndExtract()
120
herbertxued69dc512019-05-30 15:37:15 +0800121 @staticmethod
122 def InstallGcloudComponent(gcloud_runner, component):
123 """Install gcloud component.
124
125 Args:
126 gcloud_runner: A GcloudRunner class to run "gcloud" command.
127 component: String, name of gcloud component.
128 """
129 gcloud_runner.RunGcloud(["components", "install", "--quiet", component])
130
herbertxue0cf6cef2018-07-03 21:57:48 +0800131 def GetSDKBinPath(self):
132 """Get google SDK tools bin path.
133
134 We assumed there are google sdk tools somewhere and will raise if we
135 can't find it. The order we're looking for is:
136 1. Builtin gcloud (usually /usr/bin), we'll return /usr/bin with the
137 assumption other sdk tools live there.
138 2. Downloaded google sdk (self._tmp_dir), we assumed the caller already
139 downloaded/extracted and set the self._tmp_sdk_path for us to return.
140 We'll make sure it exists prior to returning it.
141
142 Return:
143 String, return google SDK tools bin path.
144
145 Raise:
146 NoGoogleSDKDetected if we can't find the sdk path.
147 """
148 builtin_gcloud = find_executable(GCLOUD_BIN)
149 if builtin_gcloud:
150 return os.path.dirname(builtin_gcloud)
151 elif os.path.exists(self._tmp_sdk_path):
152 return self._tmp_sdk_path
153 raise errors.NoGoogleSDKDetected("no sdk path.")
154
155 def DownloadGcloudSDKAndExtract(self):
156 """Download the google SDK tools and decompress it.
157
158 Download the google SDK from the GCP web.
159 Reference https://cloud.google.com/sdk/docs/downloads-versioned-archives.
herbertxue0cf6cef2018-07-03 21:57:48 +0800160 """
161 self._tmp_path = tempfile.mkdtemp(prefix="gcloud")
162 url = GetSdkUrl()
163 filename = url[url.rfind("/") + 1:]
164 file_path = os.path.join(self._tmp_path, filename)
165 logger.info("Download file from: %s", url)
166 logger.info("Save the file to: %s", file_path)
167 url_stream = urllib2.urlopen(url)
168 metadata = url_stream.info()
169 file_size = int(metadata.getheaders("Content-Length")[0])
170 logger.info("Downloading google SDK: %s bytes.", file_size)
171 with open(file_path, 'wb') as output:
172 output.write(url_stream.read())
chojoycecd004bc2018-09-13 10:39:00 +0800173 utils.Decompress(file_path, self._tmp_path)
herbertxue0cf6cef2018-07-03 21:57:48 +0800174 self._tmp_sdk_path = os.path.join(self._tmp_path, SDK_BIN_PATH)
175
176 def CleanUp(self):
177 """Clean google sdk tools install folder."""
178 if self._tmp_path and os.path.exists(self._tmp_path):
179 shutil.rmtree(self._tmp_path)