Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ If you use the Ansible package and do not update collections independently, use
- community.docker.docker_volume_info: retrieve information on Docker volumes
* Docker Compose:
- community.docker.docker_compose_v2: manage Docker Compose files (Docker compose CLI plugin)
- community.docker.docker_compose_v2_build: build images for a Docker compose project
- community.docker.docker_compose_v2_exec: run command in a container of a Compose service
- community.docker.docker_compose_v2_pull: pull a Docker compose project
- community.docker.docker_compose_v2_run: run command in a new container of a Compose service
Expand Down
3 changes: 3 additions & 0 deletions docs/docsite/rst/scenario_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,9 @@ There are several modules for working with Docker Compose projects:
community.docker.docker_compose_v2
The :ansplugin:`community.docker.docker_compose_v2 module <community.docker.docker_compose_v2#module>` allows you to use your existing Docker Compose files to orchestrate containers on a single Docker daemon or on Swarm.

community.docker.docker_compose_v2_build
The :ansplugin:`community.docker.docker_compose_v2_pull module <community.docker.docker_compose_v2_pull#module>` allows you to build images for Docker compose projects.

community.docker.docker_compose_v2_exec
The :ansplugin:`community.docker.docker_compose_v2_exec module <community.docker.docker_compose_v2_exec#module>` allows you to run a command in a container of Docker Compose projects.

Expand Down
1 change: 1 addition & 0 deletions meta/runtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ requires_ansible: '>=2.15.0'
action_groups:
docker:
- docker_compose_v2
- docker_compose_v2_build
- docker_compose_v2_exec
- docker_compose_v2_pull
- docker_compose_v2_run
Expand Down
3 changes: 3 additions & 0 deletions plugins/modules/docker_compose_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,10 @@
- Felix Fontein (@felixfontein)

seealso:
- module: community.docker.docker_compose_v2_build
- module: community.docker.docker_compose_v2_exec
- module: community.docker.docker_compose_v2_pull
- module: community.docker.docker_compose_v2_run
"""

EXAMPLES = r"""
Expand Down
190 changes: 190 additions & 0 deletions plugins/modules/docker_compose_v2_build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
#!/usr/bin/python
#
# Copyright (c) 2023, Felix Fontein <[email protected]>
# Copyright (c) 2025, Maciej Bogusz (@mjbogusz)
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later

from __future__ import absolute_import, division, print_function
__metaclass__ = type


DOCUMENTATION = r"""
module: docker_compose_v2_build

short_description: Build a Docker compose project

version_added: 4.7.0

description:
- Uses Docker Compose to build images for a project.
extends_documentation_fragment:
- community.docker.compose_v2
- community.docker.compose_v2.minimum_version
- community.docker.docker.cli_documentation
- community.docker.attributes
- community.docker.attributes.actiongroup_docker

attributes:
check_mode:
support: full
diff_mode:
support: none
idempotent:
support: full

options:
no_cache:
description:
- If set to V(true), will not use cache when building the images.
type: bool
default: false
pull:
description:
- If set to V(true), will attempt to pull newer version of the image.
type: bool
default: false
with_dependencies:
description:
- If set to V(true), also build services that are declared as dependencies.
- This only makes sense if O(services) is used.
type: bool
default: false
memory_limit:
description:
- Memory limit for the build container, in bytes. Not supported by BuildKit.
type: int
services:
description:
- Specifies a subset of services to be targeted.
type: list
elements: str

author:
- Maciej Bogusz (@mjbogusz)

seealso:
- module: community.docker.docker_compose_v2
"""

EXAMPLES = r"""
---
- name: Build images for flask project
community.docker.docker_compose_v2_build:
project_src: /path/to/flask
"""

RETURN = r"""
actions:
description:
- A list of actions that have been applied.
returned: success
type: list
elements: dict
contains:
what:
description:
- What kind of resource was changed.
type: str
sample: container
choices:
- image
- unknown
id:
description:
- The ID of the resource that was changed.
type: str
sample: container
status:
description:
- The status change that happened.
type: str
sample: Building
choices:
- Building
"""

import traceback

from ansible.module_utils.common.text.converters import to_native

from ansible_collections.community.docker.plugins.module_utils.common_cli import (
AnsibleModuleDockerClient,
DockerException,
)

from ansible_collections.community.docker.plugins.module_utils.compose_v2 import (
BaseComposeManager,
common_compose_argspec_ex,
)


class BuildManager(BaseComposeManager):
def __init__(self, client):
super(BuildManager, self).__init__(client)
parameters = self.client.module.params

self.no_cache = parameters['no_cache']
self.pull = parameters['pull']
self.with_dependencies = parameters['with_dependencies']
self.memory_limit = parameters['memory_limit']
self.services = parameters['services'] or []

def get_build_cmd(self, dry_run):
args = self.get_base_args() + ['build']
if self.no_cache:
args.append('--no-cache')
if self.pull:
args.append('--pull')
if self.with_dependencies:
args.append('--with-dependencies')
if self.memory_limit:
args.extend(['--memory', str(self.memory_limit)])
if dry_run:
args.append('--dry-run')
args.append('--')
for service in self.services:
args.append(service)
return args

def run(self):
result = dict()
args = self.get_build_cmd(self.check_mode)
rc, stdout, stderr = self.client.call_cli(*args, cwd=self.project_src)
events = self.parse_events(stderr, dry_run=self.check_mode, nonzero_rc=rc != 0)
self.emit_warnings(events)
self.update_result(result, events, stdout, stderr, ignore_build_events=False)
self.update_failed(result, events, args, stdout, stderr, rc)
self.cleanup_result(result)
return result


def main():
argument_spec = dict(
no_cache=dict(type='bool', default=False),
pull=dict(type='bool', default=False),
with_dependencies=dict(type='bool', default=False),
memory_limit=dict(type='int'),
services=dict(type='list', elements='str'),
)
argspec_ex = common_compose_argspec_ex()
argument_spec.update(argspec_ex.pop('argspec'))

client = AnsibleModuleDockerClient(
argument_spec=argument_spec,
supports_check_mode=True,
needs_api_version=False,
**argspec_ex
)

try:
manager = BuildManager(client)
result = manager.run()
manager.cleanup()
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())


if __name__ == '__main__':
main()
6 changes: 6 additions & 0 deletions tests/integration/targets/docker_compose_v2_build/aliases
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later

azp/4
destructive
10 changes: 10 additions & 0 deletions tests/integration/targets/docker_compose_v2_build/meta/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later

dependencies:
- setup_docker_cli_compose
# The Python dependencies are needed for the other modules
- setup_docker_python_deps
- setup_remote_tmp_dir
59 changes: 59 additions & 0 deletions tests/integration/targets/docker_compose_v2_build/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later

####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################

# Create random name prefix (for services, ...)
- name: Create random container name prefix
set_fact:
name_prefix: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
cnames: []
inames: []
dnetworks: []

- debug:
msg: "Using name prefix {{ name_prefix }}"

- name: Show images
command: docker images --all --digests

# Run the tests
- block:
- name: Show docker compose --help output
command: docker compose --help

- include_tasks: run-test.yml
with_fileglob:
- "tests/*.yml"
loop_control:
loop_var: test_name

always:
- name: "Make sure all containers are removed"
docker_container:
name: "{{ item }}"
state: absent
force_kill: true
with_items: "{{ cnames }}"
diff: false

- name: "Make sure all images are removed"
docker_image_remove:
name: "{{ item }}"
with_items: "{{ inames }}"
diff: false

- name: "Make sure all networks are removed"
docker_network:
name: "{{ item }}"
state: absent
force: true
with_items: "{{ dnetworks }}"
diff: false

when: docker_has_compose and docker_compose_version is version('2.18.0', '>=')
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later

- name: "Loading tasks from {{ test_name }}"
include_tasks: "{{ test_name }}"
Loading
Loading