X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/e8ae9364dce380d305833f35dfb25578175664d7..36360d1f2987cea89ce217a2519c01da7456d533:/sdk/python/arvados/commands/keepdocker.py diff --git a/sdk/python/arvados/commands/keepdocker.py b/sdk/python/arvados/commands/keepdocker.py index db77dc8837..3a0b64c38f 100644 --- a/sdk/python/arvados/commands/keepdocker.py +++ b/sdk/python/arvados/commands/keepdocker.py @@ -21,12 +21,18 @@ import arvados.commands._util as arv_cmd import arvados.commands.put as arv_put import ciso8601 +from arvados._version import __version__ + +EARLIEST_DATETIME = datetime.datetime(datetime.MINYEAR, 1, 1, 0, 0, 0) STAT_CACHE_ERRORS = (IOError, OSError, ValueError) DockerImage = collections.namedtuple( 'DockerImage', ['repo', 'tag', 'hash', 'created', 'vsize']) keepdocker_parser = argparse.ArgumentParser(add_help=False) +keepdocker_parser.add_argument( + '--version', action='version', version="%s %s" % (sys.argv[0], __version__), + help='Print version and exit.') keepdocker_parser.add_argument( '-f', '--force', action='store_true', default=False, help="Re-upload the image even if it already exists on the server") @@ -175,7 +181,7 @@ def docker_link_sort_key(link): image_timestamp = ciso8601.parse_datetime_unaware( link['properties']['image_timestamp']) except (KeyError, ValueError): - image_timestamp = 0 + image_timestamp = EARLIEST_DATETIME return (image_timestamp, ciso8601.parse_datetime_unaware(link['created_at'])) @@ -188,9 +194,10 @@ def _get_docker_links(api_client, num_retries, **kwargs): return links def _new_image_listing(link, dockerhash, repo='', tag=''): + timestamp_index = 1 if (link['_sort_key'][0] is EARLIEST_DATETIME) else 0 return { '_sort_key': link['_sort_key'], - 'timestamp': link['_sort_key'][0] or link['_sort_key'][1], + 'timestamp': link['_sort_key'][timestamp_index], 'collection': link['head_uuid'], 'dockerhash': dockerhash, 'repo': repo, @@ -281,15 +288,18 @@ def list_images_in_arv(api_client, num_retries, image_name=None, image_tag=None) return [(image['collection'], image) for image in images if image['collection'] in existing_coll_uuids] -def main(arguments=None): +def items_owned_by(owner_uuid, arv_items): + return (item for item in arv_items if item['owner_uuid'] == owner_uuid) + +def main(arguments=None, stdout=sys.stdout): args = arg_parser.parse_args(arguments) api = arvados.api('v1') if args.image is None or args.image == 'images': - fmt = "{:30} {:10} {:12} {:29} {:20}" - print fmt.format("REPOSITORY", "TAG", "IMAGE ID", "COLLECTION", "CREATED") + fmt = "{:30} {:10} {:12} {:29} {:20}\n" + stdout.write(fmt.format("REPOSITORY", "TAG", "IMAGE ID", "COLLECTION", "CREATED")) for i, j in list_images_in_arv(api, args.retries): - print(fmt.format(j["repo"], j["tag"], j["dockerhash"][0:12], i, j["timestamp"].strftime("%c"))) + stdout.write(fmt.format(j["repo"], j["tag"], j["dockerhash"][0:12], i, j["timestamp"].strftime("%c"))) sys.exit(0) # Pull the image if requested, unless the image is specified as a hash @@ -324,10 +334,10 @@ def main(arguments=None): num_retries=args.retries)['uuid'] # Find image hash tags - existing_links = api.links().list( + existing_links = _get_docker_links( + api, args.retries, filters=[['link_class', '=', 'docker_image_hash'], - ['name', '=', image_hash]] - ).execute(num_retries=args.retries)['items'] + ['name', '=', image_hash]]) if existing_links: # get readable collections collections = api.collections().list( @@ -337,21 +347,18 @@ def main(arguments=None): if collections: # check for repo+tag links on these collections - existing_repo_tag = (api.links().list( - filters=[['link_class', '=', 'docker_image_repo+tag'], - ['name', '=', image_repo_tag], - ['head_uuid', 'in', collections]] - ).execute(num_retries=args.retries)['items']) if image_repo_tag else [] - - # Filter on elements owned by the parent project - owned_col = [c for c in collections if c['owner_uuid'] == parent_project_uuid] - owned_img = [c for c in existing_links if c['owner_uuid'] == parent_project_uuid] - owned_rep = [c for c in existing_repo_tag if c['owner_uuid'] == parent_project_uuid] - - if owned_col: - # already have a collection owned by this project - coll_uuid = owned_col[0]['uuid'] + if image_repo_tag: + existing_repo_tag = _get_docker_links( + api, args.retries, + filters=[['link_class', '=', 'docker_image_repo+tag'], + ['name', '=', image_repo_tag], + ['head_uuid', 'in', collections]]) else: + existing_repo_tag = [] + + try: + coll_uuid = next(items_owned_by(parent_project_uuid, collections))['uuid'] + except StopIteration: # create new collection owned by the project coll_uuid = api.collections().create( body={"manifest_text": collections[0]['manifest_text'], @@ -361,19 +368,20 @@ def main(arguments=None): ).execute(num_retries=args.retries)['uuid'] link_base = {'owner_uuid': parent_project_uuid, - 'head_uuid': coll_uuid } + 'head_uuid': coll_uuid, + 'properties': existing_links[0]['properties']} - if not owned_img: + if not any(items_owned_by(parent_project_uuid, existing_links)): # create image link owned by the project make_link(api, args.retries, 'docker_image_hash', image_hash, **link_base) - if not owned_rep and image_repo_tag: + if image_repo_tag and not any(items_owned_by(parent_project_uuid, existing_repo_tag)): # create repo+tag link owned by the project make_link(api, args.retries, 'docker_image_repo+tag', image_repo_tag, **link_base) - print(coll_uuid) + stdout.write(coll_uuid + "\n") sys.exit(0) @@ -391,12 +399,17 @@ def main(arguments=None): put_args += ['--name', collection_name] coll_uuid = arv_put.main( - put_args + ['--filename', outfile_name, image_file.name]).strip() + put_args + ['--filename', outfile_name, image_file.name], stdout=stdout).strip() # Read the image metadata and make Arvados links from it. image_file.seek(0) image_tar = tarfile.open(fileobj=image_file) - json_file = image_tar.extractfile(image_tar.getmember(image_hash + '/json')) + image_hash_type, _, raw_image_hash = image_hash.rpartition(':') + if image_hash_type: + json_filename = raw_image_hash + '.json' + else: + json_filename = raw_image_hash + '/json' + json_file = image_tar.extractfile(image_tar.getmember(json_filename)) image_metadata = json.load(json_file) json_file.close() image_tar.close()