1# Copyright (c) 2012 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"""Module for discovering Chrome OS test images and payloads.""" 6 7import logging 8import re 9 10import common 11from autotest_lib.client.common_lib import global_config 12from autotest_lib.utils import external_packages 13 14from autotest_lib.site_utils.autoupdate import import_common 15devserver = import_common.download_and_import('devserver', 16 external_packages.DevServerRepo()) 17from devserver import gsutil_util 18 19 20# A string indicating a zip-file boundary within a URI path. This string must 21# end with a '/', in order for standard basename code to work correctly for 22# zip-encapsulated paths. 23ZIPFILE_BOUNDARY = '//' 24ARCHIVE_URL_FORMAT = '%(archive_prefix)s/%(version)s' 25 26 27class TestImageError(BaseException): 28 """Raised on any error in this module.""" 29 pass 30 31 32class NotSingleItem(Exception): 33 """Raised when we want a single item but got multiple.""" 34 35 36def get_default_archive_url(board, build_version): 37 """Returns the default archive_url for the given board and build_version . 38 39 @param board: the platform/board name 40 @param build_version: the full build version i.e. R27-3823.0.0-a2. 41 """ 42 archive_base = global_config.global_config.get_config_value( 43 'CROS', 'image_storage_server') 44 archive_base = archive_base.rstrip('/') # Remove any trailing /'s. 45 46 # TODO(garnold) adjustment to -he variant board names; should be removed 47 # once we switch to using artifacts from gs://chromeos-images/ 48 # (see chromium-os:38222) 49 board = re.sub('-he$', '_he', board) 50 archive_prefix = archive_base + '/%s-release' % board 51 return ARCHIVE_URL_FORMAT % dict( 52 archive_prefix=archive_prefix, version=build_version) 53 54 55def get_archive_url_from_prefix(archive_prefix, build_version): 56 """Returns the gs archive_url given a particular archive_prefix. 57 58 @param archive_prefix: Use the archive_prefix as the base of your URL 59 60 construction (instead of config + board-release) e.g. 61 gs://my_location/my_super_awesome_directory. 62 @param build_version: the full build version i.e. R27-3823.0.0-a2. 63 """ 64 return ARCHIVE_URL_FORMAT % dict( 65 archive_prefix=archive_prefix, version=build_version) 66 67 68def gs_ls(pattern, archive_url, single): 69 """Returns a list of URIs that match a given pattern. 70 71 @param pattern: a regexp pattern to match (feeds into re.match). 72 @param archive_url: the gs uri where to search (see ARCHIVE_URL_FORMAT). 73 @param single: if true, expect a single match and return it. 74 75 @return A list of URIs (possibly an empty list). 76 77 """ 78 try: 79 logging.debug('Searching for pattern %s from url %s', pattern, 80 archive_url) 81 uri_list = gsutil_util.GetGSNamesWithWait( 82 pattern, archive_url, err_str=__name__, timeout=1) 83 # Convert to the format our clients expect (full archive path). 84 if uri_list: 85 if not single or (single and len(uri_list) == 1): 86 return ['/'.join([archive_url, u]) for u in uri_list] 87 else: 88 raise NotSingleItem() 89 90 return [] 91 except gsutil_util.PatternNotSpecific as e: 92 raise TestImageError(str(e)) 93 except gsutil_util.GSUtilError: 94 return [] 95 96 97def find_payload_uri(archive_url, delta=False, single=False): 98 """Finds test payloads corresponding to a given board/release. 99 100 @param archive_url: Archive_url directory to find the payload. 101 @param delta: if true, seek delta payloads to the given release 102 @param single: if true, expect a single match and return it, otherwise 103 None 104 105 @return A (possibly empty) list of URIs, or a single (possibly None) URI if 106 |single| is True. 107 108 @raise TestImageError if an error has occurred. 109 110 """ 111 if delta: 112 pattern = '*_delta_*' 113 else: 114 pattern = '*_full_*' 115 116 payload_uri_list = gs_ls(pattern, archive_url, single) 117 if not payload_uri_list: 118 return None if single else [] 119 120 return payload_uri_list[0] if single else payload_uri_list 121 122 123def find_image_uri(archive_url): 124 """Returns a URI to a test image. 125 126 @param archive_url: archive_url directory to find the payload. 127 128 @return A URI to the desired image if found, None otherwise. It will most 129 likely be a file inside an image archive (image.zip), in which case 130 we'll be using ZIPFILE_BOUNDARY ('//') to denote a zip-encapsulated 131 file, for example: 132 gs://chromeos-image-archive/.../image.zip//chromiumos_test_image.bin 133 134 @raise TestImageError if an error has occurred. 135 136 """ 137 image_archive = gs_ls('image.zip', archive_url, single=True) 138 if not image_archive: 139 return None 140 141 return (image_archive[0] + ZIPFILE_BOUNDARY + 'chromiumos_test_image.bin') 142