xref: /aosp_15_r20/tools/acloud/internal/lib/gstorage_client.py (revision 800a58d989c669b8eb8a71d8df53b1ba3d411444)
1*800a58d9SAndroid Build Coastguard Worker#!/usr/bin/env python
2*800a58d9SAndroid Build Coastguard Worker#
3*800a58d9SAndroid Build Coastguard Worker# Copyright 2016 - The Android Open Source Project
4*800a58d9SAndroid Build Coastguard Worker#
5*800a58d9SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*800a58d9SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*800a58d9SAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*800a58d9SAndroid Build Coastguard Worker#
9*800a58d9SAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
10*800a58d9SAndroid Build Coastguard Worker#
11*800a58d9SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*800a58d9SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*800a58d9SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*800a58d9SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*800a58d9SAndroid Build Coastguard Worker# limitations under the License.
16*800a58d9SAndroid Build Coastguard Worker"""A client that talks to Google Cloud Storage APIs."""
17*800a58d9SAndroid Build Coastguard Worker
18*800a58d9SAndroid Build Coastguard Workerimport io
19*800a58d9SAndroid Build Coastguard Workerimport logging
20*800a58d9SAndroid Build Coastguard Worker
21*800a58d9SAndroid Build Coastguard Workerimport apiclient
22*800a58d9SAndroid Build Coastguard Worker
23*800a58d9SAndroid Build Coastguard Workerfrom acloud import errors
24*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import base_cloud_client
25*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import utils
26*800a58d9SAndroid Build Coastguard Worker
27*800a58d9SAndroid Build Coastguard Worker
28*800a58d9SAndroid Build Coastguard Workerlogger = logging.getLogger(__name__)
29*800a58d9SAndroid Build Coastguard Worker
30*800a58d9SAndroid Build Coastguard Worker
31*800a58d9SAndroid Build Coastguard Workerclass StorageClient(base_cloud_client.BaseCloudApiClient):
32*800a58d9SAndroid Build Coastguard Worker    """Client that talks to Google Cloud Storages."""
33*800a58d9SAndroid Build Coastguard Worker
34*800a58d9SAndroid Build Coastguard Worker    # API settings, used by BaseCloudApiClient.
35*800a58d9SAndroid Build Coastguard Worker    API_NAME = "storage"
36*800a58d9SAndroid Build Coastguard Worker    API_VERSION = "v1"
37*800a58d9SAndroid Build Coastguard Worker    SCOPE = "https://www.googleapis.com/auth/devstorage.read_write"
38*800a58d9SAndroid Build Coastguard Worker    GET_OBJ_MAX_RETRY = 3
39*800a58d9SAndroid Build Coastguard Worker    GET_OBJ_RETRY_SLEEP = 5
40*800a58d9SAndroid Build Coastguard Worker
41*800a58d9SAndroid Build Coastguard Worker    # Other class variables.
42*800a58d9SAndroid Build Coastguard Worker    OBJECT_URL_FMT = "https://storage.googleapis.com/%s/%s"
43*800a58d9SAndroid Build Coastguard Worker
44*800a58d9SAndroid Build Coastguard Worker    def Get(self, bucket_name, object_name):
45*800a58d9SAndroid Build Coastguard Worker        """Get object in a bucket.
46*800a58d9SAndroid Build Coastguard Worker
47*800a58d9SAndroid Build Coastguard Worker        Args:
48*800a58d9SAndroid Build Coastguard Worker            bucket_name: String, google cloud storage bucket name.
49*800a58d9SAndroid Build Coastguard Worker            object_name: String, full path to the object within the bucket.
50*800a58d9SAndroid Build Coastguard Worker
51*800a58d9SAndroid Build Coastguard Worker        Returns:
52*800a58d9SAndroid Build Coastguard Worker            A dictronary representing an object resource.
53*800a58d9SAndroid Build Coastguard Worker        """
54*800a58d9SAndroid Build Coastguard Worker        request = self.service.objects().get(
55*800a58d9SAndroid Build Coastguard Worker            bucket=bucket_name, object=object_name)
56*800a58d9SAndroid Build Coastguard Worker        return self.Execute(request)
57*800a58d9SAndroid Build Coastguard Worker
58*800a58d9SAndroid Build Coastguard Worker    def List(self, bucket_name, prefix=None):
59*800a58d9SAndroid Build Coastguard Worker        """Lists objects in a bucket.
60*800a58d9SAndroid Build Coastguard Worker
61*800a58d9SAndroid Build Coastguard Worker        Args:
62*800a58d9SAndroid Build Coastguard Worker            bucket_name: String, google cloud storage bucket name.
63*800a58d9SAndroid Build Coastguard Worker            prefix: String, Filter results to objects whose names begin with
64*800a58d9SAndroid Build Coastguard Worker                    this prefix.
65*800a58d9SAndroid Build Coastguard Worker
66*800a58d9SAndroid Build Coastguard Worker        Returns:
67*800a58d9SAndroid Build Coastguard Worker            A list of google storage objects whose names match the prefix.
68*800a58d9SAndroid Build Coastguard Worker            Each element is dictionary that wraps all the information about an object.
69*800a58d9SAndroid Build Coastguard Worker        """
70*800a58d9SAndroid Build Coastguard Worker        logger.debug("Listing storage bucket: %s, prefix: %s", bucket_name,
71*800a58d9SAndroid Build Coastguard Worker                     prefix)
72*800a58d9SAndroid Build Coastguard Worker        items = self.ListWithMultiPages(
73*800a58d9SAndroid Build Coastguard Worker            api_resource=self.service.objects().list,
74*800a58d9SAndroid Build Coastguard Worker            bucket=bucket_name,
75*800a58d9SAndroid Build Coastguard Worker            prefix=prefix)
76*800a58d9SAndroid Build Coastguard Worker        return items
77*800a58d9SAndroid Build Coastguard Worker
78*800a58d9SAndroid Build Coastguard Worker    def Upload(self, local_src, bucket_name, object_name, mime_type):
79*800a58d9SAndroid Build Coastguard Worker        """Uploads a file.
80*800a58d9SAndroid Build Coastguard Worker
81*800a58d9SAndroid Build Coastguard Worker        Args:
82*800a58d9SAndroid Build Coastguard Worker            local_src: string, a local path to a file to be uploaded.
83*800a58d9SAndroid Build Coastguard Worker            bucket_name: string, google cloud storage bucket name.
84*800a58d9SAndroid Build Coastguard Worker            object_name: string, the name of the remote file in storage.
85*800a58d9SAndroid Build Coastguard Worker            mime_type: string, mime-type of the file.
86*800a58d9SAndroid Build Coastguard Worker
87*800a58d9SAndroid Build Coastguard Worker        Returns:
88*800a58d9SAndroid Build Coastguard Worker            URL to the inserted artifact in storage.
89*800a58d9SAndroid Build Coastguard Worker        """
90*800a58d9SAndroid Build Coastguard Worker        logger.info("Uploading file: src: %s, bucket: %s, object: %s",
91*800a58d9SAndroid Build Coastguard Worker                    local_src, bucket_name, object_name)
92*800a58d9SAndroid Build Coastguard Worker        try:
93*800a58d9SAndroid Build Coastguard Worker            with io.FileIO(local_src, mode="rb") as upload_file:
94*800a58d9SAndroid Build Coastguard Worker                media = apiclient.http.MediaIoBaseUpload(upload_file, mime_type)
95*800a58d9SAndroid Build Coastguard Worker                request = self.service.objects().insert(
96*800a58d9SAndroid Build Coastguard Worker                    bucket=bucket_name, name=object_name, media_body=media)
97*800a58d9SAndroid Build Coastguard Worker                response = self.Execute(request)
98*800a58d9SAndroid Build Coastguard Worker            logger.info("Uploaded artifact: %s", response["selfLink"])
99*800a58d9SAndroid Build Coastguard Worker            return response
100*800a58d9SAndroid Build Coastguard Worker        except OSError as e:
101*800a58d9SAndroid Build Coastguard Worker            logger.error("Uploading artifact fails: %s", str(e))
102*800a58d9SAndroid Build Coastguard Worker            raise errors.DriverError(str(e))
103*800a58d9SAndroid Build Coastguard Worker
104*800a58d9SAndroid Build Coastguard Worker    def Delete(self, bucket_name, object_name):
105*800a58d9SAndroid Build Coastguard Worker        """Deletes a file.
106*800a58d9SAndroid Build Coastguard Worker
107*800a58d9SAndroid Build Coastguard Worker        Args:
108*800a58d9SAndroid Build Coastguard Worker            bucket_name: string, google cloud storage bucket name.
109*800a58d9SAndroid Build Coastguard Worker            object_name: string, the name of the remote file in storage.
110*800a58d9SAndroid Build Coastguard Worker        """
111*800a58d9SAndroid Build Coastguard Worker        logger.info("Deleting file: bucket: %s, object: %s", bucket_name,
112*800a58d9SAndroid Build Coastguard Worker                    object_name)
113*800a58d9SAndroid Build Coastguard Worker        request = self.service.objects().delete(
114*800a58d9SAndroid Build Coastguard Worker            bucket=bucket_name, object=object_name)
115*800a58d9SAndroid Build Coastguard Worker        self.Execute(request)
116*800a58d9SAndroid Build Coastguard Worker        logger.info("Deleted file: bucket: %s, object: %s", bucket_name,
117*800a58d9SAndroid Build Coastguard Worker                    object_name)
118*800a58d9SAndroid Build Coastguard Worker
119*800a58d9SAndroid Build Coastguard Worker    def DeleteFiles(self, bucket_name, object_names):
120*800a58d9SAndroid Build Coastguard Worker        """Deletes multiple files.
121*800a58d9SAndroid Build Coastguard Worker
122*800a58d9SAndroid Build Coastguard Worker        Args:
123*800a58d9SAndroid Build Coastguard Worker            bucket_name: string, google cloud storage bucket name.
124*800a58d9SAndroid Build Coastguard Worker            object_names: A list of strings, each of which is a name of a remote file.
125*800a58d9SAndroid Build Coastguard Worker
126*800a58d9SAndroid Build Coastguard Worker        Returns:
127*800a58d9SAndroid Build Coastguard Worker            A tuple, (deleted, failed, error_msgs)
128*800a58d9SAndroid Build Coastguard Worker            deleted: A list of names of objects that have been deleted.
129*800a58d9SAndroid Build Coastguard Worker            faild: A list of names of objects that we fail to delete.
130*800a58d9SAndroid Build Coastguard Worker            error_msgs: A list of failure messages.
131*800a58d9SAndroid Build Coastguard Worker        """
132*800a58d9SAndroid Build Coastguard Worker        deleted = []
133*800a58d9SAndroid Build Coastguard Worker        failed = []
134*800a58d9SAndroid Build Coastguard Worker        error_msgs = []
135*800a58d9SAndroid Build Coastguard Worker        for object_name in object_names:
136*800a58d9SAndroid Build Coastguard Worker            try:
137*800a58d9SAndroid Build Coastguard Worker                self.Delete(bucket_name, object_name)
138*800a58d9SAndroid Build Coastguard Worker                deleted.append(object_name)
139*800a58d9SAndroid Build Coastguard Worker            except errors.DriverError as e:
140*800a58d9SAndroid Build Coastguard Worker                failed.append(object_name)
141*800a58d9SAndroid Build Coastguard Worker                error_msgs.append(str(e))
142*800a58d9SAndroid Build Coastguard Worker        return deleted, failed, error_msgs
143*800a58d9SAndroid Build Coastguard Worker
144*800a58d9SAndroid Build Coastguard Worker    def GetUrl(self, bucket_name, object_name):
145*800a58d9SAndroid Build Coastguard Worker        """Get information about a file object.
146*800a58d9SAndroid Build Coastguard Worker
147*800a58d9SAndroid Build Coastguard Worker        Args:
148*800a58d9SAndroid Build Coastguard Worker            bucket_name: string, google cloud storage bucket name.
149*800a58d9SAndroid Build Coastguard Worker            object_name: string, name of the file to look for.
150*800a58d9SAndroid Build Coastguard Worker
151*800a58d9SAndroid Build Coastguard Worker        Returns:
152*800a58d9SAndroid Build Coastguard Worker            Value of "selfLink" field from the response, which represents
153*800a58d9SAndroid Build Coastguard Worker            a url to the file.
154*800a58d9SAndroid Build Coastguard Worker
155*800a58d9SAndroid Build Coastguard Worker        Raises:
156*800a58d9SAndroid Build Coastguard Worker            errors.ResourceNotFoundError: when file is not found.
157*800a58d9SAndroid Build Coastguard Worker        """
158*800a58d9SAndroid Build Coastguard Worker        item = utils.RetryExceptionType(
159*800a58d9SAndroid Build Coastguard Worker            errors.ResourceNotFoundError,
160*800a58d9SAndroid Build Coastguard Worker            self.GET_OBJ_MAX_RETRY,
161*800a58d9SAndroid Build Coastguard Worker            self.Get,
162*800a58d9SAndroid Build Coastguard Worker            self.GET_OBJ_RETRY_SLEEP,
163*800a58d9SAndroid Build Coastguard Worker            utils.DEFAULT_RETRY_BACKOFF_FACTOR,
164*800a58d9SAndroid Build Coastguard Worker            bucket_name=bucket_name,
165*800a58d9SAndroid Build Coastguard Worker            object_name=object_name)
166*800a58d9SAndroid Build Coastguard Worker        return item["selfLink"]
167