pyinfra 3.1__py2.py3-none-any.whl → 3.2__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. pyinfra/api/arguments.py +10 -3
  2. pyinfra/api/deploy.py +12 -2
  3. pyinfra/api/host.py +7 -4
  4. pyinfra/connectors/chroot.py +1 -1
  5. pyinfra/connectors/docker.py +17 -6
  6. pyinfra/connectors/local.py +1 -1
  7. pyinfra/connectors/ssh.py +3 -0
  8. pyinfra/connectors/sshuserclient/client.py +26 -14
  9. pyinfra/facts/apk.py +3 -1
  10. pyinfra/facts/apt.py +62 -2
  11. pyinfra/facts/crontab.py +190 -0
  12. pyinfra/facts/docker.py +6 -0
  13. pyinfra/facts/efibootmgr.py +108 -0
  14. pyinfra/facts/files.py +93 -6
  15. pyinfra/facts/git.py +3 -2
  16. pyinfra/facts/hardware.py +1 -0
  17. pyinfra/facts/mysql.py +1 -2
  18. pyinfra/facts/opkg.py +233 -0
  19. pyinfra/facts/pipx.py +74 -0
  20. pyinfra/facts/podman.py +47 -0
  21. pyinfra/facts/postgres.py +2 -0
  22. pyinfra/facts/selinux.py +3 -1
  23. pyinfra/facts/server.py +39 -77
  24. pyinfra/facts/util/units.py +30 -0
  25. pyinfra/facts/zfs.py +22 -19
  26. pyinfra/local.py +3 -2
  27. pyinfra/operations/apt.py +29 -21
  28. pyinfra/operations/crontab.py +189 -0
  29. pyinfra/operations/docker.py +13 -12
  30. pyinfra/operations/files.py +20 -2
  31. pyinfra/operations/git.py +48 -9
  32. pyinfra/operations/opkg.py +88 -0
  33. pyinfra/operations/pip.py +3 -2
  34. pyinfra/operations/pipx.py +90 -0
  35. pyinfra/operations/postgres.py +15 -11
  36. pyinfra/operations/runit.py +2 -0
  37. pyinfra/operations/server.py +4 -178
  38. pyinfra/operations/zfs.py +14 -14
  39. {pyinfra-3.1.dist-info → pyinfra-3.2.dist-info}/METADATA +11 -12
  40. {pyinfra-3.1.dist-info → pyinfra-3.2.dist-info}/RECORD +52 -43
  41. pyinfra_cli/inventory.py +26 -9
  42. pyinfra_cli/prints.py +18 -3
  43. pyinfra_cli/util.py +5 -2
  44. tests/test_cli/test_cli_deploy.py +15 -13
  45. tests/test_cli/test_cli_exceptions.py +2 -2
  46. tests/test_cli/test_cli_inventory.py +53 -0
  47. tests/test_cli/test_cli_util.py +2 -4
  48. tests/test_connectors/test_sshuserclient.py +68 -1
  49. {pyinfra-3.1.dist-info → pyinfra-3.2.dist-info}/LICENSE.md +0 -0
  50. {pyinfra-3.1.dist-info → pyinfra-3.2.dist-info}/WHEEL +0 -0
  51. {pyinfra-3.1.dist-info → pyinfra-3.2.dist-info}/entry_points.txt +0 -0
  52. {pyinfra-3.1.dist-info → pyinfra-3.2.dist-info}/top_level.txt +0 -0
pyinfra/facts/server.py CHANGED
@@ -5,14 +5,15 @@ import re
5
5
  import shutil
6
6
  from datetime import datetime
7
7
  from tempfile import mkdtemp
8
- from typing import Dict, List, Optional, Union
8
+ from typing import Dict, List, Optional
9
9
 
10
10
  from dateutil.parser import parse as parse_date
11
11
  from distro import distro
12
- from typing_extensions import NotRequired, TypedDict
12
+ from typing_extensions import TypedDict
13
13
 
14
14
  from pyinfra.api import FactBase, ShortFactBase
15
15
  from pyinfra.api.util import try_int
16
+ from pyinfra.facts import crontab
16
17
 
17
18
  ISO_DATE_FORMAT = "%Y-%m-%dT%H:%M:%S%z"
18
19
 
@@ -31,8 +32,7 @@ class Home(FactBase[Optional[str]]):
31
32
  Returns the home directory of the given user, or the current user if no user is given.
32
33
  """
33
34
 
34
- @staticmethod
35
- def command(user=""):
35
+ def command(self, user=""):
36
36
  return f"echo ~{user}"
37
37
 
38
38
 
@@ -123,8 +123,7 @@ class Command(FactBase[str]):
123
123
  Returns the raw output lines of a given command.
124
124
  """
125
125
 
126
- @staticmethod
127
- def command(command):
126
+ def command(self, command):
128
127
  return command
129
128
 
130
129
 
@@ -133,8 +132,7 @@ class Which(FactBase[Optional[str]]):
133
132
  Returns the path of a given command according to `command -v`, if available.
134
133
  """
135
134
 
136
- @staticmethod
137
- def command(command):
135
+ def command(self, command):
138
136
  return "command -v {0} || true".format(command)
139
137
 
140
138
 
@@ -307,6 +305,36 @@ class LsbRelease(FactBase):
307
305
  return items
308
306
 
309
307
 
308
+ class OsRelease(FactBase):
309
+ """
310
+ Returns a dictionary of release information stored in ``/etc/os-release``.
311
+
312
+ .. code:: python
313
+
314
+ {
315
+ "name": "EndeavourOS",
316
+ "pretty_name": "EndeavourOS",
317
+ "id": "endeavouros",
318
+ "id_like": "arch",
319
+ "build_id": "2024.06.25",
320
+ ...
321
+ }
322
+ """
323
+
324
+ def command(self):
325
+ return "cat /etc/os-release"
326
+
327
+ def process(self, output):
328
+ items = {}
329
+
330
+ for line in output:
331
+ if "=" in line:
332
+ key, value = line.split("=", 1)
333
+ items[key.strip().lower()] = value.strip().strip('"')
334
+
335
+ return items
336
+
337
+
310
338
  class Sysctl(FactBase):
311
339
  """
312
340
  Returns a dictionary of sysctl settings and values.
@@ -377,75 +405,9 @@ class Groups(FactBase[List[str]]):
377
405
  return groups
378
406
 
379
407
 
380
- class CrontabDict(TypedDict):
381
- minute: NotRequired[Union[int, str]]
382
- hour: NotRequired[Union[int, str]]
383
- month: NotRequired[Union[int, str]]
384
- day_of_month: NotRequired[Union[int, str]]
385
- day_of_week: NotRequired[Union[int, str]]
386
- comments: Optional[list[str]]
387
- special_time: NotRequired[str]
388
-
389
-
390
- class Crontab(FactBase[Dict[str, CrontabDict]]):
391
- """
392
- Returns a dictionary of cron command -> execution time.
393
-
394
- .. code:: python
395
-
396
- {
397
- "/path/to/command": {
398
- "minute": "*",
399
- "hour": "*",
400
- "month": "*",
401
- "day_of_month": "*",
402
- "day_of_week": "*",
403
- },
404
- "echo another command": {
405
- "special_time": "@daily",
406
- },
407
- }
408
- """
409
-
410
- default = dict
411
-
412
- def requires_command(self, user=None) -> str:
413
- return "crontab"
414
-
415
- def command(self, user=None):
416
- if user:
417
- return "crontab -l -u {0} || true".format(user)
418
- return "crontab -l || true"
419
-
420
- def process(self, output):
421
- crons: dict[str, CrontabDict] = {}
422
- current_comments = []
423
-
424
- for line in output:
425
- line = line.strip()
426
- if not line or line.startswith("#"):
427
- current_comments.append(line)
428
- continue
429
-
430
- if line.startswith("@"):
431
- special_time, command = line.split(None, 1)
432
- crons[command] = {
433
- "special_time": special_time,
434
- "comments": current_comments,
435
- }
436
- else:
437
- minute, hour, day_of_month, month, day_of_week, command = line.split(None, 5)
438
- crons[command] = {
439
- "minute": try_int(minute),
440
- "hour": try_int(hour),
441
- "month": try_int(month),
442
- "day_of_month": try_int(day_of_month),
443
- "day_of_week": try_int(day_of_week),
444
- "comments": current_comments,
445
- }
446
-
447
- current_comments = []
448
- return crons
408
+ # for compatibility
409
+ CrontabDict = crontab.CrontabDict
410
+ Crontab = crontab.Crontab
449
411
 
450
412
 
451
413
  class Users(FactBase):
@@ -0,0 +1,30 @@
1
+ # from https://stackoverflow.com/a/60708339, but with a few modifications
2
+ from __future__ import annotations # for | in type hints
3
+
4
+ import re
5
+
6
+ units = {
7
+ "B": 1,
8
+ "KB": 10**3,
9
+ "MB": 10**6,
10
+ "GB": 10**9,
11
+ "TB": 10**12,
12
+ "KIB": 2**10,
13
+ "MIB": 2**20,
14
+ "GIB": 2**30,
15
+ "TIB": 2**40,
16
+ }
17
+
18
+
19
+ def parse_human_readable_size(size: str) -> int:
20
+ size = size.upper()
21
+ if not re.match(r" ", size):
22
+ size = re.sub(r"([KMGT]?I?[B])", r" \1", size)
23
+ number, unit = [string.strip() for string in size.split()]
24
+ return int(float(number) * units[unit])
25
+
26
+
27
+ def parse_size(size: str | int) -> int:
28
+ if isinstance(size, int):
29
+ return size
30
+ return parse_human_readable_size(size)
pyinfra/facts/zfs.py CHANGED
@@ -1,5 +1,5 @@
1
1
  """
2
- Manage ZFS filesystems.
2
+ Gather information about ZFS filesystems.
3
3
  """
4
4
 
5
5
  from pyinfra.api import FactBase, ShortFactBase
@@ -15,43 +15,46 @@ def _process_zfs_props_table(output):
15
15
  return datasets
16
16
 
17
17
 
18
- class Pools(FactBase):
18
+ class ZfsPools(FactBase):
19
19
  def command(self):
20
20
  return "zpool get -H all"
21
21
 
22
- @staticmethod
23
- def process(output):
22
+ def process(self, output):
24
23
  return _process_zfs_props_table(output)
25
24
 
26
25
 
27
- class Datasets(FactBase):
26
+ class ZfsDatasets(FactBase):
28
27
  def command(self):
29
28
  return "zfs get -H all"
30
29
 
31
- @staticmethod
32
- def process(output):
30
+ def process(self, output):
33
31
  return _process_zfs_props_table(output)
34
32
 
35
33
 
36
- class Filesystems(ShortFactBase):
37
- fact = Datasets
34
+ class ZfsFilesystems(ShortFactBase):
35
+ fact = ZfsDatasets
38
36
 
39
- @staticmethod
40
- def process_data(data):
37
+ def process_data(self, data):
41
38
  return {name: props for name, props in data.items() if props.get("type") == "filesystem"}
42
39
 
43
40
 
44
- class Snapshots(ShortFactBase):
45
- fact = Datasets
41
+ class ZfsSnapshots(ShortFactBase):
42
+ fact = ZfsDatasets
46
43
 
47
- @staticmethod
48
- def process_data(data):
44
+ def process_data(self, data):
49
45
  return {name: props for name, props in data.items() if props.get("type") == "snapshot"}
50
46
 
51
47
 
52
- class Volumes(ShortFactBase):
53
- fact = Datasets
48
+ class ZfsVolumes(ShortFactBase):
49
+ fact = ZfsDatasets
54
50
 
55
- @staticmethod
56
- def process_data(data):
51
+ def process_data(self, data):
57
52
  return {name: props for name, props in data.items() if props.get("type") == "volume"}
53
+
54
+
55
+ # TODO: remove these in v4! Or flip the convention and remove all the other fact prefixes!
56
+ Pools = ZfsPools
57
+ Datasets = ZfsDatasets
58
+ Filesystems = ZfsFilesystems
59
+ Snapshots = ZfsSnapshots
60
+ Volumes = ZfsVolumes
pyinfra/local.py CHANGED
@@ -1,4 +1,5 @@
1
1
  from os import path
2
+ from typing import Optional
2
3
 
3
4
  import click
4
5
 
@@ -10,7 +11,7 @@ from pyinfra.connectors.util import run_local_process
10
11
  from pyinfra.context import ctx_state
11
12
 
12
13
 
13
- def include(filename: str):
14
+ def include(filename: str, data: Optional[dict] = None):
14
15
  """
15
16
  Executes a local python file within the ``pyinfra.state.cwd``
16
17
  directory.
@@ -33,7 +34,7 @@ def include(filename: str):
33
34
 
34
35
  from pyinfra_cli.util import exec_file
35
36
 
36
- with host.deploy(path.relpath(filename, state.cwd), None, None, in_deploy=False):
37
+ with host.deploy(path.relpath(filename, state.cwd), None, data, in_deploy=False):
37
38
  exec_file(filename)
38
39
 
39
40
  # One potential solution to the above is to add local as an actual
pyinfra/operations/apt.py CHANGED
@@ -9,7 +9,13 @@ from urllib.parse import urlparse
9
9
 
10
10
  from pyinfra import host
11
11
  from pyinfra.api import OperationError, operation
12
- from pyinfra.facts.apt import AptKeys, AptSources, parse_apt_repo
12
+ from pyinfra.facts.apt import (
13
+ AptKeys,
14
+ AptSources,
15
+ SimulateOperationWillChange,
16
+ noninteractive_apt,
17
+ parse_apt_repo,
18
+ )
13
19
  from pyinfra.facts.deb import DebPackage, DebPackages
14
20
  from pyinfra.facts.files import File
15
21
  from pyinfra.facts.gpg import GpgKey
@@ -21,21 +27,22 @@ from .util.packaging import ensure_packages
21
27
  APT_UPDATE_FILENAME = "/var/lib/apt/periodic/update-success-stamp"
22
28
 
23
29
 
24
- def noninteractive_apt(command: str, force=False):
25
- args = ["DEBIAN_FRONTEND=noninteractive apt-get -y"]
26
-
27
- if force:
28
- args.append("--force-yes")
29
-
30
- args.extend(
31
- (
32
- '-o Dpkg::Options::="--force-confdef"',
33
- '-o Dpkg::Options::="--force-confold"',
34
- command,
35
- ),
36
- )
37
-
38
- return " ".join(args)
30
+ def _simulate_then_perform(command: str):
31
+ changes = host.get_fact(SimulateOperationWillChange, command)
32
+
33
+ if not changes:
34
+ # Simulating apt-get command failed, so the actual
35
+ # operation will probably fail too:
36
+ yield noninteractive_apt(command)
37
+ elif (
38
+ changes["upgraded"] == 0
39
+ and changes["newly_installed"] == 0
40
+ and changes["removed"] == 0
41
+ and changes["not_upgraded"] == 0
42
+ ):
43
+ host.noop(f"{command} skipped, no changes would be performed")
44
+ else:
45
+ yield noninteractive_apt(command)
39
46
 
40
47
 
41
48
  @operation()
@@ -53,7 +60,8 @@ def key(src: str | None = None, keyserver: str | None = None, keyid: str | list[
53
60
  .. warning::
54
61
  ``apt-key`` is deprecated in Debian, it is recommended NOT to use this
55
62
  operation and instead follow the instructions here:
56
- https://wiki.debian.org/DebianRepository/UseThirdParty
63
+
64
+ https://wiki.debian.org/DebianRepository/UseThirdParty
57
65
 
58
66
  **Examples:**
59
67
 
@@ -320,7 +328,7 @@ def update(cache_time: int | None = None):
320
328
  _update = update # noqa: E305
321
329
 
322
330
 
323
- @operation(is_idempotent=False)
331
+ @operation()
324
332
  def upgrade(auto_remove: bool = False):
325
333
  """
326
334
  Upgrades all apt packages.
@@ -348,13 +356,13 @@ def upgrade(auto_remove: bool = False):
348
356
  if auto_remove:
349
357
  command.append("--autoremove")
350
358
 
351
- yield noninteractive_apt(" ".join(command))
359
+ yield from _simulate_then_perform(" ".join(command))
352
360
 
353
361
 
354
362
  _upgrade = upgrade # noqa: E305 (for use below where update is a kwarg)
355
363
 
356
364
 
357
- @operation(is_idempotent=False)
365
+ @operation()
358
366
  def dist_upgrade():
359
367
  """
360
368
  Updates all apt packages, employing dist-upgrade.
@@ -368,7 +376,7 @@ def dist_upgrade():
368
376
  )
369
377
  """
370
378
 
371
- yield noninteractive_apt("dist-upgrade")
379
+ yield from _simulate_then_perform("dist-upgrade")
372
380
 
373
381
 
374
382
  @operation()
@@ -0,0 +1,189 @@
1
+ from __future__ import annotations
2
+
3
+ import shlex
4
+
5
+ from pyinfra import host
6
+ from pyinfra.api import StringCommand, operation
7
+ from pyinfra.api.util import try_int
8
+ from pyinfra.facts.crontab import Crontab, CrontabFile
9
+ from pyinfra.operations.util.files import sed_replace
10
+
11
+
12
+ @operation()
13
+ def crontab(
14
+ command: str,
15
+ present=True,
16
+ user: str | None = None,
17
+ cron_name: str | None = None,
18
+ minute="*",
19
+ hour="*",
20
+ month="*",
21
+ day_of_week="*",
22
+ day_of_month="*",
23
+ special_time: str | None = None,
24
+ interpolate_variables=False,
25
+ ):
26
+ """
27
+ Add/remove/update crontab entries.
28
+
29
+ + command: the command for the cron
30
+ + present: whether this cron command should exist
31
+ + user: the user whose crontab to manage
32
+ + cron_name: name the cronjob so future changes to the command will overwrite
33
+ + modify_cron_name: modify the cron name
34
+ + minute: which minutes to execute the cron
35
+ + hour: which hours to execute the cron
36
+ + month: which months to execute the cron
37
+ + day_of_week: which day of the week to execute the cron
38
+ + day_of_month: which day of the month to execute the cron
39
+ + special_time: cron "nickname" time (@reboot, @daily, etc), overrides others
40
+ + interpolate_variables: whether to interpolate variables in ``command``
41
+
42
+ Cron commands:
43
+ Unless ``name`` is specified the command is used to identify crontab entries.
44
+ This means commands must be unique within a given users crontab. If you require
45
+ multiple identical commands, provide a different name argument for each.
46
+
47
+ Special times:
48
+ When provided, ``special_time`` will be used instead of any values passed in
49
+ for ``minute``/``hour``/``month``/``day_of_week``/``day_of_month``.
50
+
51
+ **Example:**
52
+
53
+ .. code:: python
54
+
55
+ # simple example for a crontab
56
+ crontab.crontab(
57
+ name="Backup /etc weekly",
58
+ command="/bin/tar cf /tmp/etc_bup.tar /etc",
59
+ name="backup_etc",
60
+ day_of_week=0,
61
+ hour=1,
62
+ minute=0,
63
+ )
64
+ """
65
+
66
+ def comma_sep(value):
67
+ if isinstance(value, (list, tuple)):
68
+ return ",".join("{0}".format(v) for v in value)
69
+ return value
70
+
71
+ minute = comma_sep(minute)
72
+ hour = comma_sep(hour)
73
+ month = comma_sep(month)
74
+ day_of_week = comma_sep(day_of_week)
75
+ day_of_month = comma_sep(day_of_month)
76
+
77
+ ctb0: CrontabFile | dict = host.get_fact(Crontab, user=user)
78
+ # facts from test are in dict
79
+ if isinstance(ctb0, dict):
80
+ ctb = CrontabFile(ctb0)
81
+ else:
82
+ ctb = ctb0
83
+ name_comment = "# pyinfra-name={0}".format(cron_name)
84
+
85
+ existing_crontab = ctb.get_command(command=command, name=cron_name)
86
+ existing_crontab_command = existing_crontab["command"] if existing_crontab else command
87
+ existing_crontab_match = existing_crontab["command"] if existing_crontab else command
88
+
89
+ exists = existing_crontab is not None
90
+ exists_name = existing_crontab is not None and name_comment in existing_crontab.get(
91
+ "comments", ""
92
+ )
93
+
94
+ edit_commands: list[str | StringCommand] = []
95
+ temp_filename = host.get_temp_filename()
96
+
97
+ if special_time:
98
+ new_crontab_line = "{0} {1}".format(special_time, command)
99
+ else:
100
+ new_crontab_line = "{minute} {hour} {day_of_month} {month} {day_of_week} {command}".format(
101
+ minute=minute,
102
+ hour=hour,
103
+ day_of_month=day_of_month,
104
+ month=month,
105
+ day_of_week=day_of_week,
106
+ command=command,
107
+ )
108
+
109
+ existing_crontab_match = ".*{0}.*".format(existing_crontab_match)
110
+
111
+ # Don't want the cron and it does exist? Remove the line
112
+ if not present and exists:
113
+ edit_commands.append(
114
+ sed_replace(
115
+ temp_filename,
116
+ existing_crontab_match,
117
+ "",
118
+ interpolate_variables=interpolate_variables,
119
+ ),
120
+ )
121
+
122
+ # Want the cron but it doesn't exist? Append the line
123
+ elif present and not exists:
124
+ print("present", present, "exists", exists)
125
+ if ctb: # append a blank line if cron entries already exist
126
+ edit_commands.append("echo '' >> {0}".format(temp_filename))
127
+ if cron_name:
128
+ edit_commands.append(
129
+ "echo {0} >> {1}".format(
130
+ shlex.quote(name_comment),
131
+ temp_filename,
132
+ ),
133
+ )
134
+
135
+ edit_commands.append(
136
+ "echo {0} >> {1}".format(
137
+ shlex.quote(new_crontab_line),
138
+ temp_filename,
139
+ ),
140
+ )
141
+
142
+ # We have the cron and it exists, do it's details? If not, replace the line
143
+ elif present and exists:
144
+ assert existing_crontab is not None
145
+ if any(
146
+ (
147
+ exists_name != (cron_name is not None),
148
+ special_time != existing_crontab.get("special_time"),
149
+ try_int(minute) != existing_crontab.get("minute"),
150
+ try_int(hour) != existing_crontab.get("hour"),
151
+ try_int(month) != existing_crontab.get("month"),
152
+ try_int(day_of_week) != existing_crontab.get("day_of_week"),
153
+ try_int(day_of_month) != existing_crontab.get("day_of_month"),
154
+ existing_crontab_command != command,
155
+ ),
156
+ ):
157
+ if not exists_name and cron_name:
158
+ new_crontab_line = f"{name_comment}\n{new_crontab_line}"
159
+ edit_commands.append(
160
+ sed_replace(
161
+ temp_filename,
162
+ existing_crontab_match,
163
+ new_crontab_line,
164
+ interpolate_variables=interpolate_variables,
165
+ ),
166
+ )
167
+
168
+ if edit_commands:
169
+ crontab_args = []
170
+ if user:
171
+ crontab_args.append("-u {0}".format(user))
172
+
173
+ # List the crontab into a temporary file if it exists
174
+ if ctb:
175
+ yield "crontab -l {0} > {1}".format(" ".join(crontab_args), temp_filename)
176
+
177
+ # Now yield any edits
178
+ for edit_command in edit_commands:
179
+ yield edit_command
180
+
181
+ # Finally, use the tempfile to write a new crontab
182
+ yield "crontab {0} {1}".format(" ".join(crontab_args), temp_filename)
183
+ else:
184
+ host.noop(
185
+ "crontab {0} {1}".format(
186
+ command,
187
+ "exists" if present else "does not exist",
188
+ ),
189
+ )
@@ -1,5 +1,7 @@
1
1
  """
2
- Manager Docker Containers, Volumes and Networks
2
+ Manager Docker containers, volumes and networks. These operations allow you to manage Docker from
3
+ the view of the current inventory host. See the :doc:`../connectors/docker` to use Docker containers
4
+ as inventory directly.
3
5
  """
4
6
 
5
7
  from pyinfra import host
@@ -30,9 +32,9 @@ def container(
30
32
  + networks: network list to attach on container
31
33
  + ports: port list to expose
32
34
  + volumes: volume list to map on container
33
- + env_vars: environment varible list to inject on container
35
+ + env_vars: environment variable list to inject on container
34
36
  + pull_always: force image pull
35
- + force: remove a contaner with same name and create a new one
37
+ + force: remove a container with same name and create a new one
36
38
  + present: whether the container should be up and running
37
39
  + start: start or stop the container
38
40
 
@@ -125,7 +127,7 @@ def image(image, present=True):
125
127
  Manage Docker images
126
128
 
127
129
  + image: Image and tag ex: nginx:alpine
128
- + present: whether the Docker image should be exist
130
+ + present: whether the Docker image should exist
129
131
 
130
132
  **Examples:**
131
133
 
@@ -188,7 +190,7 @@ def volume(volume, driver="", labels=None, present=True):
188
190
  if present:
189
191
 
190
192
  if existent_volume:
191
- host.noop("Volume alredy exist!")
193
+ host.noop("Volume already exists!")
192
194
  return
193
195
 
194
196
  yield handle_docker(
@@ -231,8 +233,8 @@ def network(
231
233
  """
232
234
  Manage docker networks
233
235
 
234
- + network_name: Image name
235
- + driver: Container image and tag ex: nginx:alpine
236
+ + network: Network name
237
+ + driver: Network driver ex: bridge or overlay
236
238
  + gateway: IPv4 or IPv6 Gateway for the master subnet
237
239
  + ip_range: Allocate container ip from a sub-range
238
240
  + ipam_driver: IP Address Management Driver
@@ -251,8 +253,7 @@ def network(
251
253
 
252
254
  # Create Docker network
253
255
  docker.network(
254
- name="Create nginx network",
255
- network_name="nginx",
256
+ network="nginx",
256
257
  attachable=True,
257
258
  present=True,
258
259
  )
@@ -261,7 +262,7 @@ def network(
261
262
 
262
263
  if present:
263
264
  if existent_network:
264
- host.noop("Alredy exist a network with {0} name!".format(network))
265
+ host.noop("Network {0} already exists!".format(network))
265
266
  return
266
267
 
267
268
  yield handle_docker(
@@ -284,12 +285,12 @@ def network(
284
285
 
285
286
  else:
286
287
  if existent_network is None:
287
- host.noop("Ther is not network with {0} name!".format(network))
288
+ host.noop("Network {0} does not exist!".format(network))
288
289
  return
289
290
 
290
291
  yield handle_docker(
291
292
  resource="network",
292
- command="create",
293
+ command="remove",
293
294
  network=network,
294
295
  )
295
296