Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 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_ignore_build_events=not self.check_mode)
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
52 changes: 52 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,52 @@
---
# 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: []
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 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