Skip to content
Merged
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
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
## [2.2.5] - 2025-12-26

### Added
- **Docker module**: Network management targets
- `docker/network/create/<name>` - Create a network (fails if exists)
- `docker/network/ensure/<name>` - Create network if it doesn't exist (idempotent)
- `docker/network/remove/<name>` - Remove a network (fails if doesn't exist)
- Flexible configuration via target parameters or variables:
- Target format: `<name>[@driver][@subnet][@gateway]`
- Variable format: `docker_network_<name>_driver`, `docker_network_<name>_subnet`, `docker_network_<name>_gateway`
- `docker_network_ignore_errors` variable to suppress errors silently
- `dk_network_default_driver` config (default: bridge)
- Helper functions: `dk_network_parse_params`, `dk_network_create`, `dk_network_remove`

## [2.2.4] - 2025-12-15

### Added
Expand Down
109 changes: 109 additions & 0 deletions modules/containers/docker/docker_test.mk
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,113 @@ define test_modules_docker_config_defaults
$(call mb_assert_eq,/bin/sh,$(dk_shell_default),dk_shell_default should be /bin/sh)
$(call mb_assert_eq,-it,$(dk_exec_default_tty),dk_exec_default_tty should be -it)
$(call mb_assert_eq,--tail=200,$(dk_logs_default_opts),dk_logs_default_opts should be --tail=200)
$(call mb_assert_eq,bridge,$(dk_network_default_driver),dk_network_default_driver should be bridge)
endef

######################################################################################
# dk_network_parse_params tests
######################################################################################

define test_modules_docker_dk_network_parse_params_name_only
## Test with name only (no @)
$(call dk_network_parse_params,mynetwork)
$(call mb_assert_eq,mynetwork,$(dk_network_parse_params_name),name should be mynetwork)
$(call mb_assert_eq,bridge,$(dk_network_parse_params_driver),driver should default to bridge)
$(call mb_assert_empty,$(dk_network_parse_params_subnet),subnet should be empty)
$(call mb_assert_empty,$(dk_network_parse_params_gateway),gateway should be empty)
endef

define test_modules_docker_dk_network_parse_params_with_driver
## Test with name and driver
$(call dk_network_parse_params,mynetwork@overlay)
$(call mb_assert_eq,mynetwork,$(dk_network_parse_params_name),name should be mynetwork)
$(call mb_assert_eq,overlay,$(dk_network_parse_params_driver),driver should be overlay)
$(call mb_assert_empty,$(dk_network_parse_params_subnet),subnet should be empty)
$(call mb_assert_empty,$(dk_network_parse_params_gateway),gateway should be empty)
endef

define test_modules_docker_dk_network_parse_params_full
## Test with all parameters
$(call dk_network_parse_params,mynetwork@bridge@172.20.0.0/16@172.20.0.1)
$(call mb_assert_eq,mynetwork,$(dk_network_parse_params_name),name should be mynetwork)
$(call mb_assert_eq,bridge,$(dk_network_parse_params_driver),driver should be bridge)
$(call mb_assert_eq,172.20.0.0/16,$(dk_network_parse_params_subnet),subnet should be 172.20.0.0/16)
$(call mb_assert_eq,172.20.0.1,$(dk_network_parse_params_gateway),gateway should be 172.20.0.1)
endef

define test_modules_docker_dk_network_parse_params_from_variables
## Test resolution from variables when no target params
$(eval docker_network_testnet_driver := overlay)
$(eval docker_network_testnet_subnet := 10.0.0.0/24)
$(eval docker_network_testnet_gateway := 10.0.0.1)

$(call dk_network_parse_params,testnet)
$(call mb_assert_eq,testnet,$(dk_network_parse_params_name),name should be testnet)
$(call mb_assert_eq,overlay,$(dk_network_parse_params_driver),driver should come from variable)
$(call mb_assert_eq,10.0.0.0/24,$(dk_network_parse_params_subnet),subnet should come from variable)
$(call mb_assert_eq,10.0.0.1,$(dk_network_parse_params_gateway),gateway should come from variable)

## Cleanup
$(eval docker_network_testnet_driver :=)
$(eval docker_network_testnet_subnet :=)
$(eval docker_network_testnet_gateway :=)
endef

define test_modules_docker_dk_network_parse_params_target_overrides_variable
## Test that target params override variables
$(eval docker_network_mynet_driver := host)
$(eval docker_network_mynet_subnet := 192.168.0.0/24)

$(call dk_network_parse_params,mynet@overlay@10.0.0.0/8)
$(call mb_assert_eq,overlay,$(dk_network_parse_params_driver),target param should override variable)
$(call mb_assert_eq,10.0.0.0/8,$(dk_network_parse_params_subnet),target param should override variable)

## Cleanup
$(eval docker_network_mynet_driver :=)
$(eval docker_network_mynet_subnet :=)
endef

######################################################################################
# dk_network_create tests
######################################################################################

define test_modules_docker_dk_network_create_basic
$(eval mb_invoke_silent := $(mb_on))

## Test basic create with defaults
$(eval $0_result := $(call dk_network_create,mynetwork))
$(call mb_assert_eq,docker network create --driver bridge mynetwork;,$($0_result))

$(eval mb_invoke_silent := $(mb_off))
endef

define test_modules_docker_dk_network_create_with_driver
$(eval mb_invoke_silent := $(mb_on))

$(eval $0_result := $(call dk_network_create,mynetwork,overlay))
$(call mb_assert_eq,docker network create --driver overlay mynetwork;,$($0_result))

$(eval mb_invoke_silent := $(mb_off))
endef

define test_modules_docker_dk_network_create_full
$(eval mb_invoke_silent := $(mb_on))

$(eval $0_result := $(call dk_network_create,mynetwork,bridge,172.20.0.0/16,172.20.0.1))
$(call mb_assert_eq,docker network create --driver bridge --subnet 172.20.0.0/16 --gateway 172.20.0.1 mynetwork;,$($0_result))

$(eval mb_invoke_silent := $(mb_off))
endef

######################################################################################
# dk_network_remove tests
######################################################################################

define test_modules_docker_dk_network_remove
$(eval mb_invoke_silent := $(mb_on))

$(eval $0_result := $(call dk_network_remove,mynetwork))
$(call mb_assert_eq,docker network rm mynetwork;,$($0_result))

$(eval mb_invoke_silent := $(mb_off))
endef
77 changes: 77 additions & 0 deletions modules/containers/docker/functions.mk
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,83 @@ $(strip
)
endef

######################################################################################
# Network Functions
######################################################################################

## @function dk_network_parse_params
## @desc Parse network target parameters from format: name[@driver][@subnet][@gateway]
## @desc Resolution order: target param > variable docker_network_<name>_<setting> > default
## @arg 1: params (required) - Params string, e.g., "mynet" or "mynet@overlay@172.20.0.0/16@172.20.0.1"
## @sets dk_network_parse_params_name - Network name
## @sets dk_network_parse_params_driver - Network driver (resolved)
## @sets dk_network_parse_params_subnet - Network subnet (resolved)
## @sets dk_network_parse_params_gateway - Network gateway (resolved)
## @example $(call dk_network_parse_params,mynet@overlay)
## @example Access: $(dk_network_parse_params_name), $(dk_network_parse_params_driver), etc.
define dk_network_parse_params
$(strip
$(eval $0_arg1_params := $(if $(value 1),$(strip $1),$(call mb_printf_error,$0: params string required)))

$(if $(findstring @,$($0_arg1_params)),\
$(eval $0_parts := $(subst @, ,$($0_arg1_params)))\
$(eval $0_name := $(word 1,$($0_parts)))\
$(eval $0_param_driver := $(word 2,$($0_parts)))\
$(eval $0_param_subnet := $(word 3,$($0_parts)))\
$(eval $0_param_gateway := $(word 4,$($0_parts)))\
,\
$(eval $0_name := $($0_arg1_params))\
$(eval $0_param_driver :=)\
$(eval $0_param_subnet :=)\
$(eval $0_param_gateway :=)\
)

$(eval $0_driver := $(strip \
$(if $($0_param_driver),$($0_param_driver),\
$(if $(value docker_network_$($0_name)_driver),$(docker_network_$($0_name)_driver),\
$(dk_network_default_driver)))))

$(eval $0_subnet := $(strip \
$(if $($0_param_subnet),$($0_param_subnet),\
$(if $(value docker_network_$($0_name)_subnet),$(docker_network_$($0_name)_subnet),))))

$(eval $0_gateway := $(strip \
$(if $($0_param_gateway),$($0_param_gateway),\
$(if $(value docker_network_$($0_name)_gateway),$(docker_network_$($0_name)_gateway),))))
)
endef

## @function dk_network_create
## @desc Create a docker network with optional driver, subnet, and gateway
## @arg 1: name (required) - Network name
## @arg 2: driver (optional) - Network driver (default: bridge)
## @arg 3: subnet (optional) - Network subnet in CIDR notation, e.g., 172.20.0.0/16
## @arg 4: gateway (optional) - Network gateway IP, e.g., 172.20.0.1
define dk_network_create
$(strip
$(eval $0_arg1_name := $(if $(value 1),$(strip $1),$(call mb_printf_error,$0: network name required)))
$(eval $0_arg2_driver := $(if $(value 2),$(strip $2),bridge))
$(eval $0_arg3_subnet := $(if $(value 3),$(strip $3)))
$(eval $0_arg4_gateway := $(if $(value 4),$(strip $4)))

$(eval $0_opts := --driver $($0_arg2_driver))
$(if $($0_arg3_subnet),$(eval $0_opts += --subnet $($0_arg3_subnet)))
$(if $($0_arg4_gateway),$(eval $0_opts += --gateway $($0_arg4_gateway)))

$(call dk_invoke,network create,$($0_opts),$($0_arg1_name))
)
endef

## @function dk_network_remove
## @desc Remove a docker network
## @arg 1: name (required) - Network name to remove
define dk_network_remove
$(strip
$(eval $0_arg1_name := $(if $(value 1),$(strip $1),$(call mb_printf_error,$0: network name required)))
$(call dk_invoke,network rm,,$($0_arg1_name))
)
endef

######################################################################################
# mb_exec_with_mode handler
######################################################################################
Expand Down
8 changes: 6 additions & 2 deletions modules/containers/docker/mod_config.mk
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@ dk_exec_default_tty ?= -it#
## Default options for docker logs (non-blocking by default)
dk_logs_default_opts ?= --tail=200#

## Default network name for docker/network-ensure target
dk_default_network_name ?=#
## Default network driver for docker/network/create and docker/network/ensure targets
dk_network_default_driver ?= bridge#

## Suppress errors for network create (when exists) and remove (when missing)
## Set to 'true' to skip silently instead of failing
docker_network_ignore_errors ?=#

## Default command for running commands in containers
dk_exec_default_dk_cmd ?= exec
72 changes: 72 additions & 0 deletions modules/containers/docker/targets.mk
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,75 @@ docker/clean-all: ## Remove all unused containers, images, volumes, and networks
$(call mb_printf_info,Cleaning all unused Docker resources...) $(call dk_invoke,system prune,--volumes --force),\
$(call mb_printf_info,Cleanup cancelled)\
)

######################################################################################
# Targets - Network Operations
######################################################################################

## docker/network/create: Create a docker network (fails if exists)
## Usage: docker/network/create/<name>[@driver][@subnet][@gateway]
## Parameters (use @ as separator):
## name - Network name (required)
## driver - Network driver: bridge, overlay, host, none (default: bridge)
## subnet - Network subnet in CIDR notation (optional, e.g., 172.20.0.0/16)
## gateway - Network gateway IP (optional, e.g., 172.20.0.1)
## Configuration variables (used if target params not provided):
## docker_network_<name>_driver - Network driver
## docker_network_<name>_subnet - Network subnet
## docker_network_<name>_gateway - Network gateway
## To suppress errors when network exists, set: docker_network_ignore_errors=true
## Examples:
## make docker/network/create/myapp
## make docker/network/create/myapp@overlay
## make docker/network/create/myapp@bridge@172.20.0.0/16
## make docker/network/create/myapp@bridge@172.20.0.0/16@172.20.0.1
docker/network/create/%: ## Create a network (fails if exists). Usage: docker/network/create/<name>[@driver][@subnet][@gateway]
$(call dk_network_parse_params,$*)
$(if $(call mb_is_true,$(call dk_network_exists,$(dk_network_parse_params_name))),\
$(if $(call mb_is_true,$(docker_network_ignore_errors)),\
$(call mb_printf_info,Network $(dk_network_parse_params_name) already exists (skipped))\
,\
$(call mb_printf_error,Network $(dk_network_parse_params_name) already exists. Use docker/network/ensure instead)\
),\
$(call mb_printf_info,Creating network $(dk_network_parse_params_name))\
$(call dk_network_create,$(dk_network_parse_params_name),$(dk_network_parse_params_driver),$(dk_network_parse_params_subnet),$(dk_network_parse_params_gateway))\
)

docker/network/create: # Wrapper for docker/network/create/%
$(call mb_printf_info,Usage: make docker/network/create/<name>[@driver][@subnet][@gateway])

## docker/network/ensure: Ensure a docker network exists (create if missing)
## Usage: docker/network/ensure/<name>[@driver][@subnet][@gateway]
## Parameters and configuration are identical to docker/network/create
## This target is idempotent - safe to call multiple times
## Examples:
## make docker/network/ensure/myapp
## make docker/network/ensure/myapp@overlay@172.20.0.0/16
docker/network/ensure/%: ## Ensure network exists (create if missing). Usage: docker/network/ensure/<name>[@driver][@subnet][@gateway]
$(call dk_network_parse_params,$*)
$(if $(call mb_is_true,$(call dk_network_exists,$(dk_network_parse_params_name))),\
$(call mb_printf_info,Network $(dk_network_parse_params_name) already exists),\
$(call mb_printf_info,Creating network $(dk_network_parse_params_name))\
$(call dk_network_create,$(dk_network_parse_params_name),$(dk_network_parse_params_driver),$(dk_network_parse_params_subnet),$(dk_network_parse_params_gateway))\
)

docker/network/ensure: # Wrapper for docker/network/ensure/%
$(call mb_printf_info,Usage: make docker/network/ensure/<name>[@driver][@subnet][@gateway])

## docker/network/remove: Remove a docker network (fails if not exists)
## Usage: docker/network/remove/<name>
## To suppress errors when network doesn't exist, set: docker_network_ignore_errors=true
## Examples:
## make docker/network/remove/myapp
docker/network/remove/%: ## Remove a network (fails if not exists). Usage: docker/network/remove/<name>
$(if $(call mb_is_false,$(call dk_network_exists,$*)),\
$(if $(call mb_is_true,$(docker_network_ignore_errors)),\
$(call mb_printf_info,Network $* does not exist (skipped)),\
$(call mb_printf_error,Network $* does not exist)\
),\
$(call mb_printf_info,Removing network $*)\
$(call dk_network_remove,$*)\
)

docker/network/remove: # Wrapper for docker/network/remove/%
$(call mb_printf_info,Usage: make docker/network/remove/<name>)