Updater per PR comments
This commit is contained in:
parent
7a1eea2767
commit
39fdd2358e
1 changed files with 52 additions and 60 deletions
|
@ -23,7 +23,7 @@ module: docker_image
|
||||||
|
|
||||||
short_description: Manage docker images.
|
short_description: Manage docker images.
|
||||||
|
|
||||||
version_added: "2.1.0"
|
version_added: "1.5"
|
||||||
|
|
||||||
description:
|
description:
|
||||||
- Build, load or pull an image, making the image available for creating containers. Also supports tagging an
|
- Build, load or pull an image, making the image available for creating containers. Also supports tagging an
|
||||||
|
@ -35,10 +35,6 @@ options:
|
||||||
- Use with state 'present' to archive an image to a .tar file.
|
- Use with state 'present' to archive an image to a .tar file.
|
||||||
required: false
|
required: false
|
||||||
default: null
|
default: null
|
||||||
config_path:
|
|
||||||
description:
|
|
||||||
- Path to the Docker CLI config file.
|
|
||||||
default: '~/.docker/config.json'
|
|
||||||
dockerfile:
|
dockerfile:
|
||||||
description:
|
description:
|
||||||
- Use with state 'present' to provide an alternate name for the Dockerfile to use when building an image.
|
- Use with state 'present' to provide an alternate name for the Dockerfile to use when building an image.
|
||||||
|
@ -68,14 +64,9 @@ options:
|
||||||
- build_path
|
- build_path
|
||||||
default: null
|
default: null
|
||||||
required: false
|
required: false
|
||||||
push:
|
|
||||||
description:
|
|
||||||
- "Use with state present to always push an image to the registry. The image name must contain a repository
|
|
||||||
path and optionally a registry. For example: registry.ansible.com/user_a/repository"
|
|
||||||
default: false
|
|
||||||
pull:
|
pull:
|
||||||
description:
|
description:
|
||||||
- When building an image downloads any updates to the FROM image in Dockerfiles.
|
- When building an image downloads any updates to the FROM image in Dockerfile.
|
||||||
default: true
|
default: true
|
||||||
rm:
|
rm:
|
||||||
description:
|
description:
|
||||||
|
@ -99,7 +90,7 @@ options:
|
||||||
force option is used, the image will either be pulled, built or loaded. By default the image will be pulled
|
force option is used, the image will either be pulled, built or loaded. By default the image will be pulled
|
||||||
from Docker Hub. To build the image, provide a path value set to a directory containing a context and
|
from Docker Hub. To build the image, provide a path value set to a directory containing a context and
|
||||||
Dockerfile. To load an image, specify load_path to provide a path to an archive file. To tag an image to a
|
Dockerfile. To load an image, specify load_path to provide a path to an archive file. To tag an image to a
|
||||||
repository, provide a repository path.
|
repository, provide a repository path. If the name contains a repository path, it will be pushed.
|
||||||
- "NOTE: 'build' is DEPRECATED. Specifying 'build' will behave the same as 'present'."
|
- "NOTE: 'build' is DEPRECATED. Specifying 'build' will behave the same as 'present'."
|
||||||
default: present
|
default: present
|
||||||
choices:
|
choices:
|
||||||
|
@ -144,12 +135,11 @@ EXAMPLES = '''
|
||||||
docker_image:
|
docker_image:
|
||||||
name: pacur/centos-7
|
name: pacur/centos-7
|
||||||
|
|
||||||
- name: Tag to repository in private registry
|
- name: Tag to repository to a private registry and push it
|
||||||
docker_image:
|
docker_image:
|
||||||
name: pacur/centos-7
|
name: pacur/centos-7
|
||||||
repository: registry.ansible.com/chouseknecht/centos_images
|
repository: registry.ansible.com/chouseknecht/centos_images
|
||||||
tag: 7.0
|
tag: 7.0
|
||||||
push: yes
|
|
||||||
|
|
||||||
- name: Remove image
|
- name: Remove image
|
||||||
docker_image:
|
docker_image:
|
||||||
|
@ -157,7 +147,7 @@ EXAMPLES = '''
|
||||||
name: registry.ansible.com/chouseknecht/sinatra
|
name: registry.ansible.com/chouseknecht/sinatra
|
||||||
tag: v1
|
tag: v1
|
||||||
|
|
||||||
- name: Build an image
|
- name: Build an image ad push it to a private repo
|
||||||
docker_image:
|
docker_image:
|
||||||
path: ./sinatra
|
path: ./sinatra
|
||||||
name: registry.ansible.com/chouseknecht/sinatra
|
name: registry.ansible.com/chouseknecht/sinatra
|
||||||
|
@ -169,7 +159,7 @@ EXAMPLES = '''
|
||||||
tag: v1
|
tag: v1
|
||||||
archive_path: my_sinatra.tar
|
archive_path: my_sinatra.tar
|
||||||
|
|
||||||
- name: Load image from archive
|
- name: Load image from archive and push it to a private registry
|
||||||
docker_image:
|
docker_image:
|
||||||
name: registry.ansible.com/chouseknecht/sinatra
|
name: registry.ansible.com/chouseknecht/sinatra
|
||||||
tag: v1
|
tag: v1
|
||||||
|
@ -215,7 +205,6 @@ class ImageManager(DockerBaseClass):
|
||||||
self.check_mode = self.client.check_mode
|
self.check_mode = self.client.check_mode
|
||||||
|
|
||||||
self.archive_path = parameters.get('archive_path')
|
self.archive_path = parameters.get('archive_path')
|
||||||
self.config_path = parameters.get('config_path')
|
|
||||||
self.container_limits = parameters.get('container_limits')
|
self.container_limits = parameters.get('container_limits')
|
||||||
self.dockerfile = parameters.get('dockerfile')
|
self.dockerfile = parameters.get('dockerfile')
|
||||||
self.force = parameters.get('force')
|
self.force = parameters.get('force')
|
||||||
|
@ -224,12 +213,12 @@ class ImageManager(DockerBaseClass):
|
||||||
self.nocache = parameters.get('nocache')
|
self.nocache = parameters.get('nocache')
|
||||||
self.path = parameters.get('path')
|
self.path = parameters.get('path')
|
||||||
self.pull = parameters.get('pull')
|
self.pull = parameters.get('pull')
|
||||||
self.push = parameters.get('push')
|
|
||||||
self.repository = parameters.get('repository')
|
self.repository = parameters.get('repository')
|
||||||
self.rm = parameters.get('rm')
|
self.rm = parameters.get('rm')
|
||||||
self.state = parameters.get('state')
|
self.state = parameters.get('state')
|
||||||
self.tag = parameters.get('tag')
|
self.tag = parameters.get('tag')
|
||||||
self.http_timeout = parameters.get('http_timeout')
|
self.http_timeout = parameters.get('http_timeout')
|
||||||
|
self.push = False
|
||||||
|
|
||||||
if self.state in ['present', 'build']:
|
if self.state in ['present', 'build']:
|
||||||
self.present()
|
self.present()
|
||||||
|
@ -251,6 +240,7 @@ class ImageManager(DockerBaseClass):
|
||||||
if not image or self.force:
|
if not image or self.force:
|
||||||
if self.path:
|
if self.path:
|
||||||
# build the image
|
# build the image
|
||||||
|
self.push = True
|
||||||
params = dict(
|
params = dict(
|
||||||
path=self.path,
|
path=self.path,
|
||||||
tag=self.name,
|
tag=self.name,
|
||||||
|
@ -268,11 +258,11 @@ class ImageManager(DockerBaseClass):
|
||||||
if self.container_limits:
|
if self.container_limits:
|
||||||
params['container_limits'] = self.container_limits,
|
params['container_limits'] = self.container_limits,
|
||||||
self.log("Building image %s" % (params['tag']))
|
self.log("Building image %s" % (params['tag']))
|
||||||
|
self.results['actions'].append("Built image %s from %s" % (params['tag'], self.path))
|
||||||
|
self.results['changed'] = True
|
||||||
if not self.check_mode:
|
if not self.check_mode:
|
||||||
self.results['actions'].append("Built image %s from %s" % (params['tag'], self.path))
|
|
||||||
for line in self.client.build(**params):
|
for line in self.client.build(**params):
|
||||||
self.log(line, pretty_print=True)
|
self.log(line, pretty_print=True)
|
||||||
self.results['changed'] = True
|
|
||||||
image = self.client.find_image(name=self.name, tag=self.tag)
|
image = self.client.find_image(name=self.name, tag=self.tag)
|
||||||
if image:
|
if image:
|
||||||
self.results['image'] = image
|
self.results['image'] = image
|
||||||
|
@ -282,12 +272,14 @@ class ImageManager(DockerBaseClass):
|
||||||
if not os.path.isfile(self.load_path):
|
if not os.path.isfile(self.load_path):
|
||||||
self.fail("Error loading image %s. Specified path %s does not exist." % (self.name,
|
self.fail("Error loading image %s. Specified path %s does not exist." % (self.name,
|
||||||
self.load_path))
|
self.load_path))
|
||||||
|
self.push = True
|
||||||
name = self.name
|
name = self.name
|
||||||
if self.tag:
|
if self.tag:
|
||||||
name = "%s:%s" % (self.name, self.tag)
|
name = "%s:%s" % (self.name, self.tag)
|
||||||
|
|
||||||
|
self.results['actions'].append("Loaded image %s from %s" % (name, self.load_path))
|
||||||
|
self.results['changed'] = True
|
||||||
if not self.check_mode:
|
if not self.check_mode:
|
||||||
self.results['actions'].append("Loaded image %s from %s" % (name, self.load_path))
|
|
||||||
try:
|
try:
|
||||||
self.log("Reading image data from %s" % (self.load_path))
|
self.log("Reading image data from %s" % (self.load_path))
|
||||||
image_tar = open(self.load_path, 'r')
|
image_tar = open(self.load_path, 'r')
|
||||||
|
@ -298,15 +290,13 @@ class ImageManager(DockerBaseClass):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.log("Loading image from %s" % (self.load_path))
|
self.log("Loading image from %s" % (self.load_path))
|
||||||
response = self.client.load_image(image_data)
|
self.client.load_image(image_data)
|
||||||
except Exception, exc:
|
except Exception, exc:
|
||||||
self.fail("Error loading image %s - %s" % (name, str(exc)))
|
self.fail("Error loading image %s - %s" % (name, str(exc)))
|
||||||
|
|
||||||
self.results['changed'] = True
|
|
||||||
image = self.client.find_image(self.name, self.tag)
|
image = self.client.find_image(self.name, self.tag)
|
||||||
if image:
|
if image:
|
||||||
self.results['image'] = image
|
self.results['image'] = image
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# pull the image
|
# pull the image
|
||||||
if not self.check_mode:
|
if not self.check_mode:
|
||||||
|
@ -368,8 +358,9 @@ class ImageManager(DockerBaseClass):
|
||||||
except Exception, exc:
|
except Exception, exc:
|
||||||
self.fail("Error getting image %s - %s" % (image_name, str(exc)))
|
self.fail("Error getting image %s - %s" % (image_name, str(exc)))
|
||||||
|
|
||||||
|
self.results['actions'].append('Archived image %s to %s' % (image_name, self.archive_path))
|
||||||
|
self.results['changed'] = True
|
||||||
if not self.check_mode:
|
if not self.check_mode:
|
||||||
self.results['actions'].append('Archived image %s to %s' % (image_name, self.archive_path))
|
|
||||||
try:
|
try:
|
||||||
image_tar = open(self.archive_path, 'w')
|
image_tar = open(self.archive_path, 'w')
|
||||||
image_tar.write(image.data)
|
image_tar.write(image.data)
|
||||||
|
@ -377,50 +368,52 @@ class ImageManager(DockerBaseClass):
|
||||||
except Exception, exc:
|
except Exception, exc:
|
||||||
self.fail("Error writing image archive %s - %s" % (self.archive_path, str(exc)))
|
self.fail("Error writing image archive %s - %s" % (self.archive_path, str(exc)))
|
||||||
|
|
||||||
self.results['changed'] = True
|
|
||||||
image = self.client.find_image(name=name, tag=tag)
|
image = self.client.find_image(name=name, tag=tag)
|
||||||
if image:
|
if image:
|
||||||
self.results['image'] = image
|
self.results['image'] = image
|
||||||
|
|
||||||
def push_image(self, name, tag=None):
|
def push_image(self, name, tag=None):
|
||||||
'''
|
'''
|
||||||
Push an image to a repository.
|
If the name of the image contains a repository path, then push the image.
|
||||||
|
|
||||||
:param name - name of the image to push. Type: str
|
:param name Name of the image to push.
|
||||||
:param tag - use a specific tag. Type: str
|
:param tag Use a specific tag.
|
||||||
:return: None
|
:return: None
|
||||||
'''
|
'''
|
||||||
|
|
||||||
repository = name
|
repository = name
|
||||||
if not tag:
|
if not tag:
|
||||||
repository, tag = utils.parse_repository_tag(name)
|
repository, tag = utils.parse_repository_tag(name)
|
||||||
registry, repo_name = auth.resolve_repository_name(repository)
|
registry, repo_name = auth.resolve_repository_name(repository)
|
||||||
|
|
||||||
if registry:
|
if re.search('/', repository):
|
||||||
config = auth.load_config()
|
|
||||||
if not auth.resolve_authconfig(config, registry):
|
|
||||||
self.fail("Error: configuration for %s not found. Try logging into %s first." % registry)
|
|
||||||
|
|
||||||
try:
|
if registry:
|
||||||
self.log("pushing image %s" % (repository))
|
config = auth.load_config()
|
||||||
status = None
|
if not auth.resolve_authconfig(config, registry):
|
||||||
if not self.check_mode:
|
self.fail("Error: configuration for %s not found. Try logging into %s first." % registry)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.log("pushing image %s" % (repository))
|
||||||
|
status = None
|
||||||
self.results['actions'].append("Pushed image %s to %s:%s" % (self.name, self.repository, self.tag))
|
self.results['actions'].append("Pushed image %s to %s:%s" % (self.name, self.repository, self.tag))
|
||||||
for line in self.client.push(repository, tag=tag, stream=True):
|
self.results['changed'] = True
|
||||||
response = json.loads(line)
|
if not self.check_mode:
|
||||||
self.log(response, pretty_print=True)
|
for line in self.client.push(repository, tag=tag, stream=True):
|
||||||
if response.get('errorDetail'):
|
response = json.loads(line)
|
||||||
# there was an error
|
self.log(response, pretty_print=True)
|
||||||
raise Exception(response['errorDetail']['message'])
|
if response.get('errorDetail'):
|
||||||
status = response.get('status')
|
# there was an error
|
||||||
self.results['changed'] = True
|
raise Exception(response['errorDetail']['message'])
|
||||||
image = self.client.find_image(name=repository, tag=tag)
|
status = response.get('status')
|
||||||
if image:
|
image = self.client.find_image(name=repository, tag=tag)
|
||||||
self.results['image'] = image
|
if image:
|
||||||
self.results['image']['push_status'] = status
|
self.results['image'] = image
|
||||||
except Exception, exc:
|
self.results['image']['push_status'] = status
|
||||||
if re.search(r'unauthorized', str(exc)):
|
except Exception, exc:
|
||||||
self.fail("Error pushing image %s: %s. Does the repository exist?" % (repository, str(exc)))
|
if re.search(r'unauthorized', str(exc)):
|
||||||
self.fail("Error pushing image %s: %s" % (repository, str(exc)))
|
self.fail("Error pushing image %s: %s. Does the repository exist?" % (repository, str(exc)))
|
||||||
|
self.fail("Error pushing image %s: %s" % (repository, str(exc)))
|
||||||
|
|
||||||
def tag_image(self, name, tag, repository, force=False, push=False):
|
def tag_image(self, name, tag, repository, force=False, push=False):
|
||||||
'''
|
'''
|
||||||
|
@ -441,11 +434,14 @@ class ImageManager(DockerBaseClass):
|
||||||
try:
|
try:
|
||||||
self.log("tagging %s:%s to %s" % (name, tag, repository))
|
self.log("tagging %s:%s to %s" % (name, tag, repository))
|
||||||
self.results['changed'] = True
|
self.results['changed'] = True
|
||||||
|
self.results['actions'].append("Tagged image %s:%s to %s" % (name, tag, repository))
|
||||||
if not self.check_mode:
|
if not self.check_mode:
|
||||||
self.results['actions'].append("Tagged image %s:%s to %s" % (name, tag, repository))
|
|
||||||
# Finding the image does not always work, especially running a localhost registry. In those
|
# Finding the image does not always work, especially running a localhost registry. In those
|
||||||
# cases, if we don't set force=True, it errors.
|
# cases, if we don't set force=True, it errors.
|
||||||
tag_status = self.client.tag(name, repository, tag=tag, force=True)
|
image_name = name
|
||||||
|
if tag and not re.search(tag, name):
|
||||||
|
image_name = "%s:%s" % (name, tag)
|
||||||
|
tag_status = self.client.tag(image_name, repository, tag=tag, force=True)
|
||||||
if not tag_status:
|
if not tag_status:
|
||||||
raise Exception("Tag operation failed.")
|
raise Exception("Tag operation failed.")
|
||||||
image = self.client.find_image(name=repository, tag=tag)
|
image = self.client.find_image(name=repository, tag=tag)
|
||||||
|
@ -454,15 +450,12 @@ class ImageManager(DockerBaseClass):
|
||||||
except Exception, exc:
|
except Exception, exc:
|
||||||
self.fail("Error: failed to tag image %s - %s" % (name, str(exc)))
|
self.fail("Error: failed to tag image %s - %s" % (name, str(exc)))
|
||||||
|
|
||||||
if push:
|
self.push_image(repository, tag)
|
||||||
self.log("push %s with tag %s" % (repository, tag))
|
|
||||||
self.push_image(repository, tag)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
argument_spec = dict(
|
argument_spec = dict(
|
||||||
archive_path=dict(type='str'),
|
archive_path=dict(type='str'),
|
||||||
config_path=dict(type='str'),
|
|
||||||
container_limits=dict(type='dict'),
|
container_limits=dict(type='dict'),
|
||||||
dockerfile=dict(type='str'),
|
dockerfile=dict(type='str'),
|
||||||
force=dict(type='bool', default=False),
|
force=dict(type='bool', default=False),
|
||||||
|
@ -472,7 +465,6 @@ def main():
|
||||||
nocache=dict(type='str', default=False),
|
nocache=dict(type='str', default=False),
|
||||||
path=dict(type='str', aliases=['build_path']),
|
path=dict(type='str', aliases=['build_path']),
|
||||||
pull=dict(type='bool', default=True),
|
pull=dict(type='bool', default=True),
|
||||||
push=dict(type='bool', default=False),
|
|
||||||
repository=dict(type='str'),
|
repository=dict(type='str'),
|
||||||
rm=dict(type='bool', default=True),
|
rm=dict(type='bool', default=True),
|
||||||
state=dict(type='str', choices=['absent', 'present'], default='present'),
|
state=dict(type='str', choices=['absent', 'present'], default='present'),
|
||||||
|
|
Loading…
Reference in a new issue