pyinfra 2.9.1__py2.py3-none-any.whl → 3.0__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 (156) hide show
  1. pyinfra/api/__init__.py +3 -0
  2. pyinfra/api/arguments.py +265 -253
  3. pyinfra/api/arguments_typed.py +80 -0
  4. pyinfra/api/command.py +68 -53
  5. pyinfra/api/config.py +139 -32
  6. pyinfra/api/connect.py +1 -1
  7. pyinfra/api/connectors.py +7 -26
  8. pyinfra/api/deploy.py +21 -52
  9. pyinfra/api/exceptions.py +33 -8
  10. pyinfra/api/facts.py +102 -137
  11. pyinfra/api/host.py +150 -82
  12. pyinfra/api/inventory.py +21 -25
  13. pyinfra/api/operation.py +240 -198
  14. pyinfra/api/operations.py +102 -148
  15. pyinfra/api/state.py +137 -79
  16. pyinfra/api/util.py +79 -86
  17. pyinfra/connectors/base.py +147 -0
  18. pyinfra/connectors/chroot.py +160 -169
  19. pyinfra/connectors/docker.py +220 -237
  20. pyinfra/connectors/dockerssh.py +231 -253
  21. pyinfra/connectors/local.py +196 -208
  22. pyinfra/connectors/ssh.py +530 -613
  23. pyinfra/connectors/ssh_util.py +114 -0
  24. pyinfra/connectors/sshuserclient/client.py +5 -3
  25. pyinfra/connectors/terraform.py +86 -65
  26. pyinfra/connectors/util.py +211 -137
  27. pyinfra/connectors/vagrant.py +60 -53
  28. pyinfra/context.py +4 -2
  29. pyinfra/facts/apk.py +2 -0
  30. pyinfra/facts/apt.py +2 -0
  31. pyinfra/facts/brew.py +2 -0
  32. pyinfra/facts/bsdinit.py +2 -0
  33. pyinfra/facts/cargo.py +2 -0
  34. pyinfra/facts/choco.py +2 -0
  35. pyinfra/facts/deb.py +7 -2
  36. pyinfra/facts/dnf.py +2 -0
  37. pyinfra/facts/docker.py +19 -0
  38. pyinfra/facts/files.py +47 -32
  39. pyinfra/facts/gem.py +2 -0
  40. pyinfra/facts/git.py +3 -1
  41. pyinfra/facts/gpg.py +3 -1
  42. pyinfra/facts/hardware.py +34 -24
  43. pyinfra/facts/iptables.py +5 -3
  44. pyinfra/facts/launchd.py +2 -0
  45. pyinfra/facts/lxd.py +2 -0
  46. pyinfra/facts/mysql.py +13 -6
  47. pyinfra/facts/npm.py +1 -0
  48. pyinfra/facts/openrc.py +2 -0
  49. pyinfra/facts/pacman.py +6 -2
  50. pyinfra/facts/pip.py +2 -0
  51. pyinfra/facts/pkg.py +2 -0
  52. pyinfra/facts/pkgin.py +2 -0
  53. pyinfra/facts/postgres.py +168 -0
  54. pyinfra/facts/postgresql.py +6 -160
  55. pyinfra/facts/rpm.py +12 -9
  56. pyinfra/facts/runit.py +68 -0
  57. pyinfra/facts/selinux.py +3 -1
  58. pyinfra/facts/server.py +80 -36
  59. pyinfra/facts/snap.py +2 -0
  60. pyinfra/facts/systemd.py +31 -12
  61. pyinfra/facts/sysvinit.py +10 -10
  62. pyinfra/facts/upstart.py +2 -0
  63. pyinfra/facts/util/packaging.py +7 -4
  64. pyinfra/facts/vzctl.py +2 -0
  65. pyinfra/facts/xbps.py +2 -0
  66. pyinfra/facts/yum.py +2 -0
  67. pyinfra/facts/zypper.py +2 -0
  68. pyinfra/local.py +4 -5
  69. pyinfra/operations/apk.py +6 -4
  70. pyinfra/operations/apt.py +46 -65
  71. pyinfra/operations/brew.py +17 -22
  72. pyinfra/operations/bsdinit.py +9 -7
  73. pyinfra/operations/cargo.py +4 -2
  74. pyinfra/operations/choco.py +4 -2
  75. pyinfra/operations/dnf.py +19 -23
  76. pyinfra/operations/docker.py +339 -0
  77. pyinfra/operations/files.py +188 -386
  78. pyinfra/operations/gem.py +4 -2
  79. pyinfra/operations/git.py +24 -53
  80. pyinfra/operations/iptables.py +29 -35
  81. pyinfra/operations/launchd.py +6 -7
  82. pyinfra/operations/lxd.py +8 -13
  83. pyinfra/operations/mysql.py +62 -81
  84. pyinfra/operations/npm.py +9 -2
  85. pyinfra/operations/openrc.py +6 -4
  86. pyinfra/operations/pacman.py +7 -8
  87. pyinfra/operations/pip.py +25 -24
  88. pyinfra/operations/pkg.py +4 -2
  89. pyinfra/operations/pkgin.py +6 -4
  90. pyinfra/operations/postgres.py +349 -0
  91. pyinfra/operations/postgresql.py +18 -379
  92. pyinfra/operations/puppet.py +3 -1
  93. pyinfra/operations/python.py +8 -19
  94. pyinfra/operations/runit.py +182 -0
  95. pyinfra/operations/selinux.py +47 -44
  96. pyinfra/operations/server.py +111 -127
  97. pyinfra/operations/snap.py +4 -4
  98. pyinfra/operations/ssh.py +20 -33
  99. pyinfra/operations/systemd.py +19 -15
  100. pyinfra/operations/sysvinit.py +9 -16
  101. pyinfra/operations/upstart.py +9 -7
  102. pyinfra/operations/util/__init__.py +12 -0
  103. pyinfra/operations/util/docker.py +177 -0
  104. pyinfra/operations/util/files.py +24 -16
  105. pyinfra/operations/util/packaging.py +55 -57
  106. pyinfra/operations/util/service.py +39 -51
  107. pyinfra/operations/vzctl.py +12 -10
  108. pyinfra/operations/xbps.py +6 -4
  109. pyinfra/operations/yum.py +18 -22
  110. pyinfra/operations/zypper.py +12 -13
  111. pyinfra/version.py +5 -2
  112. {pyinfra-2.9.1.dist-info → pyinfra-3.0.dist-info}/METADATA +40 -41
  113. pyinfra-3.0.dist-info/RECORD +167 -0
  114. {pyinfra-2.9.1.dist-info → pyinfra-3.0.dist-info}/WHEEL +1 -1
  115. pyinfra-3.0.dist-info/entry_points.txt +11 -0
  116. pyinfra_cli/__main__.py +4 -3
  117. pyinfra_cli/commands.py +7 -2
  118. pyinfra_cli/exceptions.py +78 -42
  119. pyinfra_cli/inventory.py +40 -6
  120. pyinfra_cli/log.py +17 -3
  121. pyinfra_cli/main.py +133 -90
  122. pyinfra_cli/prints.py +95 -127
  123. pyinfra_cli/util.py +62 -29
  124. tests/test_api/test_api.py +2 -0
  125. tests/test_api/test_api_arguments.py +13 -13
  126. tests/test_api/test_api_deploys.py +28 -29
  127. tests/test_api/test_api_facts.py +60 -98
  128. tests/test_api/test_api_operations.py +101 -201
  129. tests/test_cli/test_cli.py +18 -49
  130. tests/test_cli/test_cli_deploy.py +11 -37
  131. tests/test_cli/test_cli_exceptions.py +50 -19
  132. tests/test_cli/util.py +1 -1
  133. tests/test_connectors/test_chroot.py +6 -6
  134. tests/test_connectors/test_docker.py +4 -4
  135. tests/test_connectors/test_dockerssh.py +38 -50
  136. tests/test_connectors/test_local.py +11 -12
  137. tests/test_connectors/test_ssh.py +105 -93
  138. tests/test_connectors/test_terraform.py +9 -15
  139. tests/test_connectors/test_util.py +24 -46
  140. tests/test_connectors/test_vagrant.py +7 -7
  141. pyinfra/api/operation.pyi +0 -117
  142. pyinfra/connectors/ansible.py +0 -171
  143. pyinfra/connectors/mech.py +0 -186
  144. pyinfra/connectors/pyinfrawinrmsession/__init__.py +0 -28
  145. pyinfra/connectors/winrm.py +0 -320
  146. pyinfra/facts/windows.py +0 -366
  147. pyinfra/facts/windows_files.py +0 -90
  148. pyinfra/operations/windows.py +0 -59
  149. pyinfra/operations/windows_files.py +0 -551
  150. pyinfra-2.9.1.dist-info/RECORD +0 -170
  151. pyinfra-2.9.1.dist-info/entry_points.txt +0 -14
  152. tests/test_connectors/test_ansible.py +0 -64
  153. tests/test_connectors/test_mech.py +0 -126
  154. tests/test_connectors/test_winrm.py +0 -76
  155. {pyinfra-2.9.1.dist-info → pyinfra-3.0.dist-info}/LICENSE.md +0 -0
  156. {pyinfra-2.9.1.dist-info → pyinfra-3.0.dist-info}/top_level.txt +0 -0
@@ -1,21 +1,36 @@
1
1
  """
2
2
  Provides operations to set SELinux file contexts, booleans and port types.
3
3
  """
4
+
5
+ from __future__ import annotations
6
+
7
+ from enum import Enum
8
+
4
9
  from pyinfra import host
5
- from pyinfra.api import QuoteString, StringCommand, operation
10
+ from pyinfra.api import OperationValueError, QuoteString, StringCommand, operation
6
11
  from pyinfra.facts.selinux import FileContext, FileContextMapping, SEBoolean, SEPort, SEPorts
7
12
  from pyinfra.facts.server import Which
8
13
 
9
14
 
10
- @operation(
11
- pipeline_facts={"seboolean": "bool_name"},
12
- )
13
- def boolean(bool_name, value, persistent=False):
15
+ class Boolean(Enum):
16
+ ON = "on"
17
+ OFF = "off"
18
+
19
+
20
+ class Protocol(Enum):
21
+ UDP = "udp"
22
+ TCP = "tcp"
23
+ SCTP = "sctp"
24
+ DCCP = "dccp"
25
+
26
+
27
+ @operation()
28
+ def boolean(bool_name: str, value: Boolean, persistent=False):
14
29
  """
15
30
  Set the specified SELinux boolean to the desired state.
16
31
 
17
32
  + boolean: name of an SELinux boolean
18
- + state: 'on' or 'off'
33
+ + value: desired state of the boolean
19
34
  + persistent: whether to write updated policy or not
20
35
 
21
36
  Note: This operation requires root privileges.
@@ -27,29 +42,31 @@ def boolean(bool_name, value, persistent=False):
27
42
  selinux.boolean(
28
43
  name='Allow Apache to connect to LDAP server',
29
44
  'httpd_can_network_connect',
30
- 'on',
45
+ Boolean.ON,
31
46
  persistent=True
32
47
  )
33
48
  """
34
- _valid_states = ["on", "off"]
35
49
 
36
- if value not in _valid_states:
37
- raise ValueError(
38
- f'\'value\' must be one of \'{",".join(_valid_states)}\' but found \'{value}\'',
39
- )
50
+ value_str: str
51
+ if value in ["on", "off"]: # compatibility with the old version
52
+ assert isinstance(value, str)
53
+ value_str = value
54
+ elif value is Boolean.ON:
55
+ value_str = "on"
56
+ elif value is Boolean.OFF:
57
+ value_str = "off"
58
+ else:
59
+ raise OperationValueError(f"Invalid value '{value}' for boolean operation")
40
60
 
41
- if host.get_fact(SEBoolean, boolean=bool_name) != value:
61
+ if host.get_fact(SEBoolean, boolean=bool_name) != value_str:
42
62
  persist = "-P " if persistent else ""
43
- yield StringCommand("setsebool", f"{persist}{bool_name}", value)
44
- host.create_fact(SEBoolean, kwargs={"boolean": bool_name}, data=value)
63
+ yield StringCommand("setsebool", f"{persist}{bool_name}", value_str)
45
64
  else:
46
- host.noop(f"boolean '{bool_name}' already had the value '{value}'")
65
+ host.noop(f"boolean '{bool_name}' already had the value '{value_str}'")
47
66
 
48
67
 
49
- @operation(
50
- pipeline_facts={"filecontext": "path"},
51
- )
52
- def file_context(path, se_type):
68
+ @operation()
69
+ def file_context(path: str, se_type: str):
53
70
  """
54
71
  Set the SELinux type for the specified path to the specified value.
55
72
 
@@ -70,19 +87,12 @@ def file_context(path, se_type):
70
87
  current = host.get_fact(FileContext, path=path) or {}
71
88
  if se_type != current.get("type", ""):
72
89
  yield StringCommand("chcon", "-t", se_type, QuoteString(path))
73
- host.create_fact(
74
- FileContext,
75
- kwargs={"path": path},
76
- data=dict(current, **{"type": se_type}),
77
- )
78
90
  else:
79
91
  host.noop(f"file_context: '{path}' already had type '{se_type}'")
80
92
 
81
93
 
82
- @operation(
83
- pipeline_facts={"filecontextmapping": "target"},
84
- )
85
- def file_context_mapping(target, se_type=None, present=True):
94
+ @operation()
95
+ def file_context_mapping(target: str, se_type: str | None = None, present=True):
86
96
  """
87
97
  Set the SELinux file context mapping for paths matching the target.
88
98
 
@@ -108,30 +118,21 @@ def file_context_mapping(target, se_type=None, present=True):
108
118
  raise ValueError("se_type must have a valid value if present is set")
109
119
 
110
120
  current = host.get_fact(FileContextMapping, target=target)
111
- kwargs = {"target": target}
112
121
  if present:
113
122
  option = "-a" if len(current) == 0 else ("-m" if current.get("type") != se_type else "")
114
123
  if option != "":
115
124
  yield StringCommand("semanage", "fcontext", option, "-t", se_type, QuoteString(target))
116
- host.create_fact(
117
- FileContextMapping,
118
- kwargs=kwargs,
119
- data=dict(current, **{"type": se_type}),
120
- )
121
125
  else:
122
126
  host.noop(f"mapping for '{target}' -> '{se_type}' already present")
123
127
  else:
124
128
  if len(current) > 0:
125
129
  yield StringCommand("semanage", "fcontext", "-d", QuoteString(target))
126
- host.create_fact(FileContextMapping, kwargs=kwargs, data={})
127
130
  else:
128
131
  host.noop(f"no existing mapping for '{target}'")
129
132
 
130
133
 
131
- @operation(
132
- pipeline_facts={"which": "sepolicy"},
133
- )
134
- def port(protocol, port_num, se_type=None, present=True):
134
+ @operation()
135
+ def port(protocol: Protocol | str, port_num: int, se_type: str | None = None, present=True):
135
136
  """
136
137
  Set the SELinux type for the specified protocol and port.
137
138
 
@@ -148,12 +149,16 @@ def port(protocol, port_num, se_type=None, present=True):
148
149
 
149
150
  selinux.port(
150
151
  name='Allow Apache to provide service on port 2222',
151
- 'tcp',
152
+ Protocol.TCP,
152
153
  2222,
153
154
  'http_port_t',
154
155
  )
155
156
  """
156
157
 
158
+ if protocol is Protocol:
159
+ assert isinstance(protocol, Protocol)
160
+ protocol = protocol.value
161
+
157
162
  if present and (se_type is None):
158
163
  raise ValueError("se_type must have a valid value if present is set")
159
164
 
@@ -178,9 +183,7 @@ def port(protocol, port_num, se_type=None, present=True):
178
183
  host.noop(f"setype for '{protocol}/{port_num}' is already unset")
179
184
 
180
185
  if (present and (option != "")) or (not present and (current != "")):
181
- if direct_get:
182
- host.create_fact(SEPort, kwargs={"protocol": protocol, "port": port_num}, data=new_type)
183
- else:
186
+ if not direct_get:
184
187
  if protocol not in port_info:
185
188
  port_info[protocol] = {}
186
189
  port_info[protocol][str(port_num)] = new_type