• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#  Copyright (C) 2020 The Android Open Source Project
2#
3#  Licensed under the Apache License, Version 2.0 (the "License");
4#  you may not use this file except in compliance with the License.
5#  You may obtain a copy of the License at
6#
7#       http://www.apache.org/licenses/LICENSE-2.0
8#
9#  Unless required by applicable law or agreed to in writing, software
10#  distributed under the License is distributed on an "AS IS" BASIS,
11#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12#  See the License for the specific language governing permissions and
13#  limitations under the License.
14#
15#  Licensed under the Apache License, Version 2.0 (the "License");
16#  you may not use this file except in compliance with the License.
17#  You may obtain a copy of the License at
18#
19#       http://www.apache.org/licenses/LICENSE-2.0
20#
21#  Unless required by applicable law or agreed to in writing, software
22#  distributed under the License is distributed on an "AS IS" BASIS,
23#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24#  See the License for the specific language governing permissions and
25#  limitations under the License.
26#
27# Licensed under the Apache License, Version 2.0 (the "License");
28# you may not use this file except in compliance with the License.
29# You may obtain a copy of the License at
30#
31#     http://www.apache.org/licenses/LICENSE-2.0
32#
33# Unless required by applicable law or agreed to in writing, software
34# distributed under the License is distributed on an "AS IS" BASIS,
35# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
36# See the License for the specific language governing permissions and
37# limitations under the License.
38
39
40""" Utility functions for logstorage. """
41from __future__ import print_function
42
43import logging
44import uuid
45import time
46
47# pylint: disable=import-error
48try:
49    import httplib2
50    from googleapiclient.discovery import build
51except ImportError as e:
52    logging.debug('Import error due to: %s', e)
53
54from atest import constants
55from atest import metrics
56
57
58class BuildClient:
59    """Build api helper class."""
60
61    def __init__(self, creds):
62        """Init BuildClient class.
63        Args:
64            creds: An oauth2client.OAuth2Credentials instance.
65        """
66        http_auth = creds.authorize(httplib2.Http())
67        self.client = build(
68            serviceName=constants.STORAGE_SERVICE_NAME,
69            version=constants.STORAGE_API_VERSION,
70            cache_discovery=False,
71            http=http_auth,
72            discoveryServiceUrl=constants.DISCOVERY_SERVICE)
73
74    def list_branch(self):
75        """List all branch."""
76        return self.client.branch().list(maxResults=10000).execute()
77
78    def list_target(self, branch):
79        """List all target in the branch."""
80        return self.client.target().list(branch=branch,
81                                         maxResults=10000).execute()
82
83    def get_branch(self, branch):
84        """Get BuildInfo for specific branch.
85        Args:
86            branch: A string of branch name to query.
87        """
88        query_branch = ''
89        try:
90            query_branch = self.client.branch().get(resourceId=branch).execute()
91        # pylint: disable=broad-except
92        except Exception:
93            return ''
94        return query_branch
95
96    def insert_local_build(self, external_id, target, branch):
97        """Insert a build record.
98        Args:
99            external_id: unique id of build record.
100            target: build target.
101            branch: build branch.
102
103        Returns:
104            An build record object.
105        """
106        body = {
107            "buildId": "",
108            "externalId": external_id,
109            "branch": branch,
110            "target": {
111                "name": target,
112                "target": target
113            },
114            "buildAttemptStatus": "complete",
115        }
116        return self.client.build().insert(buildType="local",
117                                          body=body).execute()
118
119    def insert_build_attempts(self, build_record):
120        """Insert a build attempt record.
121        Args:
122            build_record: build record.
123
124        Returns:
125            An build attempt object.
126        """
127        build_attempt = {
128            "id": 0,
129            "status": "complete",
130            "successful": True
131        }
132        return self.client.buildattempt().insert(
133            buildId=build_record['buildId'],
134            target=build_record['target']['name'],
135            body=build_attempt).execute()
136
137    def insert_invocation(self, build_record):
138        """Insert a build invocation record.
139        Args:
140            build_record: build record.
141
142        Returns:
143            A build invocation object.
144        """
145        sponge_invocation_id = str(uuid.uuid4())
146        user_email = metrics.metrics_base.get_user_email()
147        invocation = {
148            "primaryBuild": {
149                "buildId": build_record['buildId'],
150                "buildTarget": build_record['target']['name'],
151                "branch": build_record['branch'],
152            },
153            "schedulerState": "running",
154            "runner": "atest",
155            "scheduler": "atest",
156            "users": [user_email],
157            "properties": [{
158                'name': 'sponge_invocation_id',
159                'value': sponge_invocation_id,
160            }, {
161                'name': 'test_uri',
162                'value': f'{constants.STORAGE2_TEST_URI}{sponge_invocation_id}'
163            }]
164        }
165        return self.client.invocation().insert(body=invocation).execute()
166
167    def update_invocation(self, invocation):
168        """Insert a build invocation record.
169        Args:
170            invocation: invocation record.
171
172        Returns:
173            A invocation object.
174        """
175        # Because invocation revision will be update by TF, we need to fetch
176        # latest invocation revision to update status correctly.
177        count = 0
178        invocations = None
179        while count < 5:
180            invocations = self.client.invocation().list(
181                invocationId=invocation['invocationId'],
182                maxResults=10).execute().get('invocations', [])
183            if invocations:
184                break
185            time.sleep(0.5)
186            count = count + 1
187        if invocations:
188            latest_revision = invocations[-1].get('revision', '')
189            if latest_revision:
190                logging.debug('Get latest_revision:%s from invocations:%s',
191                              latest_revision, invocations)
192                invocation['revision'] = latest_revision
193        return self.client.invocation().update(
194            resourceId=invocation['invocationId'],
195            body=invocation).execute()
196
197    def insert_work_unit(self, invocation_record):
198        """Insert a workunit record.
199          Args:
200              invocation_record: invocation record.
201
202          Returns:
203              the workunit object.
204          """
205        workunit = {
206            'invocationId': invocation_record['invocationId']
207        }
208        return self.client.workunit().insert(body=workunit).execute()
209