diff --git a/lib/ansible/module_utils/docker_common.py b/lib/ansible/module_utils/docker_common.py index c989e0fca3..c324883863 100644 --- a/lib/ansible/module_utils/docker_common.py +++ b/lib/ansible/module_utils/docker_common.py @@ -36,6 +36,7 @@ try: from docker.tls import TLSConfig from docker.constants import DEFAULT_TIMEOUT_SECONDS, DEFAULT_DOCKER_API_VERSION from docker.utils.types import Ulimit, LogConfig + from docker import auth except ImportError, exc: HAS_DOCKER_ERROR = str(exc) HAS_DOCKER_PY = False @@ -114,6 +115,7 @@ class DockerBaseClass(object): # log_file = open('docker.log', 'a') # if pretty_print: # log_file.write(json.dumps(msg, sort_keys=True, indent=4, separators=(',', ': '))) + # log_file.write(u'\n') # else: # log_file.write(msg + u'\n') @@ -166,11 +168,11 @@ class AnsibleDockerClient(Client): def log(self, msg, pretty_print=False): pass - # if self.debug: # log_file = open('docker.log', 'a') # if pretty_print: # log_file.write(json.dumps(msg, sort_keys=True, indent=4, separators=(',', ': '))) + # log_file.write(u'\n') # else: # log_file.write(msg + u'\n') @@ -392,40 +394,70 @@ class AnsibleDockerClient(Client): if not name: return None - lookup = name - if tag: - lookup = "%s:%s" % (name, tag) - - self.log("Find image %s" % lookup) - try: - images = self.images(name=lookup) - except Exception, exc: - self.fail("Error getting image: %s" % str(exc)) + self.log("Find image %s:%s" % (name, tag)) + images = self._image_lookup(name, tag) + if len(images) == 0: + # In API <= 1.20 seeing 'docker.io/' as the name of images pulled from docker hub + registry, repo_name = auth.resolve_repository_name(name) + if registry == 'docker.io': + # the name does not contain a registry, so let's see if docker.io works + lookup = "docker.io/%s" % name + self.log("Check for docker.io image: %s" % lookup) + images = self._image_lookup(lookup, tag) if len(images) > 1: - self.fail("Registry returned more than one result for %s" % lookup) + self.fail("Registry returned more than one result for %s:%s" % (name, tag)) if len(images) == 1: try: inspection = self.inspect_image(images[0]['Id']) except Exception, exc: - self.fail("Error inspecting image %s - %s" % (lookup, str(exc))) - inspection['Name'] = lookup + self.fail("Error inspecting image %s:%s - %s" % (name, tag, str(exc))) return inspection - self.log("Image %s not found." % lookup) + + self.log("Image %s:%s not found." % (name, tag)) return None + def _image_lookup(self, name, tag): + ''' + Including a tag in the name parameter sent to the docker-py images method does not + work consistently. Instead, get the result set for name and manually check if the tag + exists. + ''' + try: + response = self.images(name=name) + except Exception as exc: + self.fail("Error searching for image %s - %s" % (name, str(exc))) + images = response + if tag: + lookup = "%s:%s" % (name, tag) + for image in response: + self.log(image, pretty_print=True) + if image.get('RepoTags') and lookup in image.get('RepoTags'): + images = [image] + break + return images + def pull_image(self, name, tag="latest"): ''' Pull an image ''' + self.log("Pulling image %s:%s" % (name, tag)) try: - self.log("Pulling image %s:%s" % (name, tag)) for line in self.pull(name, tag=tag, stream=True): - response = json.loads(line) - self.log(response, pretty_print=True) - return self.find_image(name, tag) + line = json.loads(line) + self.log(line, pretty_print=True) + if line.get('error'): + if line.get('errorDetail'): + error_detail = line.get('errorDetail') + self.fail("Error pulling %s - code: %s message: %s" % (name, + error_detail.get('code'), + error_detail.get('message'))) + else: + self.fail("Error pulling %s - %s" % (name, line.get('error'))) except Exception, exc: self.fail("Error pulling image %s:%s - %s" % (name, tag, str(exc))) + return self.find_image(name, tag) +