pyinfra 2.9.2__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.
- pyinfra/api/__init__.py +3 -0
- pyinfra/api/arguments.py +265 -253
- pyinfra/api/arguments_typed.py +80 -0
- pyinfra/api/command.py +68 -53
- pyinfra/api/config.py +139 -32
- pyinfra/api/connect.py +1 -1
- pyinfra/api/connectors.py +7 -26
- pyinfra/api/deploy.py +21 -52
- pyinfra/api/exceptions.py +33 -8
- pyinfra/api/facts.py +102 -137
- pyinfra/api/host.py +150 -82
- pyinfra/api/inventory.py +21 -25
- pyinfra/api/operation.py +240 -198
- pyinfra/api/operations.py +102 -148
- pyinfra/api/state.py +137 -79
- pyinfra/api/util.py +79 -86
- pyinfra/connectors/base.py +147 -0
- pyinfra/connectors/chroot.py +160 -169
- pyinfra/connectors/docker.py +220 -237
- pyinfra/connectors/dockerssh.py +231 -253
- pyinfra/connectors/local.py +196 -208
- pyinfra/connectors/ssh.py +530 -613
- pyinfra/connectors/ssh_util.py +114 -0
- pyinfra/connectors/sshuserclient/client.py +5 -3
- pyinfra/connectors/terraform.py +86 -65
- pyinfra/connectors/util.py +211 -137
- pyinfra/connectors/vagrant.py +60 -53
- pyinfra/context.py +4 -2
- pyinfra/facts/apk.py +2 -0
- pyinfra/facts/apt.py +2 -0
- pyinfra/facts/brew.py +2 -0
- pyinfra/facts/bsdinit.py +2 -0
- pyinfra/facts/cargo.py +2 -0
- pyinfra/facts/choco.py +2 -0
- pyinfra/facts/deb.py +7 -2
- pyinfra/facts/dnf.py +2 -0
- pyinfra/facts/docker.py +19 -0
- pyinfra/facts/files.py +47 -32
- pyinfra/facts/gem.py +2 -0
- pyinfra/facts/git.py +3 -1
- pyinfra/facts/gpg.py +3 -1
- pyinfra/facts/hardware.py +34 -24
- pyinfra/facts/iptables.py +5 -3
- pyinfra/facts/launchd.py +2 -0
- pyinfra/facts/lxd.py +2 -0
- pyinfra/facts/mysql.py +13 -6
- pyinfra/facts/npm.py +1 -0
- pyinfra/facts/openrc.py +2 -0
- pyinfra/facts/pacman.py +6 -2
- pyinfra/facts/pip.py +2 -0
- pyinfra/facts/pkg.py +2 -0
- pyinfra/facts/pkgin.py +2 -0
- pyinfra/facts/postgres.py +168 -0
- pyinfra/facts/postgresql.py +6 -160
- pyinfra/facts/rpm.py +12 -9
- pyinfra/facts/runit.py +68 -0
- pyinfra/facts/selinux.py +3 -1
- pyinfra/facts/server.py +80 -36
- pyinfra/facts/snap.py +2 -0
- pyinfra/facts/systemd.py +31 -12
- pyinfra/facts/sysvinit.py +10 -10
- pyinfra/facts/upstart.py +2 -0
- pyinfra/facts/util/packaging.py +7 -4
- pyinfra/facts/vzctl.py +2 -0
- pyinfra/facts/xbps.py +2 -0
- pyinfra/facts/yum.py +2 -0
- pyinfra/facts/zypper.py +2 -0
- pyinfra/local.py +4 -5
- pyinfra/operations/apk.py +6 -4
- pyinfra/operations/apt.py +46 -65
- pyinfra/operations/brew.py +17 -22
- pyinfra/operations/bsdinit.py +9 -7
- pyinfra/operations/cargo.py +4 -2
- pyinfra/operations/choco.py +4 -2
- pyinfra/operations/dnf.py +19 -23
- pyinfra/operations/docker.py +339 -0
- pyinfra/operations/files.py +188 -386
- pyinfra/operations/gem.py +4 -2
- pyinfra/operations/git.py +24 -53
- pyinfra/operations/iptables.py +29 -35
- pyinfra/operations/launchd.py +6 -7
- pyinfra/operations/lxd.py +8 -13
- pyinfra/operations/mysql.py +62 -81
- pyinfra/operations/npm.py +9 -2
- pyinfra/operations/openrc.py +6 -4
- pyinfra/operations/pacman.py +7 -8
- pyinfra/operations/pip.py +25 -24
- pyinfra/operations/pkg.py +4 -2
- pyinfra/operations/pkgin.py +6 -4
- pyinfra/operations/postgres.py +349 -0
- pyinfra/operations/postgresql.py +18 -379
- pyinfra/operations/puppet.py +3 -1
- pyinfra/operations/python.py +8 -19
- pyinfra/operations/runit.py +182 -0
- pyinfra/operations/selinux.py +47 -44
- pyinfra/operations/server.py +111 -127
- pyinfra/operations/snap.py +4 -4
- pyinfra/operations/ssh.py +20 -33
- pyinfra/operations/systemd.py +19 -15
- pyinfra/operations/sysvinit.py +9 -16
- pyinfra/operations/upstart.py +9 -7
- pyinfra/operations/util/__init__.py +12 -0
- pyinfra/operations/util/docker.py +177 -0
- pyinfra/operations/util/files.py +24 -16
- pyinfra/operations/util/packaging.py +55 -57
- pyinfra/operations/util/service.py +39 -51
- pyinfra/operations/vzctl.py +12 -10
- pyinfra/operations/xbps.py +6 -4
- pyinfra/operations/yum.py +18 -22
- pyinfra/operations/zypper.py +12 -13
- pyinfra/version.py +5 -2
- {pyinfra-2.9.2.dist-info → pyinfra-3.0.dist-info}/METADATA +40 -41
- pyinfra-3.0.dist-info/RECORD +167 -0
- {pyinfra-2.9.2.dist-info → pyinfra-3.0.dist-info}/WHEEL +1 -1
- pyinfra-3.0.dist-info/entry_points.txt +11 -0
- pyinfra_cli/__main__.py +4 -3
- pyinfra_cli/commands.py +7 -2
- pyinfra_cli/exceptions.py +78 -42
- pyinfra_cli/inventory.py +40 -6
- pyinfra_cli/log.py +17 -3
- pyinfra_cli/main.py +133 -90
- pyinfra_cli/prints.py +95 -127
- pyinfra_cli/util.py +62 -29
- tests/test_api/test_api.py +2 -0
- tests/test_api/test_api_arguments.py +13 -13
- tests/test_api/test_api_deploys.py +28 -29
- tests/test_api/test_api_facts.py +60 -98
- tests/test_api/test_api_operations.py +101 -201
- tests/test_cli/test_cli.py +18 -49
- tests/test_cli/test_cli_deploy.py +11 -37
- tests/test_cli/test_cli_exceptions.py +50 -19
- tests/test_cli/util.py +1 -1
- tests/test_connectors/test_chroot.py +6 -6
- tests/test_connectors/test_docker.py +4 -4
- tests/test_connectors/test_dockerssh.py +38 -50
- tests/test_connectors/test_local.py +11 -12
- tests/test_connectors/test_ssh.py +105 -93
- tests/test_connectors/test_terraform.py +9 -15
- tests/test_connectors/test_util.py +24 -46
- tests/test_connectors/test_vagrant.py +7 -7
- pyinfra/api/operation.pyi +0 -117
- pyinfra/connectors/ansible.py +0 -171
- pyinfra/connectors/mech.py +0 -186
- pyinfra/connectors/pyinfrawinrmsession/__init__.py +0 -28
- pyinfra/connectors/winrm.py +0 -320
- pyinfra/facts/windows.py +0 -366
- pyinfra/facts/windows_files.py +0 -90
- pyinfra/operations/windows.py +0 -59
- pyinfra/operations/windows_files.py +0 -551
- pyinfra-2.9.2.dist-info/RECORD +0 -170
- pyinfra-2.9.2.dist-info/entry_points.txt +0 -14
- tests/test_connectors/test_ansible.py +0 -64
- tests/test_connectors/test_mech.py +0 -126
- tests/test_connectors/test_winrm.py +0 -76
- {pyinfra-2.9.2.dist-info → pyinfra-3.0.dist-info}/LICENSE.md +0 -0
- {pyinfra-2.9.2.dist-info → pyinfra-3.0.dist-info}/top_level.txt +0 -0
pyinfra/api/operations.py
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import traceback
|
|
2
4
|
from itertools import product
|
|
3
5
|
from socket import error as socket_error, timeout as timeout_error
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
6
|
+
from typing import TYPE_CHECKING, Optional, cast
|
|
5
7
|
|
|
6
8
|
import click
|
|
7
9
|
import gevent
|
|
8
10
|
from paramiko import SSHException
|
|
9
11
|
|
|
10
|
-
import pyinfra
|
|
11
12
|
from pyinfra import logger
|
|
12
|
-
from pyinfra.
|
|
13
|
+
from pyinfra.connectors.util import CommandOutput, OutputLine
|
|
14
|
+
from pyinfra.context import ctx_host, ctx_state
|
|
13
15
|
from pyinfra.progress import progress_spinner
|
|
14
16
|
|
|
15
|
-
from .arguments import
|
|
17
|
+
from .arguments import CONNECTOR_ARGUMENT_KEYS, ConnectorArguments
|
|
16
18
|
from .command import FunctionCommand, PyinfraCommand, StringCommand
|
|
17
|
-
from .exceptions import
|
|
19
|
+
from .exceptions import PyinfraError
|
|
18
20
|
from .util import (
|
|
19
21
|
format_exception,
|
|
20
22
|
log_error_or_warning,
|
|
21
23
|
log_host_command_error,
|
|
22
24
|
log_operation_start,
|
|
23
|
-
memoize,
|
|
24
25
|
print_host_combined_output,
|
|
25
26
|
)
|
|
26
27
|
|
|
@@ -29,192 +30,153 @@ if TYPE_CHECKING:
|
|
|
29
30
|
from .state import State
|
|
30
31
|
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
logger.warning("The `{0}` argument is in beta!".format(condition_name))
|
|
33
|
+
# Run a single host operation
|
|
34
|
+
#
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
def run_host_op(state: "State", host: "Host", op_hash):
|
|
37
|
+
def run_host_op(state: "State", host: "Host", op_hash: str) -> Optional[bool]:
|
|
38
38
|
state.trigger_callbacks("operation_host_start", host, op_hash)
|
|
39
39
|
|
|
40
40
|
if op_hash not in state.ops[host]:
|
|
41
41
|
logger.info("{0}{1}".format(host.print_prefix, click.style("Skipped", "blue")))
|
|
42
42
|
return True
|
|
43
43
|
|
|
44
|
-
op_data = state.get_op_data(host, op_hash)
|
|
45
|
-
global_kwargs = op_data["global_kwargs"]
|
|
46
|
-
|
|
47
44
|
op_meta = state.get_op_meta(op_hash)
|
|
45
|
+
logger.debug("Starting operation %r on %s", op_meta.names, host)
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
executor_kwarg_keys = get_executor_kwarg_keys()
|
|
55
|
-
base_executor_kwargs = {
|
|
56
|
-
key: global_kwargs[key] for key in executor_kwarg_keys if key in global_kwargs
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
def _run_shell_command(command, executor_kwargs):
|
|
60
|
-
status = False
|
|
61
|
-
combined_output_lines = []
|
|
62
|
-
|
|
63
|
-
try:
|
|
64
|
-
status, combined_output_lines = command.execute(state, host, executor_kwargs)
|
|
65
|
-
except (timeout_error, socket_error, SSHException) as e:
|
|
66
|
-
log_host_command_error(
|
|
67
|
-
host,
|
|
68
|
-
e,
|
|
69
|
-
timeout=global_kwargs["timeout"],
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
# If we failed and have no already printed the stderr, print it
|
|
73
|
-
if status is False and not state.print_output:
|
|
74
|
-
print_host_combined_output(host, combined_output_lines)
|
|
75
|
-
|
|
76
|
-
return status, combined_output_lines
|
|
77
|
-
|
|
78
|
-
def run_condition(condition_name: str) -> bool:
|
|
79
|
-
condition_value = global_kwargs[condition_name]
|
|
80
|
-
if not condition_value:
|
|
81
|
-
return True
|
|
82
|
-
|
|
83
|
-
show_pre_or_post_condition_warning(condition_name)
|
|
47
|
+
if host.executing_op_hash is None:
|
|
48
|
+
host.executing_op_hash = op_hash
|
|
49
|
+
else:
|
|
50
|
+
host.nested_executing_op_hash = op_hash
|
|
84
51
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
52
|
+
try:
|
|
53
|
+
return _run_host_op(state, host, op_hash)
|
|
54
|
+
finally:
|
|
55
|
+
if host.nested_executing_op_hash:
|
|
56
|
+
host.nested_executing_op_hash = None
|
|
57
|
+
else:
|
|
58
|
+
host.executing_op_hash = None
|
|
89
59
|
|
|
90
|
-
if _shell_command_status:
|
|
91
|
-
return True
|
|
92
60
|
|
|
93
|
-
|
|
94
|
-
|
|
61
|
+
def _run_host_op(state: "State", host: "Host", op_hash: str) -> Optional[bool]:
|
|
62
|
+
op_data = state.get_op_data_for_host(host, op_hash)
|
|
63
|
+
global_arguments = op_data.global_arguments
|
|
95
64
|
|
|
96
|
-
|
|
97
|
-
|
|
65
|
+
ignore_errors = global_arguments["_ignore_errors"]
|
|
66
|
+
continue_on_error = global_arguments["_continue_on_error"]
|
|
67
|
+
timeout = global_arguments.get("_timeout", 0)
|
|
98
68
|
|
|
99
|
-
|
|
100
|
-
|
|
69
|
+
executor_kwarg_keys = CONNECTOR_ARGUMENT_KEYS
|
|
70
|
+
# See: https://github.com/python/mypy/issues/10371
|
|
71
|
+
base_connector_arguments: ConnectorArguments = cast(
|
|
72
|
+
ConnectorArguments,
|
|
73
|
+
{key: global_arguments[key] for key in executor_kwarg_keys if key in global_arguments}, # type: ignore[literal-required] # noqa
|
|
74
|
+
)
|
|
101
75
|
|
|
102
|
-
if not run_condition("precondition"):
|
|
103
|
-
return False
|
|
104
|
-
|
|
105
|
-
state.ops_run.add(op_hash)
|
|
106
|
-
|
|
107
|
-
if host.executing_op_hash is None:
|
|
108
|
-
host.executing_op_hash = op_hash
|
|
109
|
-
else:
|
|
110
|
-
host.nested_executing_op_hash = op_hash
|
|
111
|
-
|
|
112
|
-
return_status = False
|
|
113
76
|
did_error = False
|
|
114
77
|
executed_commands = 0
|
|
115
|
-
|
|
78
|
+
commands = []
|
|
79
|
+
all_output_lines: list[OutputLine] = []
|
|
116
80
|
|
|
117
|
-
for
|
|
118
|
-
|
|
81
|
+
for command in op_data.command_generator():
|
|
82
|
+
commands.append(command)
|
|
119
83
|
|
|
120
|
-
|
|
121
|
-
executor_kwargs.update(command.executor_kwargs)
|
|
84
|
+
status = False
|
|
122
85
|
|
|
123
|
-
|
|
124
|
-
|
|
86
|
+
connector_arguments = base_connector_arguments.copy()
|
|
87
|
+
connector_arguments.update(command.connector_arguments)
|
|
125
88
|
|
|
126
89
|
if not isinstance(command, PyinfraCommand):
|
|
127
90
|
raise TypeError("{0} is an invalid pyinfra command!".format(command))
|
|
128
91
|
|
|
129
92
|
if isinstance(command, FunctionCommand):
|
|
130
93
|
try:
|
|
131
|
-
status = command.execute(state, host,
|
|
132
|
-
except
|
|
133
|
-
|
|
134
|
-
except Exception as e: # Custom functions could do anything, so expect anything!
|
|
135
|
-
_formatted_exc = format_exception(e)
|
|
136
|
-
_error_msg = "Unexpected error in Python callback: {0}".format(_formatted_exc)
|
|
137
|
-
_error_msg_styled = click.style(_error_msg, "red")
|
|
138
|
-
_error_log = "{0}{1}".format(host.print_prefix, _error_msg_styled)
|
|
94
|
+
status = command.execute(state, host, connector_arguments)
|
|
95
|
+
except Exception as e:
|
|
96
|
+
# Custom functions could do anything, so expect anything!
|
|
139
97
|
logger.warning(traceback.format_exc())
|
|
140
|
-
|
|
98
|
+
host.log_styled(
|
|
99
|
+
f"Unexpected error in Python callback: {format_exception(e)}",
|
|
100
|
+
fg="red",
|
|
101
|
+
log_func=logger.warning,
|
|
102
|
+
)
|
|
141
103
|
|
|
142
104
|
elif isinstance(command, StringCommand):
|
|
143
|
-
|
|
144
|
-
|
|
105
|
+
output_lines = CommandOutput([])
|
|
106
|
+
try:
|
|
107
|
+
status, output_lines = command.execute(
|
|
108
|
+
state,
|
|
109
|
+
host,
|
|
110
|
+
connector_arguments,
|
|
111
|
+
)
|
|
112
|
+
except (timeout_error, socket_error, SSHException) as e:
|
|
113
|
+
log_host_command_error(host, e, timeout=timeout)
|
|
114
|
+
all_output_lines.extend(output_lines)
|
|
115
|
+
# If we failed and have not already printed the stderr, print it
|
|
116
|
+
if status is False and not state.print_output:
|
|
117
|
+
print_host_combined_output(host, output_lines)
|
|
145
118
|
|
|
146
119
|
else:
|
|
147
120
|
try:
|
|
148
|
-
status = command.execute(state, host,
|
|
121
|
+
status = command.execute(state, host, connector_arguments)
|
|
149
122
|
except (timeout_error, socket_error, SSHException, IOError) as e:
|
|
150
|
-
|
|
151
|
-
log_host_command_error(host, e, timeout=_timeout)
|
|
123
|
+
log_host_command_error(host, e, timeout=timeout)
|
|
152
124
|
|
|
153
125
|
# Break the loop to trigger a failure
|
|
154
126
|
if status is False:
|
|
127
|
+
did_error = True
|
|
155
128
|
if continue_on_error is True:
|
|
156
|
-
did_error = True
|
|
157
129
|
continue
|
|
158
130
|
break
|
|
159
131
|
|
|
160
132
|
executed_commands += 1
|
|
161
|
-
state.results[host]["commands"] += 1
|
|
162
133
|
|
|
163
|
-
#
|
|
164
|
-
|
|
165
|
-
if not run_condition("postcondition"):
|
|
166
|
-
return False
|
|
134
|
+
# Handle results
|
|
135
|
+
#
|
|
167
136
|
|
|
168
|
-
|
|
169
|
-
|
|
137
|
+
op_success = return_status = not did_error
|
|
138
|
+
host_results = state.get_results_for_host(host)
|
|
170
139
|
|
|
171
|
-
if
|
|
172
|
-
|
|
173
|
-
|
|
140
|
+
if did_error is False:
|
|
141
|
+
host_results.ops += 1
|
|
142
|
+
host_results.success_ops += 1
|
|
174
143
|
|
|
175
|
-
_status_log = "Success" if
|
|
144
|
+
_status_log = "Success" if executed_commands > 0 else "No changes"
|
|
176
145
|
_click_log_status = click.style(_status_log, "green")
|
|
177
146
|
logger.info("{0}{1}".format(host.print_prefix, _click_log_status))
|
|
178
147
|
|
|
179
|
-
# Trigger any success handler
|
|
180
|
-
if global_kwargs["on_success"]:
|
|
181
|
-
global_kwargs["on_success"](state, host, op_hash)
|
|
182
|
-
|
|
183
148
|
state.trigger_callbacks("operation_host_success", host, op_hash)
|
|
184
149
|
else:
|
|
185
150
|
if ignore_errors:
|
|
186
|
-
|
|
151
|
+
host_results.ignored_error_ops += 1
|
|
187
152
|
else:
|
|
188
|
-
|
|
153
|
+
host_results.error_ops += 1
|
|
189
154
|
|
|
190
155
|
if executed_commands:
|
|
191
|
-
|
|
156
|
+
host_results.partial_ops += 1
|
|
192
157
|
|
|
193
|
-
_command_description = f"executed {executed_commands}
|
|
158
|
+
_command_description = f"executed {executed_commands} commands"
|
|
194
159
|
log_error_or_warning(host, ignore_errors, _command_description, continue_on_error)
|
|
195
160
|
|
|
196
|
-
# Always trigger any error handler
|
|
197
|
-
if global_kwargs["on_error"]:
|
|
198
|
-
global_kwargs["on_error"](state, host, op_hash)
|
|
199
|
-
|
|
200
161
|
# Ignored, op "completes" w/ ignored error
|
|
201
162
|
if ignore_errors:
|
|
202
|
-
|
|
163
|
+
host_results.ops += 1
|
|
164
|
+
return_status = True
|
|
203
165
|
|
|
204
166
|
# Unignored error -> False
|
|
205
167
|
state.trigger_callbacks("operation_host_error", host, op_hash)
|
|
206
168
|
|
|
207
|
-
|
|
208
|
-
|
|
169
|
+
op_data.operation_meta.set_complete(
|
|
170
|
+
op_success,
|
|
171
|
+
commands,
|
|
172
|
+
CommandOutput(all_output_lines),
|
|
173
|
+
)
|
|
209
174
|
|
|
210
|
-
|
|
175
|
+
return return_status
|
|
211
176
|
|
|
212
|
-
if host.nested_executing_op_hash:
|
|
213
|
-
host.nested_executing_op_hash = None
|
|
214
|
-
else:
|
|
215
|
-
host.executing_op_hash = None
|
|
216
177
|
|
|
217
|
-
|
|
178
|
+
# Run all operations strategies
|
|
179
|
+
#
|
|
218
180
|
|
|
219
181
|
|
|
220
182
|
def _run_host_op_with_context(state: "State", host: "Host", op_hash: str):
|
|
@@ -242,14 +204,11 @@ def _run_host_ops(state: "State", host: "Host", progress=None):
|
|
|
242
204
|
if result is False:
|
|
243
205
|
raise PyinfraError(
|
|
244
206
|
"Error in operation {0} on {1}".format(
|
|
245
|
-
", ".join(op_meta
|
|
207
|
+
", ".join(op_meta.names),
|
|
246
208
|
host,
|
|
247
209
|
),
|
|
248
210
|
)
|
|
249
211
|
|
|
250
|
-
if pyinfra.is_cli:
|
|
251
|
-
click.echo(err=True)
|
|
252
|
-
|
|
253
212
|
|
|
254
213
|
def _run_serial_ops(state: "State"):
|
|
255
214
|
"""
|
|
@@ -303,7 +262,7 @@ def _run_single_op(state: "State", op_hash: str):
|
|
|
303
262
|
|
|
304
263
|
failed_hosts = set()
|
|
305
264
|
|
|
306
|
-
if op_meta["
|
|
265
|
+
if op_meta.global_arguments["_serial"]:
|
|
307
266
|
with progress_spinner(state.inventory.iter_active_hosts()) as progress:
|
|
308
267
|
# For each host, run the op
|
|
309
268
|
for host in state.inventory.iter_active_hosts():
|
|
@@ -318,10 +277,9 @@ def _run_single_op(state: "State", op_hash: str):
|
|
|
318
277
|
batches = [list(state.inventory.iter_active_hosts())]
|
|
319
278
|
|
|
320
279
|
# If parallel set break up the inventory into a series of batches
|
|
321
|
-
|
|
322
|
-
|
|
280
|
+
parallel = op_meta.global_arguments["_parallel"]
|
|
281
|
+
if parallel:
|
|
323
282
|
hosts = list(state.inventory.iter_active_hosts())
|
|
324
|
-
|
|
325
283
|
batches = [hosts[i : i + parallel] for i in range(0, len(hosts), parallel)]
|
|
326
284
|
|
|
327
285
|
for batch in batches:
|
|
@@ -347,9 +305,6 @@ def _run_single_op(state: "State", op_hash: str):
|
|
|
347
305
|
# Now all the batches/hosts are complete, fail any failures
|
|
348
306
|
state.fail_hosts(failed_hosts)
|
|
349
307
|
|
|
350
|
-
if pyinfra.is_cli:
|
|
351
|
-
click.echo(err=True)
|
|
352
|
-
|
|
353
308
|
state.trigger_callbacks("operation_end", op_hash)
|
|
354
309
|
|
|
355
310
|
|
|
@@ -366,15 +321,14 @@ def run_ops(state: "State", serial: bool = False, no_wait: bool = False):
|
|
|
366
321
|
# Flag state as deploy in process
|
|
367
322
|
state.is_executing = True
|
|
368
323
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
_run_single_op(state, op_hash)
|
|
324
|
+
with ctx_state.use(state):
|
|
325
|
+
# Run all ops, but server by server
|
|
326
|
+
if serial:
|
|
327
|
+
_run_serial_ops(state)
|
|
328
|
+
# Run all the ops on each server in parallel (not waiting at each operation)
|
|
329
|
+
elif no_wait:
|
|
330
|
+
_run_no_wait_ops(state)
|
|
331
|
+
# Default: run all ops in order, waiting at each for all servers to complete
|
|
332
|
+
else:
|
|
333
|
+
for op_hash in state.get_op_order():
|
|
334
|
+
_run_single_op(state, op_hash)
|