blob: 586b173865c8133666c497e4312b1e7a7350a8e6 [file] [log] [blame]
Keun Soo Yimb293fdb2016-09-21 16:03:44 -07001#!/usr/bin/env python
2#
3# Copyright 2016 - 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.
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070016"""A client that talks to Google Cloud Storage APIs."""
17
18import io
19import logging
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070020
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070021import apiclient
22
Sam Chiu7de3b232018-12-06 19:45:52 +080023from acloud import errors
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070024from acloud.internal.lib import base_cloud_client
Tri Vo8e292532016-10-01 16:55:51 -070025from acloud.internal.lib import utils
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070026
27logger = logging.getLogger(__name__)
28
29
30class StorageClient(base_cloud_client.BaseCloudApiClient):
31 """Client that talks to Google Cloud Storages."""
32
33 # API settings, used by BaseCloudApiClient.
34 API_NAME = "storage"
35 API_VERSION = "v1"
36 SCOPE = "https://www.googleapis.com/auth/devstorage.read_write"
37 GET_OBJ_MAX_RETRY = 3
38 GET_OBJ_RETRY_SLEEP = 5
39
40 # Other class variables.
41 OBJECT_URL_FMT = "https://storage.googleapis.com/%s/%s"
42
43 def Get(self, bucket_name, object_name):
44 """Get object in a bucket.
45
46 Args:
47 bucket_name: String, google cloud storage bucket name.
48 object_name: String, full path to the object within the bucket.
49
50 Returns:
51 A dictronary representing an object resource.
52 """
Sam Chiu46ea3112018-05-18 10:47:52 +080053 request = self.service.objects().get(
54 bucket=bucket_name, object=object_name)
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070055 return self.Execute(request)
56
57 def List(self, bucket_name, prefix=None):
58 """Lists objects in a bucket.
59
60 Args:
61 bucket_name: String, google cloud storage bucket name.
62 prefix: String, Filter results to objects whose names begin with
63 this prefix.
64
65 Returns:
66 A list of google storage objects whose names match the prefix.
67 Each element is dictionary that wraps all the information about an object.
68 """
69 logger.debug("Listing storage bucket: %s, prefix: %s", bucket_name,
70 prefix)
71 items = self.ListWithMultiPages(
72 api_resource=self.service.objects().list,
73 bucket=bucket_name,
74 prefix=prefix)
75 return items
76
77 def Upload(self, local_src, bucket_name, object_name, mime_type):
78 """Uploads a file.
79
80 Args:
81 local_src: string, a local path to a file to be uploaded.
82 bucket_name: string, google cloud storage bucket name.
83 object_name: string, the name of the remote file in storage.
84 mime_type: string, mime-type of the file.
85
86 Returns:
87 URL to the inserted artifact in storage.
88 """
89 logger.info("Uploading file: src: %s, bucket: %s, object: %s",
90 local_src, bucket_name, object_name)
91 try:
Sam Chiu46ea3112018-05-18 10:47:52 +080092 with io.FileIO(local_src, mode="rb") as upload_file:
93 media = apiclient.http.MediaIoBaseUpload(upload_file, mime_type)
94 request = self.service.objects().insert(
95 bucket=bucket_name, name=object_name, media_body=media)
Keun Soo Yimb293fdb2016-09-21 16:03:44 -070096 response = self.Execute(request)
97 logger.info("Uploaded artifact: %s", response["selfLink"])
98 return response
99 except OSError as e:
100 logger.error("Uploading artifact fails: %s", str(e))
101 raise errors.DriverError(str(e))
102
103 def Delete(self, bucket_name, object_name):
104 """Deletes a file.
105
106 Args:
107 bucket_name: string, google cloud storage bucket name.
108 object_name: string, the name of the remote file in storage.
109 """
110 logger.info("Deleting file: bucket: %s, object: %s", bucket_name,
111 object_name)
Sam Chiu46ea3112018-05-18 10:47:52 +0800112 request = self.service.objects().delete(
113 bucket=bucket_name, object=object_name)
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700114 self.Execute(request)
115 logger.info("Deleted file: bucket: %s, object: %s", bucket_name,
116 object_name)
117
118 def DeleteFiles(self, bucket_name, object_names):
119 """Deletes multiple files.
120
121 Args:
122 bucket_name: string, google cloud storage bucket name.
123 object_names: A list of strings, each of which is a name of a remote file.
124
125 Returns:
126 A tuple, (deleted, failed, error_msgs)
127 deleted: A list of names of objects that have been deleted.
128 faild: A list of names of objects that we fail to delete.
129 error_msgs: A list of failure messages.
130 """
131 deleted = []
132 failed = []
133 error_msgs = []
134 for object_name in object_names:
135 try:
136 self.Delete(bucket_name, object_name)
137 deleted.append(object_name)
138 except errors.DriverError as e:
139 failed.append(object_name)
140 error_msgs.append(str(e))
141 return deleted, failed, error_msgs
142
143 def GetUrl(self, bucket_name, object_name):
144 """Get information about a file object.
145
146 Args:
147 bucket_name: string, google cloud storage bucket name.
148 object_name: string, name of the file to look for.
149
150 Returns:
151 Value of "selfLink" field from the response, which represents
152 a url to the file.
153
154 Raises:
155 errors.ResourceNotFoundError: when file is not found.
156 """
Fang Dengf24be082018-02-10 10:09:55 -0800157 item = utils.RetryExceptionType(
Sam Chiu46ea3112018-05-18 10:47:52 +0800158 errors.ResourceNotFoundError,
Kevin Chengd25feee2018-05-24 10:15:20 -0700159 self.GET_OBJ_MAX_RETRY,
160 self.Get,
161 self.GET_OBJ_RETRY_SLEEP,
162 utils.DEFAULT_RETRY_BACKOFF_FACTOR,
Sam Chiu46ea3112018-05-18 10:47:52 +0800163 bucket_name=bucket_name,
164 object_name=object_name)
Keun Soo Yimb293fdb2016-09-21 16:03:44 -0700165 return item["selfLink"]