Merge branch 'master' into origin-2883-job-log-viewer
[arvados.git] / sdk / python / arvados / commands / keepdocker.py
index 318f73096b7b393cdae5b4bd7d51087ac1c339a5..236d9fc0043c3438401d496116cd33e7ef7f8da8 100644 (file)
@@ -82,17 +82,31 @@ def docker_images():
     list_proc.stdout.close()
     check_docker(list_proc, "images")
 
-def find_image_hash(image_name, image_tag):
-    hash_search = image_name.lower()
+def find_image_hashes(image_search, image_tag=None):
+    # Given one argument, search for Docker images with matching hashes,
+    # and return their full hashes in a set.
+    # Given two arguments, also search for a Docker image with the
+    # same repository and tag.  If one is found, return its hash in a
+    # set; otherwise, fall back to the one-argument hash search.
+    # Returns None if no match is found, or a hash search is ambiguous.
+    hash_search = image_search.lower()
     hash_matches = set()
     for image in docker_images():
-        if (image.repo == image_name) and (image.tag == image_tag):
-            return image.hash
+        if (image.repo == image_search) and (image.tag == image_tag):
+            return set([image.hash])
         elif image.hash.startswith(hash_search):
             hash_matches.add(image.hash)
-    if len(hash_matches) == 1:
-        return hash_matches.pop()
-    return None
+    return hash_matches
+
+def find_one_image_hash(image_search, image_tag=None):
+    hashes = find_image_hashes(image_search, image_tag)
+    hash_count = len(hashes)
+    if hash_count == 1:
+        return hashes.pop()
+    elif hash_count == 0:
+        raise DockerError("no matching image found")
+    else:
+        raise DockerError("{} images match {}".format(hash_count, image_search))
 
 def stat_cache_name(image_file):
     return getattr(image_file, 'name', image_file) + '.stat'
@@ -143,14 +157,15 @@ def main(arguments=None):
 
     # Pull the image if requested, unless the image is specified as a hash
     # that we already have.
-    if args.pull and (find_image_hash(args.image, None) is None):
+    if args.pull and not find_image_hashes(args.image):
         pull_image(args.image, args.tag)
 
-    image_hash = find_image_hash(args.image, args.tag)
-    if image_hash is None:
-        print >>sys.stderr, "arv-keepdocker: No image found."
+    try:
+        image_hash = find_one_image_hash(args.image, args.tag)
+    except DockerError as error:
+        print >>sys.stderr, "arv-keepdocker:", error.message
         sys.exit(1)
-    elif not args.force:
+    if not args.force:
         # Abort if this image is already in Arvados.
         existing_links = arvados.api('v1').links().list(
             filters=[['link_class', '=', 'docker_image_hash'],
@@ -189,7 +204,8 @@ def main(arguments=None):
     make_link('docker_image_hash', image_hash, **link_base)
     if not image_hash.startswith(args.image.lower()):
         make_link('docker_image_repository', args.image, **link_base)
-        make_link('docker_image_tag', args.tag, **link_base)
+        make_link('docker_image_repo+tag', '{}:{}'.format(args.image, args.tag),
+                  **link_base)
 
     # Clean up.
     image_file.close()