Michael Tang | 97d188c | 2016-06-25 11:18:42 -0700 | [diff] [blame] | 1 | # Copyright 2016 The Chromium OS Authors. All rights reserved. |
| 2 | # Use of this source code is governed by a BSD-style license that can be |
| 3 | # found in the LICENSE file. |
| 4 | |
| 5 | """Script to archive old Autotest results to Google Storage. |
| 6 | |
| 7 | Uses gsutil to archive files to the configured Google Storage bucket. |
| 8 | Upon successful copy, the local results directory is deleted. |
| 9 | """ |
| 10 | |
Michael Tang | 0f553bd | 2017-06-16 17:38:45 -0700 | [diff] [blame] | 11 | from __future__ import print_function |
| 12 | |
Mike Frysinger | 2c3d9c3 | 2020-02-06 14:46:40 -0500 | [diff] [blame] | 13 | import logging |
Michael Tang | 97d188c | 2016-06-25 11:18:42 -0700 | [diff] [blame] | 14 | import os |
| 15 | |
| 16 | from apiclient import discovery |
Michael Tang | 0f553bd | 2017-06-16 17:38:45 -0700 | [diff] [blame] | 17 | from apiclient import errors |
Michael Tang | 97d188c | 2016-06-25 11:18:42 -0700 | [diff] [blame] | 18 | from oauth2client.client import ApplicationDefaultCredentialsError |
| 19 | from oauth2client.client import GoogleCredentials |
Michael Tang | 97d188c | 2016-06-25 11:18:42 -0700 | [diff] [blame] | 20 | |
| 21 | # Cloud service |
Michael Tang | 97d188c | 2016-06-25 11:18:42 -0700 | [diff] [blame] | 22 | PUBSUB_SERVICE_NAME = 'pubsub' |
| 23 | PUBSUB_VERSION = 'v1beta2' |
| 24 | PUBSUB_SCOPES = ['https://www.googleapis.com/auth/pubsub'] |
| 25 | # number of retry to publish an event. |
Michael Tang | 0f553bd | 2017-06-16 17:38:45 -0700 | [diff] [blame] | 26 | DEFAULT_PUBSUB_NUM_RETRIES = 3 |
Michael Tang | 97d188c | 2016-06-25 11:18:42 -0700 | [diff] [blame] | 27 | |
Michael Tang | 56cbe94 | 2017-05-19 09:30:49 -0700 | [diff] [blame] | 28 | class PubSubException(Exception): |
| 29 | """Exception to be raised when the test to push to prod failed.""" |
| 30 | pass |
Michael Tang | 97d188c | 2016-06-25 11:18:42 -0700 | [diff] [blame] | 31 | |
| 32 | |
Michael Tang | 56cbe94 | 2017-05-19 09:30:49 -0700 | [diff] [blame] | 33 | class PubSubClient(object): |
Michael Tang | 0f553bd | 2017-06-16 17:38:45 -0700 | [diff] [blame] | 34 | """A generic pubsub client.""" |
| 35 | def __init__(self, credential_file=None): |
Michael Tang | 56cbe94 | 2017-05-19 09:30:49 -0700 | [diff] [blame] | 36 | """Constructor for PubSubClient. |
Michael Tang | 97d188c | 2016-06-25 11:18:42 -0700 | [diff] [blame] | 37 | |
Michael Tang | 0f553bd | 2017-06-16 17:38:45 -0700 | [diff] [blame] | 38 | Args: |
| 39 | credential_file: The credential filename. |
| 40 | |
| 41 | Raises: |
| 42 | PubSubException if the credential file does not exist or corrupted. |
Michael Tang | 56cbe94 | 2017-05-19 09:30:49 -0700 | [diff] [blame] | 43 | """ |
Michael Tang | 0f553bd | 2017-06-16 17:38:45 -0700 | [diff] [blame] | 44 | if not credential_file: |
| 45 | raise PubSubException('You need to specify a credential file.') |
Michael Tang | 56cbe94 | 2017-05-19 09:30:49 -0700 | [diff] [blame] | 46 | self.credential_file = credential_file |
| 47 | self.credential = self._get_credential() |
Michael Tang | 97d188c | 2016-06-25 11:18:42 -0700 | [diff] [blame] | 48 | |
Michael Tang | 56cbe94 | 2017-05-19 09:30:49 -0700 | [diff] [blame] | 49 | def _get_credential(self): |
| 50 | """Gets the pubsub service api handle.""" |
| 51 | if not os.path.isfile(self.credential_file): |
| 52 | logging.error('No credential file found') |
Michael Tang | 0f553bd | 2017-06-16 17:38:45 -0700 | [diff] [blame] | 53 | raise PubSubException('Credential file does not exist:' + |
| 54 | self.credential_file) |
Michael Tang | 56cbe94 | 2017-05-19 09:30:49 -0700 | [diff] [blame] | 55 | try: |
| 56 | credential = GoogleCredentials.from_stream(self.credential_file) |
| 57 | if credential.create_scoped_required(): |
| 58 | credential = credential.create_scoped(PUBSUB_SCOPES) |
| 59 | return credential |
| 60 | except ApplicationDefaultCredentialsError as ex: |
Michael Tang | 0f553bd | 2017-06-16 17:38:45 -0700 | [diff] [blame] | 61 | logging.exception('Failed to get credential:%s', ex) |
| 62 | except errors.Error as e: |
| 63 | logging.exception('Failed to get the pubsub service handle:%s', e) |
Michael Tang | 56cbe94 | 2017-05-19 09:30:49 -0700 | [diff] [blame] | 64 | |
Michael Tang | 0f553bd | 2017-06-16 17:38:45 -0700 | [diff] [blame] | 65 | raise PubSubException('Credential file %s does not exists:' % |
| 66 | self.credential_file) |
Michael Tang | 56cbe94 | 2017-05-19 09:30:49 -0700 | [diff] [blame] | 67 | |
| 68 | def _get_pubsub_service(self): |
| 69 | try: |
| 70 | return discovery.build(PUBSUB_SERVICE_NAME, PUBSUB_VERSION, |
| 71 | credentials=self.credential) |
Michael Tang | 0f553bd | 2017-06-16 17:38:45 -0700 | [diff] [blame] | 72 | except errors.Error as e: |
| 73 | logging.exception('Failed to get pubsub resource object:%s', e) |
| 74 | raise PubSubException('Failed to get pubsub resource object') |
Michael Tang | 56cbe94 | 2017-05-19 09:30:49 -0700 | [diff] [blame] | 75 | |
Michael Tang | 0f553bd | 2017-06-16 17:38:45 -0700 | [diff] [blame] | 76 | def publish_notifications(self, topic, messages=None): |
Michael Tang | 56cbe94 | 2017-05-19 09:30:49 -0700 | [diff] [blame] | 77 | """Publishes a test result notification to a given pubsub topic. |
| 78 | |
| 79 | @param topic: The Cloud pubsub topic. |
| 80 | @param messages: A list of notification messages. |
| 81 | |
| 82 | @returns A list of pubsub message ids, and empty if fails. |
| 83 | |
| 84 | @raises PubSubException if failed to publish the notification. |
| 85 | """ |
Michael Tang | 0f553bd | 2017-06-16 17:38:45 -0700 | [diff] [blame] | 86 | if not messages: |
| 87 | return None |
| 88 | |
Michael Tang | 56cbe94 | 2017-05-19 09:30:49 -0700 | [diff] [blame] | 89 | pubsub = self._get_pubsub_service() |
Michael Tang | 97d188c | 2016-06-25 11:18:42 -0700 | [diff] [blame] | 90 | try: |
| 91 | body = {'messages': messages} |
Michael Tang | 0f553bd | 2017-06-16 17:38:45 -0700 | [diff] [blame] | 92 | resp = pubsub.projects().topics().publish( |
| 93 | topic=topic, body=body).execute( |
| 94 | num_retries=DEFAULT_PUBSUB_NUM_RETRIES) |
| 95 | msgIds = [] |
Michael Tang | 97d188c | 2016-06-25 11:18:42 -0700 | [diff] [blame] | 96 | if resp: |
| 97 | msgIds = resp.get('messageIds') |
| 98 | if msgIds: |
| 99 | logging.debug('Published notification message') |
Michael Tang | 0f553bd | 2017-06-16 17:38:45 -0700 | [diff] [blame] | 100 | else: |
| 101 | logging.error('Failed to published notification message') |
| 102 | return msgIds |
| 103 | except errors.Error as e: |
| 104 | logging.exception('Failed to publish test result notification:%s', |
| 105 | e) |
| 106 | raise PubSubException('Failed to publish the notification') |