44as inventory directly.
55"""
66
7+ from __future__ import annotations
8+
79from pyinfra import host
810from pyinfra .api import operation
9- from pyinfra .facts .docker import DockerContainer , DockerNetwork , DockerVolume
11+ from pyinfra .facts .docker import DockerContainer , DockerNetwork , DockerPlugin , DockerVolume
1012
1113from .util .docker import ContainerSpec , handle_docker
1214
1315
1416@operation ()
1517def container (
16- container ,
17- image = "" ,
18- ports = None ,
19- networks = None ,
20- volumes = None ,
21- env_vars = None ,
22- pull_always = False ,
23- present = True ,
24- force = False ,
25- start = True ,
18+ container : str ,
19+ image : str = "" ,
20+ ports : list [ str ] | None = None ,
21+ networks : list [ str ] | None = None ,
22+ volumes : list [ str ] | None = None ,
23+ env_vars : list [ str ] | None = None ,
24+ pull_always : bool = False ,
25+ present : bool = True ,
26+ force : bool = False ,
27+ start : bool = True ,
2628):
2729 """
2830 Manage Docker containers
@@ -168,7 +170,7 @@ def image(image, present=True):
168170
169171
170172@operation ()
171- def volume (volume , driver = "" , labels = None , present = True ):
173+ def volume (volume : str , driver : str = "" , labels : list [ str ] | None = None , present : bool = True ):
172174 """
173175 Manage Docker volumes
174176
@@ -220,20 +222,20 @@ def volume(volume, driver="", labels=None, present=True):
220222
221223@operation ()
222224def network (
223- network ,
224- driver = "" ,
225- gateway = "" ,
226- ip_range = "" ,
227- ipam_driver = "" ,
228- subnet = "" ,
229- scope = "" ,
230- aux_addresses = None ,
231- opts = None ,
232- ipam_opts = None ,
233- labels = None ,
234- ingress = False ,
235- attachable = False ,
236- present = True ,
225+ network : str ,
226+ driver : str = "" ,
227+ gateway : str = "" ,
228+ ip_range : str = "" ,
229+ ipam_driver : str = "" ,
230+ subnet : str = "" ,
231+ scope : str = "" ,
232+ aux_addresses : dict [ str , str ] | None = None ,
233+ opts : list [ str ] | None = None ,
234+ ipam_opts : list [ str ] | None = None ,
235+ labels : list [ str ] | None = None ,
236+ ingress : bool = False ,
237+ attachable : bool = False ,
238+ present : bool = True ,
237239):
238240 """
239241 Manage docker networks
@@ -245,6 +247,7 @@ def network(
245247 + ipam_driver: IP Address Management Driver
246248 + subnet: Subnet in CIDR format that represents a network segment
247249 + scope: Control the network's scope
250+ + aux_addresses: named aux addresses for the network
248251 + opts: Set driver specific options
249252 + ipam_opts: Set IPAM driver specific options
250253 + labels: Label list to attach in the network
@@ -303,9 +306,9 @@ def network(
303306
304307@operation (is_idempotent = False )
305308def prune (
306- all = False ,
307- volumes = False ,
308- filter = "" ,
309+ all : bool = False ,
310+ volumes : bool = False ,
311+ filter : str = "" ,
309312):
310313 """
311314 Execute a docker system prune.
@@ -344,3 +347,101 @@ def prune(
344347 volumes = volumes ,
345348 filter = filter ,
346349 )
350+
351+
352+ @operation ()
353+ def plugin (
354+ plugin : str ,
355+ alias : str | None = None ,
356+ present : bool = True ,
357+ enabled : bool = True ,
358+ plugin_options : dict [str , str ] | None = None ,
359+ ):
360+ """
361+ Manage Docker plugins
362+
363+ + plugin: Plugin name
364+ + alias: Alias for the plugin (optional)
365+ + present: Whether the plugin should be installed
366+ + enabled: Whether the plugin should be enabled
367+ + plugin_options: Options to pass to the plugin
368+
369+ **Examples:**
370+
371+ .. code:: python
372+
373+ # Install and enable a Docker plugin
374+ docker.plugin(
375+ name="Install and enable a Docker plugin",
376+ plugin="username/my-awesome-plugin:latest",
377+ alias="my-plugin",
378+ present=True,
379+ enabled=True,
380+ plugin_options={"option1": "value1", "option2": "value2"},
381+ )
382+ """
383+ plugin_name = alias if alias else plugin
384+ existent_plugin = host .get_fact (DockerPlugin , object_id = plugin_name )
385+ if existent_plugin :
386+ existent_plugin = existent_plugin [0 ]
387+
388+ if present :
389+ if existent_plugin :
390+ plugin_options_different = (
391+ plugin_options and existent_plugin ["Settings" ]["Env" ] != plugin_options
392+ )
393+ if plugin_options_different :
394+ # Update options on existing plugin
395+ if existent_plugin ["Enabled" ]:
396+ yield handle_docker (
397+ resource = "plugin" ,
398+ command = "disable" ,
399+ plugin = plugin_name ,
400+ )
401+ yield handle_docker (
402+ resource = "plugin" ,
403+ command = "set" ,
404+ plugin = plugin_name ,
405+ enabled = enabled ,
406+ existent_options = existent_plugin ["Settings" ]["Env" ],
407+ required_options = plugin_options ,
408+ )
409+ if enabled :
410+ yield handle_docker (
411+ resource = "plugin" ,
412+ command = "enable" ,
413+ plugin = plugin_name ,
414+ )
415+ else :
416+ # Options are the same, check if enabled state is different
417+ if existent_plugin ["Enabled" ] == enabled :
418+ host .noop (
419+ f"Plugin '{ plugin_name } ' is already installed with the same options "
420+ f"and { 'enabled' if enabled else 'disabled' } ."
421+ )
422+ return
423+ else :
424+ command = "enable" if enabled else "disable"
425+ yield handle_docker (
426+ resource = "plugin" ,
427+ command = command ,
428+ plugin = plugin_name ,
429+ )
430+ else :
431+ yield handle_docker (
432+ resource = "plugin" ,
433+ command = "install" ,
434+ plugin = plugin ,
435+ alias = alias ,
436+ enabled = enabled ,
437+ plugin_options = plugin_options ,
438+ )
439+ else :
440+ if not existent_plugin :
441+ host .noop (f"Plugin '{ plugin_name } ' is not installed." )
442+ return
443+ yield handle_docker (
444+ resource = "plugin" ,
445+ command = "remove" ,
446+ plugin = plugin_name ,
447+ )
0 commit comments