459a76c0dd
The new present state just makes sure that a container exists, not that it's running, although it get started one creation. This is very useful for data volumes. This also changes the old present, now running (default) state to only create the container if it's not found, otherwise it just get started. See also discussion on mailinglist: https://groups.google.com/forum/#!topic/ansible-devel/jB84gdhPzLQ This closes #6395
730 lines
24 KiB
Python
730 lines
24 KiB
Python
#!/usr/bin/python
|
|
|
|
# (c) 2013, Cove Schneider
|
|
# (c) 2014, Joshua Conner <joshua.conner@gmail.com>
|
|
# (c) 2014, Pavel Antonov <antonov@adwz.ru>
|
|
#
|
|
# This file is part of Ansible,
|
|
#
|
|
# Ansible is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# Ansible is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
######################################################################
|
|
|
|
DOCUMENTATION = '''
|
|
---
|
|
module: docker
|
|
version_added: "1.4"
|
|
short_description: manage docker containers
|
|
description:
|
|
- Manage the life cycle of docker containers.
|
|
options:
|
|
count:
|
|
description:
|
|
- Set number of containers to run
|
|
required: False
|
|
default: 1
|
|
aliases: []
|
|
image:
|
|
description:
|
|
- Set container image to use
|
|
required: true
|
|
default: null
|
|
aliases: []
|
|
command:
|
|
description:
|
|
- Set command to run in a container on startup
|
|
required: false
|
|
default: null
|
|
aliases: []
|
|
name:
|
|
description:
|
|
- Set name for container (used to find single container or to provide links)
|
|
required: false
|
|
default: null
|
|
aliases: []
|
|
version_added: "1.5"
|
|
ports:
|
|
description:
|
|
- Set private to public port mapping specification using docker CLI-style syntax [([<host_interface>:[host_port]])|(<host_port>):]<container_port>[/udp]
|
|
required: false
|
|
default: null
|
|
aliases: []
|
|
version_added: "1.5"
|
|
expose:
|
|
description:
|
|
- Set container ports to expose for port mappings or links. (If the port is already exposed using EXPOSE in a Dockerfile, you don't need to expose it again.)
|
|
required: false
|
|
default: null
|
|
aliases: []
|
|
version_added: "1.5"
|
|
publish_all_ports:
|
|
description:
|
|
- Publish all exposed ports to the host interfaces
|
|
required: false
|
|
default: false
|
|
aliases: []
|
|
version_added: "1.5"
|
|
volumes:
|
|
description:
|
|
- Set volume(s) to mount on the container
|
|
required: false
|
|
default: null
|
|
aliases: []
|
|
volumes_from:
|
|
description:
|
|
- Set shared volume(s) from another container
|
|
required: false
|
|
default: null
|
|
aliases: []
|
|
links:
|
|
description:
|
|
- Link container(s) to other container(s) (e.g. links=redis,postgresql:db)
|
|
required: false
|
|
default: null
|
|
aliases: []
|
|
version_added: "1.5"
|
|
memory_limit:
|
|
description:
|
|
- Set RAM allocated to container
|
|
required: false
|
|
default: null
|
|
aliases: []
|
|
default: 256MB
|
|
docker_url:
|
|
description:
|
|
- URL of docker host to issue commands to
|
|
required: false
|
|
default: unix://var/run/docker.sock
|
|
aliases: []
|
|
username:
|
|
description:
|
|
- Set remote API username
|
|
required: false
|
|
default: null
|
|
aliases: []
|
|
password:
|
|
description:
|
|
- Set remote API password
|
|
required: false
|
|
default: null
|
|
aliases: []
|
|
hostname:
|
|
description:
|
|
- Set container hostname
|
|
required: false
|
|
default: null
|
|
aliases: []
|
|
env:
|
|
description:
|
|
- Set environment variables (e.g. env="PASSWORD=sEcRe7,WORKERS=4")
|
|
required: false
|
|
default: null
|
|
aliases: []
|
|
dns:
|
|
description:
|
|
- Set custom DNS servers for the container
|
|
required: false
|
|
default: null
|
|
aliases: []
|
|
detach:
|
|
description:
|
|
- Enable detached mode on start up, leaves container running in background
|
|
required: false
|
|
default: true
|
|
aliases: []
|
|
state:
|
|
description:
|
|
- Set the state of the container
|
|
required: false
|
|
default: present
|
|
choices: [ "present", "running", "stopped", "absent", "killed", "restarted" ]
|
|
aliases: []
|
|
privileged:
|
|
description:
|
|
- Set whether the container should run in privileged mode
|
|
required: false
|
|
default: false
|
|
aliases: []
|
|
lxc_conf:
|
|
description:
|
|
- LXC config parameters, e.g. lxc.aa_profile:unconfined
|
|
required: false
|
|
default:
|
|
aliases: []
|
|
name:
|
|
description:
|
|
- Set the name of the container (cannot use with count)
|
|
required: false
|
|
default: null
|
|
aliases: []
|
|
version_added: "1.5"
|
|
author: Cove Schneider, Joshua Conner, Pavel Antonov
|
|
requirements: [ "docker-py >= 0.3.0" ]
|
|
'''
|
|
|
|
EXAMPLES = '''
|
|
Start one docker container running tomcat in each host of the web group and bind tomcat's listening port to 8080
|
|
on the host:
|
|
|
|
- hosts: web
|
|
sudo: yes
|
|
tasks:
|
|
- name: run tomcat servers
|
|
docker: image=centos command="service tomcat6 start" ports=8080
|
|
|
|
The tomcat server's port is NAT'ed to a dynamic port on the host, but you can determine which port the server was
|
|
mapped to using docker_containers:
|
|
|
|
- hosts: web
|
|
sudo: yes
|
|
tasks:
|
|
- name: run tomcat servers
|
|
docker: image=centos command="service tomcat6 start" ports=8080 count=5
|
|
- name: Display IP address and port mappings for containers
|
|
debug: msg={{inventory_hostname}}:{{item['HostConfig']['PortBindings']['8080/tcp'][0]['HostPort']}}
|
|
with_items: docker_containers
|
|
|
|
Just as in the previous example, but iterates over the list of docker containers with a sequence:
|
|
|
|
- hosts: web
|
|
sudo: yes
|
|
vars:
|
|
start_containers_count: 5
|
|
tasks:
|
|
- name: run tomcat servers
|
|
docker: image=centos command="service tomcat6 start" ports=8080 count={{start_containers_count}}
|
|
- name: Display IP address and port mappings for containers
|
|
debug: msg="{{inventory_hostname}}:{{docker_containers[{{item}}]['HostConfig']['PortBindings']['8080/tcp'][0]['HostPort']}}"
|
|
with_sequence: start=0 end={{start_containers_count - 1}}
|
|
|
|
Stop, remove all of the running tomcat containers and list the exit code from the stopped containers:
|
|
|
|
- hosts: web
|
|
sudo: yes
|
|
tasks:
|
|
- name: stop tomcat servers
|
|
docker: image=centos command="service tomcat6 start" state=absent
|
|
- name: Display return codes from stopped containers
|
|
debug: msg="Returned {{inventory_hostname}}:{{item}}"
|
|
with_items: docker_containers
|
|
|
|
Create a named container:
|
|
|
|
- hosts: web
|
|
sudo: yes
|
|
tasks:
|
|
- name: run tomcat server
|
|
docker: image=centos name=tomcat command="service tomcat6 start" ports=8080
|
|
|
|
Create multiple named containers:
|
|
|
|
- hosts: web
|
|
sudo: yes
|
|
tasks:
|
|
- name: run tomcat servers
|
|
docker: image=centos name={{item}} command="service tomcat6 start" ports=8080
|
|
with_items:
|
|
- crookshank
|
|
- snowbell
|
|
- heathcliff
|
|
- felix
|
|
- sylvester
|
|
|
|
Create containers named in a sequence:
|
|
|
|
- hosts: web
|
|
sudo: yes
|
|
tasks:
|
|
- name: run tomcat servers
|
|
docker: image=centos name={{item}} command="service tomcat6 start" ports=8080
|
|
with_sequence: start=1 end=5 format=tomcat_%d.example.com
|
|
|
|
Create two linked containers:
|
|
|
|
- hosts: web
|
|
sudo: yes
|
|
tasks:
|
|
- name: ensure redis container is running
|
|
docker: image=crosbymichael/redis name=redis
|
|
|
|
- name: ensure redis_ambassador container is running
|
|
docker: image=svendowideit/ambassador ports=6379:6379 links=redis:redis name=redis_ambassador_ansible
|
|
|
|
Create containers with options specified as key-value pairs and lists:
|
|
|
|
- hosts: web
|
|
sudo: yes
|
|
tasks:
|
|
- docker:
|
|
image: namespace/image_name
|
|
links:
|
|
- postgresql:db
|
|
- redis:redis
|
|
|
|
|
|
Create containers with options specified as strings and lists as comma-separated strings:
|
|
|
|
- hosts: web
|
|
sudo: yes
|
|
tasks:
|
|
docker: image=namespace/image_name links=postgresql:db,redis:redis
|
|
'''
|
|
|
|
HAS_DOCKER_PY = True
|
|
|
|
import sys
|
|
from urlparse import urlparse
|
|
try:
|
|
import docker.client
|
|
from requests.exceptions import *
|
|
except ImportError, e:
|
|
HAS_DOCKER_PY = False
|
|
|
|
|
|
def _human_to_bytes(number):
|
|
suffixes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
|
|
|
|
if isinstance(number, int):
|
|
return number
|
|
if number[-1] == suffixes[0] and number[-2].isdigit():
|
|
return number[:-1]
|
|
|
|
i = 1
|
|
for each in suffixes[1:]:
|
|
if number[-len(each):] == suffixes[i]:
|
|
return int(number[:-len(each)]) * (1024 ** i)
|
|
i = i + 1
|
|
|
|
print "failed=True msg='Could not convert %s to integer'" % (number)
|
|
sys.exit(1)
|
|
|
|
def _ansible_facts(container_list):
|
|
return {"docker_containers": container_list}
|
|
|
|
def _docker_id_quirk(inspect):
|
|
# XXX: some quirk in docker
|
|
if 'ID' in inspect:
|
|
inspect['Id'] = inspect['ID']
|
|
del inspect['ID']
|
|
return inspect
|
|
|
|
class DockerManager:
|
|
|
|
counters = {'created':0, 'started':0, 'stopped':0, 'killed':0, 'removed':0, 'restarted':0, 'pull':0}
|
|
|
|
def __init__(self, module):
|
|
self.module = module
|
|
|
|
self.binds = None
|
|
self.volumes = None
|
|
if self.module.params.get('volumes'):
|
|
self.binds = {}
|
|
self.volumes = {}
|
|
vols = self.parse_list_from_param('volumes')
|
|
for vol in vols:
|
|
parts = vol.split(":")
|
|
# host mount (e.g. /mnt:/tmp, bind mounts host's /tmp to /mnt in the container)
|
|
if len(parts) == 2:
|
|
self.volumes[parts[1]] = {}
|
|
self.binds[parts[0]] = parts[1]
|
|
# docker mount (e.g. /www, mounts a docker volume /www on the container at the same location)
|
|
else:
|
|
self.volumes[parts[0]] = {}
|
|
|
|
self.lxc_conf = None
|
|
if self.module.params.get('lxc_conf'):
|
|
self.lxc_conf = []
|
|
options = self.parse_list_from_param('lxc_conf')
|
|
for option in options:
|
|
parts = option.split(':')
|
|
self.lxc_conf.append({"Key": parts[0], "Value": parts[1]})
|
|
|
|
self.exposed_ports = None
|
|
if self.module.params.get('expose'):
|
|
expose = self.parse_list_from_param('expose')
|
|
self.exposed_ports = self.get_exposed_ports(expose)
|
|
|
|
self.port_bindings = None
|
|
if self.module.params.get('ports'):
|
|
ports = self.parse_list_from_param('ports')
|
|
self.port_bindings = self.get_port_bindings(ports)
|
|
|
|
self.links = None
|
|
if self.module.params.get('links'):
|
|
links = self.parse_list_from_param('links')
|
|
self.links = dict(map(lambda x: x.split(':'), links))
|
|
|
|
self.env = None
|
|
if self.module.params.get('env'):
|
|
env = self.parse_list_from_param('env')
|
|
self.env = dict(map(lambda x: x.split("="), env))
|
|
|
|
# connect to docker server
|
|
docker_url = urlparse(module.params.get('docker_url'))
|
|
self.client = docker.Client(base_url=docker_url.geturl())
|
|
|
|
|
|
def parse_list_from_param(self, param_name, delimiter=','):
|
|
"""
|
|
Get a list from a module parameter, whether it's specified as a delimiter-separated string or is already in list form.
|
|
"""
|
|
param_list = self.module.params.get(param_name)
|
|
if not isinstance(param_list, list):
|
|
param_list = param_list.split(delimiter)
|
|
return param_list
|
|
|
|
|
|
def get_exposed_ports(self, expose_list):
|
|
"""
|
|
Parse the ports and protocols (TCP/UDP) to expose in the docker-py `create_container` call from the docker CLI-style syntax.
|
|
"""
|
|
if expose_list:
|
|
exposed = []
|
|
for port in expose_list:
|
|
if port.endswith('/tcp') or port.endswith('/udp'):
|
|
port_with_proto = tuple(port.split('/'))
|
|
else:
|
|
# assume tcp protocol if not specified
|
|
port_with_proto = (port, 'tcp')
|
|
exposed.append(port_with_proto)
|
|
return exposed
|
|
else:
|
|
return None
|
|
|
|
|
|
def get_port_bindings(self, ports):
|
|
"""
|
|
Parse the `ports` string into a port bindings dict for the `start_container` call.
|
|
"""
|
|
binds = {}
|
|
for port in ports:
|
|
parts = port.split(':')
|
|
container_port = parts[-1]
|
|
if '/' not in container_port:
|
|
container_port = int(parts[-1])
|
|
|
|
p_len = len(parts)
|
|
if p_len == 1:
|
|
# Bind `container_port` of the container to a dynamically
|
|
# allocated TCP port on all available interfaces of the host
|
|
# machine.
|
|
bind = ('0.0.0.0',)
|
|
elif p_len == 2:
|
|
# Bind `container_port` of the container to port `parts[0]` on
|
|
# all available interfaces of the host machine.
|
|
bind = ('0.0.0.0', int(parts[0]))
|
|
elif p_len == 3:
|
|
# Bind `container_port` of the container to port `parts[1]` on
|
|
# IP `parts[0]` of the host machine. If `parts[1]` empty bind
|
|
# to a dynamically allocacted port of IP `parts[0]`.
|
|
bind = (parts[0], int(parts[1])) if parts[1] else (parts[0],)
|
|
|
|
if container_port in binds:
|
|
old_bind = binds[container_port]
|
|
if isinstance(old_bind, list):
|
|
# append to list if it already exists
|
|
old_bind.append(bind)
|
|
else:
|
|
# otherwise create list that contains the old and new binds
|
|
binds[container_port] = [binds[container_port], bind]
|
|
else:
|
|
binds[container_port] = bind
|
|
|
|
return binds
|
|
|
|
|
|
|
|
def get_split_image_tag(self, image):
|
|
if '/' in image:
|
|
image = image.split('/')[1]
|
|
tag = None
|
|
if image.find(':') > 0:
|
|
return image.split(':')
|
|
else:
|
|
return image, tag
|
|
|
|
def get_summary_counters_msg(self):
|
|
msg = ""
|
|
for k, v in self.counters.iteritems():
|
|
msg = msg + "%s %d " % (k, v)
|
|
|
|
return msg
|
|
|
|
def increment_counter(self, name):
|
|
self.counters[name] = self.counters[name] + 1
|
|
|
|
def has_changed(self):
|
|
for k, v in self.counters.iteritems():
|
|
if v > 0:
|
|
return True
|
|
|
|
return False
|
|
|
|
def get_inspect_containers(self, containers):
|
|
inspect = []
|
|
for i in containers:
|
|
details = self.client.inspect_container(i['Id'])
|
|
details = _docker_id_quirk(details)
|
|
inspect.append(details)
|
|
|
|
return inspect
|
|
|
|
def get_deployed_containers(self):
|
|
# determine which images/commands are running already
|
|
containers = self.client.containers(all=True)
|
|
image = self.module.params.get('image')
|
|
command = self.module.params.get('command')
|
|
if command:
|
|
command = command.strip()
|
|
name = self.module.params.get('name')
|
|
if name and not name.startswith('/'):
|
|
name = '/' + name
|
|
deployed = []
|
|
|
|
# if we weren't given a tag with the image, we need to only compare on the image name, as that
|
|
# docker will give us back the full image name including a tag in the container list if one exists.
|
|
image, tag = self.get_split_image_tag(image)
|
|
|
|
for i in containers:
|
|
running_image, running_tag = self.get_split_image_tag(i['Image'])
|
|
running_command = i['Command'].strip()
|
|
|
|
if (name and name in i['Names']) or \
|
|
(not name and running_image == image and (not tag or tag == running_tag) and
|
|
(not command or running_command == command)):
|
|
details = self.client.inspect_container(i['Id'])
|
|
details = _docker_id_quirk(details)
|
|
deployed.append(details)
|
|
|
|
return deployed
|
|
|
|
def get_running_containers(self):
|
|
running = []
|
|
for i in self.get_deployed_containers():
|
|
if i['State']['Running'] == True and i['State']['Ghost'] == False:
|
|
running.append(i)
|
|
|
|
return running
|
|
|
|
def create_containers(self, count=1):
|
|
params = {'image': self.module.params.get('image'),
|
|
'command': self.module.params.get('command'),
|
|
'ports': self.exposed_ports,
|
|
'volumes': self.volumes,
|
|
'volumes_from': self.module.params.get('volumes_from'),
|
|
'mem_limit': _human_to_bytes(self.module.params.get('memory_limit')),
|
|
'environment': self.env,
|
|
'dns': self.module.params.get('dns'),
|
|
'hostname': self.module.params.get('hostname'),
|
|
'detach': self.module.params.get('detach'),
|
|
'name': self.module.params.get('name'),
|
|
}
|
|
|
|
def do_create(count, params):
|
|
results = []
|
|
for _ in range(count):
|
|
result = self.client.create_container(**params)
|
|
self.increment_counter('created')
|
|
results.append(result)
|
|
|
|
return results
|
|
|
|
try:
|
|
containers = do_create(count, params)
|
|
except:
|
|
self.client.pull(params['image'])
|
|
self.increment_counter('pull')
|
|
containers = do_create(count, params)
|
|
|
|
return containers
|
|
|
|
def start_containers(self, containers):
|
|
params = {
|
|
'lxc_conf': self.lxc_conf,
|
|
'binds': self.binds,
|
|
'port_bindings': self.port_bindings,
|
|
'publish_all_ports': self.module.params.get('publish_all_ports'),
|
|
'privileged': self.module.params.get('privileged'),
|
|
'links': self.links,
|
|
}
|
|
for i in containers:
|
|
self.client.start(i['Id'], **params)
|
|
self.increment_counter('started')
|
|
|
|
def stop_containers(self, containers):
|
|
for i in containers:
|
|
self.client.stop(i['Id'])
|
|
self.increment_counter('stopped')
|
|
|
|
return [self.client.wait(i['Id']) for i in containers]
|
|
|
|
def remove_containers(self, containers):
|
|
for i in containers:
|
|
self.client.remove_container(i['Id'])
|
|
self.increment_counter('removed')
|
|
|
|
def kill_containers(self, containers):
|
|
for i in containers:
|
|
self.client.kill(i['Id'])
|
|
self.increment_counter('killed')
|
|
|
|
def restart_containers(self, containers):
|
|
for i in containers:
|
|
self.client.restart(i['Id'])
|
|
self.increment_counter('restarted')
|
|
|
|
|
|
def check_dependencies(module):
|
|
"""
|
|
Ensure `docker-py` >= 0.3.0 is installed, and call module.fail_json with a
|
|
helpful error message if it isn't.
|
|
"""
|
|
if not HAS_DOCKER_PY:
|
|
module.fail_json(msg="`docker-py` doesn't seem to be installed, but is required for the Ansible Docker module.")
|
|
else:
|
|
HAS_NEW_ENOUGH_DOCKER_PY = False
|
|
if hasattr(docker, '__version__'):
|
|
# a '__version__' attribute was added to the module but not until
|
|
# after 0.3.0 was added pushed to pip. If it's there, use it.
|
|
if docker.__version__ >= '0.3.0':
|
|
HAS_NEW_ENOUGH_DOCKER_PY = True
|
|
else:
|
|
# HACK: if '__version__' isn't there, we check for the existence of
|
|
# `_get_raw_response_socket` in the docker.Client class, which was
|
|
# added in 0.3.0
|
|
if hasattr(docker.Client, '_get_raw_response_socket'):
|
|
HAS_NEW_ENOUGH_DOCKER_PY = True
|
|
|
|
if not HAS_NEW_ENOUGH_DOCKER_PY:
|
|
module.fail_json(msg="The Ansible Docker module requires `docker-py` >= 0.3.0.")
|
|
|
|
|
|
def main():
|
|
module = AnsibleModule(
|
|
argument_spec = dict(
|
|
count = dict(default=1),
|
|
image = dict(required=True),
|
|
command = dict(required=False, default=None),
|
|
expose = dict(required=False, default=None),
|
|
ports = dict(required=False, default=None),
|
|
publish_all_ports = dict(default=False, type='bool'),
|
|
volumes = dict(default=None),
|
|
volumes_from = dict(default=None),
|
|
links = dict(default=None),
|
|
memory_limit = dict(default=0),
|
|
memory_swap = dict(default=0),
|
|
docker_url = dict(default='unix://var/run/docker.sock'),
|
|
user = dict(default=None),
|
|
password = dict(),
|
|
email = dict(),
|
|
hostname = dict(default=None),
|
|
env = dict(),
|
|
dns = dict(),
|
|
detach = dict(default=True, type='bool'),
|
|
state = dict(default='running', choices=['absent', 'present', 'running', 'stopped', 'killed', 'restarted']),
|
|
debug = dict(default=False, type='bool'),
|
|
privileged = dict(default=False, type='bool'),
|
|
lxc_conf = dict(default=None),
|
|
name = dict(default=None)
|
|
)
|
|
)
|
|
|
|
check_dependencies(module)
|
|
|
|
try:
|
|
manager = DockerManager(module)
|
|
state = module.params.get('state')
|
|
count = int(module.params.get('count'))
|
|
name = module.params.get('name')
|
|
|
|
if count < 0:
|
|
module.fail_json(msg="Count must be greater than zero")
|
|
if count > 1 and name:
|
|
module.fail_json(msg="Count and name must not be used together")
|
|
|
|
running_containers = manager.get_running_containers()
|
|
running_count = len(running_containers)
|
|
delta = count - running_count
|
|
deployed_containers = manager.get_deployed_containers()
|
|
facts = None
|
|
failed = False
|
|
changed = False
|
|
|
|
# start/stop containers
|
|
if state in [ "running", "present" ]:
|
|
|
|
# make sure a container with `name` exists, if not create and start it
|
|
if name and "/" + name not in map(lambda x: x.get('Name'), deployed_containers):
|
|
containers = manager.create_containers(1)
|
|
if state == "present": #otherwise it get (re)started later anyways..
|
|
manager.start_containers(containers)
|
|
running_containers = manager.get_running_containers()
|
|
deployed_containers = manager.get_deployed_containers()
|
|
|
|
if state == "running":
|
|
# make sure a container with `name` is running
|
|
if name and "/" + name not in map(lambda x: x.get('Name'), running_containers):
|
|
manager.start_containers(deployed_containers)
|
|
|
|
# start more containers if we don't have enough
|
|
elif delta > 0:
|
|
containers = manager.create_containers(delta)
|
|
manager.start_containers(containers)
|
|
|
|
# stop containers if we have too many
|
|
elif delta < 0:
|
|
containers_to_stop = running_containers[0:abs(delta)]
|
|
containers = manager.stop_containers(containers_to_stop)
|
|
manager.remove_containers(containers_to_stop)
|
|
|
|
facts = manager.get_running_containers()
|
|
else:
|
|
acts = manager.get_deployed_containers()
|
|
|
|
# stop and remove containers
|
|
elif state == "absent":
|
|
facts = manager.stop_containers(deployed_containers)
|
|
manager.remove_containers(deployed_containers)
|
|
|
|
# stop containers
|
|
elif state == "stopped":
|
|
facts = manager.stop_containers(running_containers)
|
|
|
|
# kill containers
|
|
elif state == "killed":
|
|
manager.kill_containers(running_containers)
|
|
|
|
# restart containers
|
|
elif state == "restarted":
|
|
manager.restart_containers(running_containers)
|
|
facts = manager.get_inspect_containers(running_containers)
|
|
|
|
msg = "%s container(s) running image %s with command %s" % \
|
|
(manager.get_summary_counters_msg(), module.params.get('image'), module.params.get('command'))
|
|
changed = manager.has_changed()
|
|
|
|
module.exit_json(failed=failed, changed=changed, msg=msg, ansible_facts=_ansible_facts(facts))
|
|
|
|
except docker.client.APIError, e:
|
|
changed = manager.has_changed()
|
|
module.exit_json(failed=True, changed=changed, msg="Docker API error: " + e.explanation)
|
|
|
|
except RequestException, e:
|
|
changed = manager.has_changed()
|
|
module.exit_json(failed=True, changed=changed, msg=repr(e))
|
|
|
|
# import module snippets
|
|
from ansible.module_utils.basic import *
|
|
|
|
main()
|