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