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