def __init__(self):
        self.docker_client = AnsibleDockerClient(
            argument_spec=dict(label_name=dict(type='str', required=False),
                               label_value=dict(type='str', required=False)))

        self.containers = self.docker_client.containers()
        self.label_name = self.docker_client.module.params.get('label_name')
        self.label_value = self.docker_client.module.params.get('label_value')

        if self.label_name:
            self.containers_names = self._get_containers_names_by_label()
        else:
            self.containers_names = self._get_containers_names()

        self.result = dict(containers=self.containers_names, changed=False)
class DockerListContainers:
    def __init__(self):
        self.docker_client = AnsibleDockerClient(
            argument_spec=dict(label_name=dict(type='str', required=False),
                               label_value=dict(type='str', required=False)))

        self.containers = self.docker_client.containers()
        self.label_name = self.docker_client.module.params.get('label_name')
        self.label_value = self.docker_client.module.params.get('label_value')

        if self.label_name:
            self.containers_names = self._get_containers_names_by_label()
        else:
            self.containers_names = self._get_containers_names()

        self.result = dict(containers=self.containers_names, changed=False)

    def _get_containers_names(self):
        return [
            str(container_meta.get('Names')[0][1:])
            for container_meta in self.containers if 'Names' in container_meta
        ]

    def _get_containers_names_by_label(self):
        names = []
        for container_meta in self.containers:
            if container_meta.get('Labels',
                                  {}).get(self.label_name) == self.label_value:
                names.append(
                    str(container_meta['Names'][0][1:])
                )  # strip leading '/' in container name and convert to str from unicode

        return names
Exemplo n.º 3
0
def main():
    argument_spec = dict(name=dict(type='str', required=True), )

    client = AnsibleDockerClient(
        argument_spec=argument_spec,
        supports_check_mode=True,
        min_docker_api_version='1.21',
    )

    try:
        network = client.get_network(client.module.params['name'])

        client.module.exit_json(
            changed=False,
            exists=(True if network else False),
            network=network,
        )
    except DockerException as e:
        client.fail('An unexpected docker error occurred: {0}'.format(
            to_native(e)),
                    exception=traceback.format_exc())
    except RequestException as e:
        client.fail(
            'An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'
            .format(to_native(e)),
            exception=traceback.format_exc())
def main():
    argument_spec = dict(
        alias=dict(type='str'),
        plugin_name=dict(type='str', required=True),
        state=dict(type='str', default='present', choices=['present', 'absent', 'enable', 'disable']),
        plugin_options=dict(type='dict', default={}),
        debug=dict(type='bool', default=False),
        force_remove=dict(type='bool', default=False),
        enable_timeout=dict(type='int', default=0),
    )
    client = AnsibleDockerClient(
        argument_spec=argument_spec,
        supports_check_mode=True,
        min_docker_version='2.6.0',
        min_docker_api_version='1.25',
    )

    try:
        cm = DockerPluginManager(client)
        client.module.exit_json(**cm.result)
    except DockerException as e:
        client.fail('An unexpected docker error occurred: {0}'.format(to_native(e)), exception=traceback.format_exc())
    except RequestException as e:
        client.fail(
            'An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(to_native(e)),
            exception=traceback.format_exc())
def main():
    argument_spec = dict(name=dict(type='str',
                                   required=True,
                                   aliases=['volume_name']), )

    client = AnsibleDockerClient(
        argument_spec=argument_spec,
        supports_check_mode=True,
        min_docker_version='1.8.0',
        min_docker_api_version='1.21',
    )

    try:
        volume = get_existing_volume(client, client.module.params['name'])

        client.module.exit_json(
            changed=False,
            exists=(True if volume else False),
            volume=volume,
        )
    except DockerException as e:
        client.fail('An unexpected docker error occurred: {0}'.format(e),
                    exception=traceback.format_exc())
    except RequestException as e:
        client.fail(
            'An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'
            .format(e),
            exception=traceback.format_exc())
Exemplo n.º 6
0
def main():
    argument_spec = dict(
        name=dict(type='list', elements='str'),
    )

    client = AnsibleDockerClient(
        argument_spec=argument_spec,
        supports_check_mode=True,
        min_docker_api_version='1.20',
    )

    try:
        results = dict(
            changed=False,
            images=[]
        )

        ImageManager(client, results)
        client.module.exit_json(**results)
    except DockerException as e:
        client.fail('An unexpected docker error occurred: {0}'.format(to_native(e)), exception=traceback.format_exc())
    except RequestException as e:
        client.fail(
            'An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(to_native(e)),
            exception=traceback.format_exc())
def main():
    argument_spec = dict(name=dict(type='str', required=True),
                         state=dict(type='str',
                                    default='present',
                                    choices=['absent', 'present']),
                         data=dict(type='str'),
                         data_is_b64=dict(type='bool', default=False),
                         labels=dict(type='dict'),
                         force=dict(type='bool', default=False))

    required_if = [('state', 'present', ['data'])]

    client = AnsibleDockerClient(
        argument_spec=argument_spec,
        supports_check_mode=True,
        required_if=required_if,
        min_docker_version='2.6.0',
        min_docker_api_version='1.30',
    )

    try:
        results = dict(changed=False, )

        ConfigManager(client, results)()
        client.module.exit_json(**results)
    except DockerException as e:
        client.fail('An unexpected docker error occurred: {0}'.format(
            to_native(e)),
                    exception=traceback.format_exc())
    except RequestException as e:
        client.fail(
            'An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'
            .format(to_native(e)),
            exception=traceback.format_exc())
Exemplo n.º 8
0
def main():
    client = AnsibleDockerClient(
        argument_spec=dict(path=dict(type='path', required=True), ),
        supports_check_mode=False,
        min_docker_version='2.5.0',
        min_docker_api_version='1.23',
    )

    try:
        results = dict(
            image_names=[],
            images=[],
        )

        ImageManager(client, results)
        client.module.exit_json(**results)
    except DockerException as e:
        client.fail('An unexpected docker error occurred: {0}'.format(
            to_native(e)),
                    exception=traceback.format_exc())
    except RequestException as e:
        client.fail(
            'An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'
            .format(to_native(e)),
            exception=traceback.format_exc())
Exemplo n.º 9
0
def main():
    argument_spec = dict(
        volume_name=dict(type='str', required=True, aliases=['name']),
        state=dict(type='str', default='present', choices=['present', 'absent']),
        driver=dict(type='str', default='local'),
        driver_options=dict(type='dict', default={}),
        labels=dict(type='dict'),
        recreate=dict(type='str', default='never', choices=['always', 'never', 'options-changed']),
        debug=dict(type='bool', default=False)
    )

    option_minimal_versions = dict(
        labels=dict(docker_py_version='1.10.0', docker_api_version='1.23'),
    )

    client = AnsibleDockerClient(
        argument_spec=argument_spec,
        supports_check_mode=True,
        min_docker_version='1.10.0',
        min_docker_api_version='1.21',
        # "The docker server >= 1.9.0"
        option_minimal_versions=option_minimal_versions,
    )

    try:
        cm = DockerVolumeManager(client)
        client.module.exit_json(**cm.results)
    except DockerException as e:
        client.fail('An unexpected docker error occurred: {0}'.format(to_native(e)), exception=traceback.format_exc())
    except RequestException as e:
        client.fail(
            'An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(to_native(e)),
            exception=traceback.format_exc())
Exemplo n.º 10
0
def main():
    argument_spec = dict(
        name=dict(type='str', required=True, aliases=['network_name']),
        connected=dict(type='list',
                       default=[],
                       elements='str',
                       aliases=['containers']),
        state=dict(type='str',
                   default='present',
                   choices=['present', 'absent']),
        driver=dict(type='str', default='bridge'),
        driver_options=dict(type='dict', default={}),
        force=dict(type='bool', default=False),
        appends=dict(type='bool', default=False, aliases=['incremental']),
        ipam_driver=dict(type='str'),
        ipam_driver_options=dict(type='dict'),
        ipam_config=dict(type='list',
                         elements='dict',
                         options=dict(
                             subnet=dict(type='str'),
                             iprange=dict(type='str'),
                             gateway=dict(type='str'),
                             aux_addresses=dict(type='dict'),
                         )),
        enable_ipv6=dict(type='bool'),
        internal=dict(type='bool'),
        labels=dict(type='dict', default={}),
        debug=dict(type='bool', default=False),
        scope=dict(type='str', choices=['local', 'global', 'swarm']),
        attachable=dict(type='bool'),
    )

    option_minimal_versions = dict(
        scope=dict(docker_py_version='2.6.0', docker_api_version='1.30'),
        attachable=dict(docker_py_version='2.0.0', docker_api_version='1.26'),
        labels=dict(docker_api_version='1.23'),
        ipam_driver_options=dict(docker_py_version='2.0.0'),
    )

    client = AnsibleDockerClient(
        argument_spec=argument_spec,
        supports_check_mode=True,
        min_docker_version='1.10.0',
        min_docker_api_version='1.22',
        # "The docker server >= 1.10.0"
        option_minimal_versions=option_minimal_versions,
    )

    try:
        cm = DockerNetworkManager(client)
        client.module.exit_json(**cm.results)
    except DockerException as e:
        client.fail('An unexpected docker error occurred: {0}'.format(
            to_native(e)),
                    exception=traceback.format_exc())
    except RequestException as e:
        client.fail(
            'An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'
            .format(to_native(e)),
            exception=traceback.format_exc())
Exemplo n.º 11
0
def main():
    argument_spec = dict(
        name=dict(type='str', required=True),
        state=dict(type='str',
                   default='present',
                   choices=['absent', 'present']),
        data=dict(type='str'),
        data_is_b64=dict(type='bool', default=False),
        data_src=dict(type='path'),
        labels=dict(type='dict'),
        force=dict(type='bool', default=False),
        rolling_versions=dict(type='bool', default=False),
        versions_to_keep=dict(type='int', default=5),
        template_driver=dict(type='str', choices=['golang']),
    )

    required_if = [
        ('state', 'present', ['data', 'data_src'], True),
    ]

    mutually_exclusive = [
        ('data', 'data_src'),
    ]

    option_minimal_versions = dict(template_driver=dict(
        docker_py_version='5.0.3', docker_api_version='1.37'), )

    client = AnsibleDockerClient(
        argument_spec=argument_spec,
        supports_check_mode=True,
        required_if=required_if,
        mutually_exclusive=mutually_exclusive,
        min_docker_version='2.6.0',
        min_docker_api_version='1.30',
        option_minimal_versions=option_minimal_versions,
    )

    try:
        results = dict(changed=False, )

        ConfigManager(client, results)()
        client.module.exit_json(**results)
    except DockerException as e:
        client.fail('An unexpected docker error occurred: {0}'.format(
            to_native(e)),
                    exception=traceback.format_exc())
    except RequestException as e:
        client.fail(
            'An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'
            .format(to_native(e)),
            exception=traceback.format_exc())
Exemplo n.º 12
0
def main():

    argument_spec = dict(
        registry_url=dict(type='str',
                          default=DEFAULT_DOCKER_REGISTRY,
                          aliases=['registry', 'url']),
        username=dict(type='str'),
        password=dict(type='str', no_log=True),
        # Was Ansible 2.14 / community.general 3.0.0:
        email=dict(type='str',
                   removed_in_version='2.0.0',
                   removed_from_collection='community.docker'),
        reauthorize=dict(type='bool', default=False, aliases=['reauth']),
        state=dict(type='str',
                   default='present',
                   choices=['present', 'absent']),
        config_path=dict(type='path',
                         default='~/.docker/config.json',
                         aliases=['dockercfg_path']),
    )

    required_if = [
        ('state', 'present', ['username', 'password']),
    ]

    client = AnsibleDockerClient(
        argument_spec=argument_spec,
        supports_check_mode=True,
        required_if=required_if,
        min_docker_api_version='1.20',
    )

    try:
        results = dict(changed=False, actions=[], login_result={})

        manager = LoginManager(client, results)
        manager.run()

        if 'actions' in results:
            del results['actions']
        client.module.exit_json(**results)
    except DockerException as e:
        client.fail('An unexpected docker error occurred: {0}'.format(e),
                    exception=traceback.format_exc())
    except RequestException as e:
        client.fail(
            'An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'
            .format(e),
            exception=traceback.format_exc())
Exemplo n.º 13
0
def main():
    argument_spec = dict(project_src=dict(type='path'),
                         project_name=dict(type='str', ),
                         files=dict(type='list', elements='path'),
                         state=dict(type='str',
                                    default='present',
                                    choices=['absent', 'present']),
                         definition=dict(type='dict'),
                         hostname_check=dict(type='bool', default=False),
                         recreate=dict(type='str',
                                       default='smart',
                                       choices=['always', 'never', 'smart']),
                         build=dict(type='bool', default=False),
                         remove_images=dict(type='str',
                                            choices=['all', 'local']),
                         remove_volumes=dict(type='bool', default=False),
                         remove_orphans=dict(type='bool', default=False),
                         stopped=dict(type='bool', default=False),
                         restarted=dict(type='bool', default=False),
                         scale=dict(type='dict'),
                         services=dict(type='list', elements='str'),
                         dependencies=dict(type='bool', default=True),
                         pull=dict(type='bool', default=False),
                         nocache=dict(type='bool', default=False),
                         debug=dict(type='bool', default=False),
                         timeout=dict(type='int', default=DEFAULT_TIMEOUT))

    mutually_exclusive = [('definition', 'project_src'),
                          ('definition', 'files')]

    client = AnsibleDockerClient(
        argument_spec=argument_spec,
        mutually_exclusive=mutually_exclusive,
        supports_check_mode=True,
        min_docker_api_version='1.20',
    )

    try:
        result = ContainerManager(client).exec_module()
        client.module.exit_json(**result)
    except DockerException as e:
        client.fail('An unexpected docker error occurred: {0}'.format(
            to_native(e)),
                    exception=traceback.format_exc())
    except RequestException as e:
        client.fail(
            'An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'
            .format(to_native(e)),
            exception=traceback.format_exc())
Exemplo n.º 14
0
def main():
    argument_spec = dict(
        containers=dict(type='bool', default=False),
        containers_filters=dict(type='dict'),
        images=dict(type='bool', default=False),
        images_filters=dict(type='dict'),
        networks=dict(type='bool', default=False),
        networks_filters=dict(type='dict'),
        volumes=dict(type='bool', default=False),
        volumes_filters=dict(type='dict'),
        disk_usage=dict(type='bool', default=False),
        verbose_output=dict(type='bool', default=False),
    )

    option_minimal_versions = dict(
        network_filters=dict(docker_py_version='2.0.2'),
        disk_usage=dict(docker_py_version='2.2.0'),
    )

    client = AnsibleDockerClient(
        argument_spec=argument_spec,
        supports_check_mode=True,
        min_docker_version='1.10.0',
        min_docker_api_version='1.21',
        option_minimal_versions=option_minimal_versions,
        fail_results=dict(can_talk_to_docker=False, ),
    )
    client.fail_results['can_talk_to_docker'] = True

    try:
        results = dict(changed=False, )

        DockerHostManager(client, results)
        client.module.exit_json(**results)
    except DockerException as e:
        client.fail('An unexpected docker error occurred: {0}'.format(
            to_native(e)),
                    exception=traceback.format_exc())
    except RequestException as e:
        client.fail(
            'An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'
            .format(to_native(e)),
            exception=traceback.format_exc())
Exemplo n.º 15
0
def main():
    argument_spec = dict(
        containers=dict(type='bool', default=False),
        containers_filters=dict(type='dict'),
        images=dict(type='bool', default=False),
        images_filters=dict(type='dict'),
        networks=dict(type='bool', default=False),
        networks_filters=dict(type='dict'),
        volumes=dict(type='bool', default=False),
        volumes_filters=dict(type='dict'),
        builder_cache=dict(type='bool', default=False),
    )

    client = AnsibleDockerClient(
        argument_spec=argument_spec,
        # supports_check_mode=True,
        min_docker_api_version='1.25',
        min_docker_version='2.1.0',
    )

    # Version checks
    cache_min_version = '3.3.0'
    if client.module.params[
            'builder_cache'] and client.docker_py_version < LooseVersion(
                cache_min_version):
        msg = "Error: Docker SDK for Python's version is %s. Minimum version required for builds option is %s. Use `pip install --upgrade docker` to upgrade."
        client.fail(msg % (docker_version, cache_min_version))

    try:
        result = dict()

        if client.module.params['containers']:
            filters = clean_dict_booleans_for_docker_api(
                client.module.params.get('containers_filters'))
            res = client.prune_containers(filters=filters)
            result['containers'] = res.get('ContainersDeleted') or []
            result['containers_space_reclaimed'] = res['SpaceReclaimed']

        if client.module.params['images']:
            filters = clean_dict_booleans_for_docker_api(
                client.module.params.get('images_filters'))
            res = client.prune_images(filters=filters)
            result['images'] = res.get('ImagesDeleted') or []
            result['images_space_reclaimed'] = res['SpaceReclaimed']

        if client.module.params['networks']:
            filters = clean_dict_booleans_for_docker_api(
                client.module.params.get('networks_filters'))
            res = client.prune_networks(filters=filters)
            result['networks'] = res.get('NetworksDeleted') or []

        if client.module.params['volumes']:
            filters = clean_dict_booleans_for_docker_api(
                client.module.params.get('volumes_filters'))
            res = client.prune_volumes(filters=filters)
            result['volumes'] = res.get('VolumesDeleted') or []
            result['volumes_space_reclaimed'] = res['SpaceReclaimed']

        if client.module.params['builder_cache']:
            res = client.prune_builds()
            result['builder_cache_space_reclaimed'] = res['SpaceReclaimed']

        client.module.exit_json(**result)
    except DockerException as e:
        client.fail('An unexpected docker error occurred: {0}'.format(
            to_native(e)),
                    exception=traceback.format_exc())
    except RequestException as e:
        client.fail(
            'An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'
            .format(to_native(e)),
            exception=traceback.format_exc())
Exemplo n.º 16
0
def main():
    argument_spec = dict(
        container=dict(type='str', required=True),
        argv=dict(type='list', elements='str'),
        command=dict(type='str'),
        chdir=dict(type='str'),
        user=dict(type='str'),
        stdin=dict(type='str'),
        stdin_add_newline=dict(type='bool', default=True),
        strip_empty_ends=dict(type='bool', default=True),
        tty=dict(type='bool', default=False),
    )

    client = AnsibleDockerClient(
        argument_spec=argument_spec,
        min_docker_api_version='1.20',
        mutually_exclusive=[('argv', 'command')],
        required_one_of=[('argv', 'command')],
    )

    container = client.module.params['container']
    argv = client.module.params['argv']
    command = client.module.params['command']
    chdir = client.module.params['chdir']
    user = client.module.params['user']
    stdin = client.module.params['stdin']
    strip_empty_ends = client.module.params['strip_empty_ends']
    tty = client.module.params['tty']

    if command is not None:
        argv = shlex.split(command)

    if stdin is not None and client.module.params['stdin_add_newline']:
        stdin += '\n'

    selectors = None
    if stdin:
        selectors = find_selectors(client.module)

    try:
        exec_data = client.exec_create(
            container,
            argv,
            stdout=True,
            stderr=True,
            stdin=bool(stdin),
            user=user or '',
            workdir=chdir,
        )
        exec_id = exec_data['Id']

        if selectors:
            exec_socket = client.exec_start(
                exec_id,
                tty=tty,
                detach=False,
                socket=True,
            )
            try:
                with DockerSocketHandlerModule(
                        exec_socket, client.module,
                        selectors) as exec_socket_handler:
                    if stdin:
                        exec_socket_handler.write(to_bytes(stdin))

                    stdout, stderr = exec_socket_handler.consume()
            finally:
                exec_socket.close()
        else:
            stdout, stderr = client.exec_start(
                exec_id,
                tty=tty,
                detach=False,
                stream=False,
                socket=False,
                demux=True,
            )

        result = client.exec_inspect(exec_id)

        stdout = to_text(stdout or b'')
        stderr = to_text(stderr or b'')
        if strip_empty_ends:
            stdout = stdout.rstrip('\r\n')
            stderr = stderr.rstrip('\r\n')

        client.module.exit_json(
            changed=True,
            stdout=stdout,
            stderr=stderr,
            rc=result.get('ExitCode') or 0,
        )
    except NotFound:
        client.fail('Could not find container "{0}"'.format(container))
    except APIError as e:
        if e.response and e.response.status_code == 409:
            client.fail('The container "{0}" has been paused ({1})'.format(
                container, to_native(e)))
        client.fail('An unexpected docker error occurred: {0}'.format(
            to_native(e)),
                    exception=traceback.format_exc())
    except DockerException as e:
        client.fail('An unexpected docker error occurred: {0}'.format(
            to_native(e)),
                    exception=traceback.format_exc())
    except RequestException as e:
        client.fail(
            'An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'
            .format(to_native(e)),
            exception=traceback.format_exc())
def main():
    argument_spec = dict(
        container=dict(type='str', required=True),
        argv=dict(type='list', elements='str'),
        command=dict(type='str'),
        chdir=dict(type='str'),
        detach=dict(type='bool', default=False),
        user=dict(type='str'),
        stdin=dict(type='str'),
        stdin_add_newline=dict(type='bool', default=True),
        strip_empty_ends=dict(type='bool', default=True),
        tty=dict(type='bool', default=False),
        env=dict(type='dict'),
    )

    option_minimal_versions = dict(
        chdir=dict(docker_py_version='3.0.0', docker_api_version='1.35'),
        env=dict(docker_py_version='2.3.0', docker_api_version='1.25'),
    )

    client = AnsibleDockerClient(
        argument_spec=argument_spec,
        option_minimal_versions=option_minimal_versions,
        min_docker_api_version='1.20',
        mutually_exclusive=[('argv', 'command')],
        required_one_of=[('argv', 'command')],
    )

    container = client.module.params['container']
    argv = client.module.params['argv']
    command = client.module.params['command']
    chdir = client.module.params['chdir']
    detach = client.module.params['detach']
    user = client.module.params['user']
    stdin = client.module.params['stdin']
    strip_empty_ends = client.module.params['strip_empty_ends']
    tty = client.module.params['tty']
    env = client.module.params['env']

    if env is not None:
        for name, value in list(env.items()):
            if not isinstance(value, string_types):
                client.module.fail_json(
                    msg=
                    "Non-string value found for env option. Ambiguous env options must be "
                    "wrapped in quotes to avoid them being interpreted. Key: %s"
                    % (name, ))
            env[name] = to_text(value, errors='surrogate_or_strict')

    if command is not None:
        argv = shlex.split(command)

    if detach and stdin is not None:
        client.module.fail_json(
            msg='If detach=true, stdin cannot be provided.')

    if stdin is not None and client.module.params['stdin_add_newline']:
        stdin += '\n'

    selectors = None
    if stdin and not detach:
        selectors = find_selectors(client.module)

    try:
        kwargs = {}
        if chdir is not None:
            kwargs['workdir'] = chdir
        if env is not None:
            kwargs['environment'] = env
        exec_data = client.exec_create(container,
                                       argv,
                                       stdout=True,
                                       stderr=True,
                                       stdin=bool(stdin),
                                       user=user or '',
                                       **kwargs)
        exec_id = exec_data['Id']

        if detach:
            client.exec_start(exec_id, tty=tty, detach=True)
            client.module.exit_json(changed=True, exec_id=exec_id)

        else:
            if selectors:
                exec_socket = client.exec_start(
                    exec_id,
                    tty=tty,
                    detach=False,
                    socket=True,
                )
                try:
                    with DockerSocketHandlerModule(
                            exec_socket, client.module,
                            selectors) as exec_socket_handler:
                        if stdin:
                            exec_socket_handler.write(to_bytes(stdin))

                        stdout, stderr = exec_socket_handler.consume()
                finally:
                    exec_socket.close()
            else:
                stdout, stderr = client.exec_start(
                    exec_id,
                    tty=tty,
                    detach=False,
                    stream=False,
                    socket=False,
                    demux=True,
                )

            result = client.exec_inspect(exec_id)

            stdout = to_text(stdout or b'')
            stderr = to_text(stderr or b'')
            if strip_empty_ends:
                stdout = stdout.rstrip('\r\n')
                stderr = stderr.rstrip('\r\n')

            client.module.exit_json(
                changed=True,
                stdout=stdout,
                stderr=stderr,
                rc=result.get('ExitCode') or 0,
            )
    except NotFound:
        client.fail('Could not find container "{0}"'.format(container))
    except APIError as e:
        if e.response and e.response.status_code == 409:
            client.fail('The container "{0}" has been paused ({1})'.format(
                container, to_native(e)))
        client.fail('An unexpected docker error occurred: {0}'.format(
            to_native(e)),
                    exception=traceback.format_exc())
    except DockerException as e:
        client.fail('An unexpected docker error occurred: {0}'.format(
            to_native(e)),
                    exception=traceback.format_exc())
    except RequestException as e:
        client.fail(
            'An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'
            .format(to_native(e)),
            exception=traceback.format_exc())
def main():
    argument_spec = dict(
        source=dict(type='str', choices=['build', 'load', 'pull', 'local']),
        build=dict(type='dict',
                   options=dict(
                       cache_from=dict(type='list', elements='str'),
                       container_limits=dict(type='dict',
                                             options=dict(
                                                 memory=dict(type='int'),
                                                 memswap=dict(type='int'),
                                                 cpushares=dict(type='int'),
                                                 cpusetcpus=dict(type='str'),
                                             )),
                       dockerfile=dict(type='str'),
                       http_timeout=dict(type='int'),
                       network=dict(type='str'),
                       nocache=dict(type='bool', default=False),
                       path=dict(type='path', required=True),
                       pull=dict(type='bool', default=False),
                       rm=dict(type='bool', default=True),
                       args=dict(type='dict'),
                       use_config_proxy=dict(type='bool'),
                       target=dict(type='str'),
                       etc_hosts=dict(type='dict'),
                       platform=dict(type='str'),
                   )),
        archive_path=dict(type='path'),
        force_source=dict(type='bool', default=False),
        force_absent=dict(type='bool', default=False),
        force_tag=dict(type='bool', default=False),
        load_path=dict(type='path'),
        name=dict(type='str', required=True),
        push=dict(type='bool', default=False),
        repository=dict(type='str'),
        state=dict(type='str',
                   default='present',
                   choices=['absent', 'present']),
        tag=dict(type='str', default='latest'),
    )

    required_if = [
        ('state', 'present', ['source']),
        ('source', 'build', ['build']),
        ('source', 'load', ['load_path']),
    ]

    def detect_build_cache_from(client):
        return client.module.params['build'] and client.module.params[
            'build'].get('cache_from') is not None

    def detect_build_network(client):
        return client.module.params['build'] and client.module.params[
            'build'].get('network') is not None

    def detect_build_target(client):
        return client.module.params['build'] and client.module.params[
            'build'].get('target') is not None

    def detect_use_config_proxy(client):
        return client.module.params['build'] and client.module.params[
            'build'].get('use_config_proxy') is not None

    def detect_etc_hosts(client):
        return client.module.params['build'] and bool(
            client.module.params['build'].get('etc_hosts'))

    def detect_platform(client):
        return client.module.params['build'] and client.module.params[
            'build'].get('platform') is not None

    option_minimal_versions = dict()
    option_minimal_versions["build.cache_from"] = dict(
        docker_py_version='2.1.0',
        docker_api_version='1.25',
        detect_usage=detect_build_cache_from)
    option_minimal_versions["build.network"] = dict(
        docker_py_version='2.4.0',
        docker_api_version='1.25',
        detect_usage=detect_build_network)
    option_minimal_versions["build.target"] = dict(
        docker_py_version='2.4.0', detect_usage=detect_build_target)
    option_minimal_versions["build.use_config_proxy"] = dict(
        docker_py_version='3.7.0', detect_usage=detect_use_config_proxy)
    option_minimal_versions["build.etc_hosts"] = dict(
        docker_py_version='2.6.0',
        docker_api_version='1.27',
        detect_usage=detect_etc_hosts)
    option_minimal_versions["build.platform"] = dict(
        docker_py_version='3.0.0',
        docker_api_version='1.32',
        detect_usage=detect_platform)

    client = AnsibleDockerClient(
        argument_spec=argument_spec,
        required_if=required_if,
        supports_check_mode=True,
        min_docker_version='1.8.0',
        min_docker_api_version='1.20',
        option_minimal_versions=option_minimal_versions,
    )

    if not is_valid_tag(client.module.params['tag'], allow_empty=True):
        client.fail('"{0}" is not a valid docker tag!'.format(
            client.module.params['tag']))

    if client.module.params['source'] == 'build':
        if not client.module.params['build'] or not client.module.params[
                'build'].get('path'):
            client.fail(
                'If "source" is set to "build", the "build.path" option must be specified.'
            )

    try:
        results = dict(changed=False, actions=[], image={})

        ImageManager(client, results)
        client.module.exit_json(**results)
    except DockerException as e:
        client.fail('An unexpected docker error occurred: {0}'.format(e),
                    exception=traceback.format_exc())
    except RequestException as e:
        client.fail(
            'An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'
            .format(e),
            exception=traceback.format_exc())