pyinfra 2.9.2__py2.py3-none-any.whl → 3.0b1__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 +261 -255
- pyinfra/api/arguments_typed.py +77 -0
- pyinfra/api/command.py +66 -53
- pyinfra/api/config.py +27 -22
- pyinfra/api/connect.py +1 -1
- pyinfra/api/connectors.py +2 -24
- pyinfra/api/deploy.py +21 -52
- pyinfra/api/exceptions.py +33 -8
- pyinfra/api/facts.py +77 -113
- pyinfra/api/host.py +150 -82
- pyinfra/api/inventory.py +17 -25
- pyinfra/api/operation.py +232 -198
- pyinfra/api/operations.py +102 -148
- pyinfra/api/state.py +137 -79
- pyinfra/api/util.py +55 -70
- pyinfra/connectors/base.py +150 -0
- pyinfra/connectors/chroot.py +160 -169
- pyinfra/connectors/docker.py +227 -237
- pyinfra/connectors/dockerssh.py +231 -253
- pyinfra/connectors/local.py +195 -207
- pyinfra/connectors/ssh.py +528 -615
- pyinfra/connectors/ssh_util.py +114 -0
- pyinfra/connectors/sshuserclient/client.py +5 -3
- pyinfra/connectors/terraform.py +86 -65
- pyinfra/connectors/util.py +212 -137
- pyinfra/connectors/vagrant.py +55 -48
- pyinfra/context.py +3 -2
- pyinfra/facts/docker.py +1 -0
- pyinfra/facts/files.py +45 -32
- pyinfra/facts/git.py +3 -1
- pyinfra/facts/gpg.py +1 -1
- pyinfra/facts/hardware.py +4 -2
- pyinfra/facts/iptables.py +5 -3
- pyinfra/facts/mysql.py +1 -0
- pyinfra/facts/postgres.py +168 -0
- pyinfra/facts/postgresql.py +5 -161
- pyinfra/facts/selinux.py +3 -1
- pyinfra/facts/server.py +77 -30
- pyinfra/facts/systemd.py +29 -12
- pyinfra/facts/sysvinit.py +10 -10
- pyinfra/facts/util/packaging.py +4 -2
- pyinfra/local.py +4 -5
- pyinfra/operations/apk.py +3 -3
- pyinfra/operations/apt.py +25 -47
- pyinfra/operations/brew.py +7 -14
- pyinfra/operations/bsdinit.py +4 -4
- pyinfra/operations/cargo.py +1 -1
- pyinfra/operations/choco.py +1 -1
- pyinfra/operations/dnf.py +4 -4
- pyinfra/operations/files.py +108 -321
- pyinfra/operations/gem.py +1 -1
- pyinfra/operations/git.py +6 -37
- pyinfra/operations/iptables.py +2 -10
- pyinfra/operations/launchd.py +1 -1
- pyinfra/operations/lxd.py +1 -9
- pyinfra/operations/mysql.py +5 -28
- pyinfra/operations/npm.py +1 -1
- pyinfra/operations/openrc.py +1 -1
- pyinfra/operations/pacman.py +3 -3
- pyinfra/operations/pip.py +14 -15
- pyinfra/operations/pkg.py +1 -1
- pyinfra/operations/pkgin.py +3 -3
- pyinfra/operations/postgres.py +347 -0
- pyinfra/operations/postgresql.py +17 -380
- pyinfra/operations/python.py +2 -17
- pyinfra/operations/selinux.py +5 -28
- pyinfra/operations/server.py +59 -84
- pyinfra/operations/snap.py +1 -3
- pyinfra/operations/ssh.py +8 -23
- pyinfra/operations/systemd.py +7 -7
- pyinfra/operations/sysvinit.py +3 -12
- pyinfra/operations/upstart.py +4 -4
- pyinfra/operations/util/__init__.py +12 -0
- pyinfra/operations/util/files.py +2 -2
- pyinfra/operations/util/packaging.py +6 -24
- pyinfra/operations/util/service.py +18 -37
- pyinfra/operations/vzctl.py +2 -2
- pyinfra/operations/xbps.py +3 -3
- pyinfra/operations/yum.py +4 -4
- pyinfra/operations/zypper.py +4 -4
- {pyinfra-2.9.2.dist-info → pyinfra-3.0b1.dist-info}/METADATA +19 -22
- pyinfra-3.0b1.dist-info/RECORD +163 -0
- pyinfra-3.0b1.dist-info/entry_points.txt +11 -0
- pyinfra_cli/__main__.py +2 -0
- pyinfra_cli/commands.py +7 -2
- pyinfra_cli/exceptions.py +83 -42
- pyinfra_cli/inventory.py +19 -4
- pyinfra_cli/log.py +17 -3
- pyinfra_cli/main.py +133 -90
- pyinfra_cli/prints.py +93 -129
- pyinfra_cli/util.py +60 -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 +100 -200
- 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 +66 -107
- tests/test_connectors/test_terraform.py +9 -15
- tests/test_connectors/test_util.py +24 -46
- tests/test_connectors/test_vagrant.py +4 -4
- 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.0b1.dist-info}/LICENSE.md +0 -0
- {pyinfra-2.9.2.dist-info → pyinfra-3.0b1.dist-info}/WHEEL +0 -0
- {pyinfra-2.9.2.dist-info → pyinfra-3.0b1.dist-info}/top_level.txt +0 -0
pyinfra/connectors/winrm.py
DELETED
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
.. warning::
|
|
3
|
-
This connector is in alpha and may change in future releases.
|
|
4
|
-
|
|
5
|
-
Some Windows facts and Windows operations work but this is to be considered
|
|
6
|
-
experimental. For now, only ``winrm_username`` and ``winrm_password`` is
|
|
7
|
-
being used. There are other methods for authentication, but they have not yet
|
|
8
|
-
been added/experimented with.
|
|
9
|
-
|
|
10
|
-
The ``@winrm`` connector can be used to communicate with Windows instances that have WinRM enabled.
|
|
11
|
-
|
|
12
|
-
Examples using ``@winrm``:
|
|
13
|
-
|
|
14
|
-
.. code:: python
|
|
15
|
-
|
|
16
|
-
# Get the windows_home fact
|
|
17
|
-
pyinfra @winrm/192.168.3.232 --winrm-username vagrant \\
|
|
18
|
-
--winrm-password vagrant --winrm-port 5985 -vv --debug fact windows_home
|
|
19
|
-
|
|
20
|
-
# Create a directory
|
|
21
|
-
pyinfra @winrm/192.168.3.232 --winrm-username vagrant \\
|
|
22
|
-
--winrm-password vagrant --winrm-port 5985 windows_files.windows_directory 'c:\temp'
|
|
23
|
-
|
|
24
|
-
# Run a powershell command ('ps' is the default shell-executable for the winrm connector)
|
|
25
|
-
pyinfra @winrm/192.168.3.232 --winrm-username vagrant \\
|
|
26
|
-
--winrm-password vagrant --winrm-port 5985 exec -- write-host hello
|
|
27
|
-
|
|
28
|
-
# Run a command using the command prompt:
|
|
29
|
-
pyinfra @winrm/192.168.3.232 --winrm-username vagrant \\
|
|
30
|
-
--winrm-password vagrant --winrm-port 5985 --shell-executable cmd exec -- date /T
|
|
31
|
-
|
|
32
|
-
# Run a command using the winrm ntlm transport
|
|
33
|
-
pyinfra @winrm/192.168.3.232 --winrm-username vagrant \\
|
|
34
|
-
--winrm-password vagrant --winrm-port 5985 --winrm-transport ntlm exec -- hostname
|
|
35
|
-
"""
|
|
36
|
-
|
|
37
|
-
import base64
|
|
38
|
-
import ntpath
|
|
39
|
-
|
|
40
|
-
import click
|
|
41
|
-
|
|
42
|
-
from pyinfra import logger
|
|
43
|
-
from pyinfra.api.connectors import BaseConnectorMeta
|
|
44
|
-
from pyinfra.api.exceptions import ConnectError, PyinfraError
|
|
45
|
-
from pyinfra.api.util import get_file_io, memoize, sha1_hash
|
|
46
|
-
|
|
47
|
-
from .pyinfrawinrmsession import PyinfraWinrmSession
|
|
48
|
-
from .util import make_win_command
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class Meta(BaseConnectorMeta):
|
|
52
|
-
handles_execution = True
|
|
53
|
-
keys_prefix = "winrm"
|
|
54
|
-
|
|
55
|
-
class DataKeys:
|
|
56
|
-
hostname = "WinRM hostname to connect to"
|
|
57
|
-
port = "WinRM port to connect to"
|
|
58
|
-
user = "WinRM username"
|
|
59
|
-
password = "WinRM password"
|
|
60
|
-
transport = "WinRM transport (default: ``plaintext``)"
|
|
61
|
-
read_timeout_sec = "Read timeout in seconds (default: ``30``)"
|
|
62
|
-
operation_timeout_sec = "Operation timeout in seconds (default: ``20``)"
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
DATA_KEYS = Meta.keys()
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def _raise_connect_error(host, message, data):
|
|
69
|
-
message = "{0} ({1})".format(message, data)
|
|
70
|
-
raise ConnectError(message)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
@memoize
|
|
74
|
-
def show_warning():
|
|
75
|
-
logger.warning("The @winrm connector is alpha!")
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def _make_winrm_kwargs(state, host):
|
|
79
|
-
kwargs = {}
|
|
80
|
-
|
|
81
|
-
for key, value in (
|
|
82
|
-
("username", host.data.get(DATA_KEYS.user)),
|
|
83
|
-
("password", host.data.get(DATA_KEYS.password)),
|
|
84
|
-
("winrm_port", int(host.data.get(DATA_KEYS.port, 0))),
|
|
85
|
-
("winrm_transport", host.data.get(DATA_KEYS.transport, "plaintext")),
|
|
86
|
-
(
|
|
87
|
-
"winrm_read_timeout_sec",
|
|
88
|
-
host.data.get(DATA_KEYS.read_timeout_sec, 30),
|
|
89
|
-
),
|
|
90
|
-
(
|
|
91
|
-
"winrm_operation_timeout_sec",
|
|
92
|
-
host.data.get(DATA_KEYS.operation_timeout_sec, 20),
|
|
93
|
-
),
|
|
94
|
-
):
|
|
95
|
-
if value:
|
|
96
|
-
kwargs[key] = value
|
|
97
|
-
|
|
98
|
-
# FUTURE: add more auth
|
|
99
|
-
# pywinrm supports: basic, certificate, ntlm, kerberos, plaintext, ssl, credssp
|
|
100
|
-
# see https://github.com/diyan/pywinrm/blob/master/winrm/__init__.py#L12
|
|
101
|
-
|
|
102
|
-
return kwargs
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
def make_names_data(hostname):
|
|
106
|
-
|
|
107
|
-
show_warning()
|
|
108
|
-
|
|
109
|
-
yield "@winrm/{0}".format(hostname), {"winrm_hostname": hostname}, []
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def connect(state, host):
|
|
113
|
-
"""
|
|
114
|
-
Connect to a single host. Returns the winrm Session if successful.
|
|
115
|
-
"""
|
|
116
|
-
|
|
117
|
-
kwargs = _make_winrm_kwargs(state, host)
|
|
118
|
-
logger.debug("Connecting to: %s (%s)", host.name, kwargs)
|
|
119
|
-
|
|
120
|
-
# Hostname can be provided via winrm config (alias), data, or the hosts name
|
|
121
|
-
hostname = kwargs.pop(
|
|
122
|
-
"hostname",
|
|
123
|
-
host.data.get(DATA_KEYS.hostname, host.name),
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
try:
|
|
127
|
-
# Create new session
|
|
128
|
-
host_and_port = "{}:{}".format(hostname, host.data.get(DATA_KEYS.port))
|
|
129
|
-
logger.debug("host_and_port: %s", host_and_port)
|
|
130
|
-
|
|
131
|
-
session = PyinfraWinrmSession(
|
|
132
|
-
host_and_port,
|
|
133
|
-
auth=(
|
|
134
|
-
kwargs["username"],
|
|
135
|
-
kwargs["password"],
|
|
136
|
-
),
|
|
137
|
-
transport=kwargs["winrm_transport"],
|
|
138
|
-
read_timeout_sec=kwargs["winrm_read_timeout_sec"],
|
|
139
|
-
operation_timeout_sec=kwargs["winrm_operation_timeout_sec"],
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
return session
|
|
143
|
-
|
|
144
|
-
# TODO: add exceptions here
|
|
145
|
-
except Exception as e:
|
|
146
|
-
auth_kwargs = {}
|
|
147
|
-
|
|
148
|
-
for key, value in kwargs.items():
|
|
149
|
-
if key in ("username", "password"):
|
|
150
|
-
auth_kwargs[key] = value
|
|
151
|
-
|
|
152
|
-
auth_args = ", ".join("{0}={1}".format(key, value) for key, value in auth_kwargs.items())
|
|
153
|
-
logger.debug("%s", e)
|
|
154
|
-
_raise_connect_error(host, "Authentication error", auth_args)
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
def run_shell_command(
|
|
158
|
-
state,
|
|
159
|
-
host,
|
|
160
|
-
command,
|
|
161
|
-
env=None,
|
|
162
|
-
success_exit_codes=None,
|
|
163
|
-
print_output=False,
|
|
164
|
-
print_input=False,
|
|
165
|
-
return_combined_output=False,
|
|
166
|
-
shell_executable=None,
|
|
167
|
-
**ignored_command_kwargs,
|
|
168
|
-
):
|
|
169
|
-
"""
|
|
170
|
-
Execute a command on the specified host.
|
|
171
|
-
|
|
172
|
-
Args:
|
|
173
|
-
state (``pyinfra.api.State`` obj): state object for this command
|
|
174
|
-
hostname (string): hostname of the target
|
|
175
|
-
command (string): actual command to execute
|
|
176
|
-
success_exit_codes (list): all values in the list that will return success
|
|
177
|
-
print_output (boolean): print the output
|
|
178
|
-
print_intput (boolean): print the input
|
|
179
|
-
return_combined_output (boolean): combine the stdout and stderr lists
|
|
180
|
-
shell_executable (string): shell to use - 'cmd'=cmd, 'ps'=powershell(default)
|
|
181
|
-
env (dict): environment variables to set
|
|
182
|
-
|
|
183
|
-
Returns:
|
|
184
|
-
tuple: (exit_code, stdout, stderr)
|
|
185
|
-
stdout and stderr are both lists of strings from each buffer.
|
|
186
|
-
"""
|
|
187
|
-
|
|
188
|
-
command = make_win_command(command)
|
|
189
|
-
|
|
190
|
-
logger.debug("Running command on %s: %s", host.name, command)
|
|
191
|
-
|
|
192
|
-
if print_input:
|
|
193
|
-
click.echo("{0}>>> {1}".format(host.print_prefix, command), err=True)
|
|
194
|
-
|
|
195
|
-
# get rid of leading/trailing quote
|
|
196
|
-
tmp_command = command.strip("'")
|
|
197
|
-
|
|
198
|
-
if print_output:
|
|
199
|
-
click.echo(
|
|
200
|
-
"{0}>>> {1}".format(host.print_prefix, command),
|
|
201
|
-
err=True,
|
|
202
|
-
)
|
|
203
|
-
|
|
204
|
-
if not shell_executable:
|
|
205
|
-
shell_executable = "ps"
|
|
206
|
-
logger.debug("shell_executable:%s", shell_executable)
|
|
207
|
-
|
|
208
|
-
# we use our own subclassed session that allows for env setting from open_shell.
|
|
209
|
-
if shell_executable in ["cmd"]:
|
|
210
|
-
response = host.connection.run_cmd(tmp_command, env=env)
|
|
211
|
-
else:
|
|
212
|
-
response = host.connection.run_ps(tmp_command, env=env)
|
|
213
|
-
|
|
214
|
-
return_code = response.status_code
|
|
215
|
-
logger.debug("response:%s", response)
|
|
216
|
-
|
|
217
|
-
std_out_str = response.std_out.decode("utf-8")
|
|
218
|
-
std_err_str = response.std_err.decode("utf-8")
|
|
219
|
-
|
|
220
|
-
# split on '\r\n' (windows newlines)
|
|
221
|
-
std_out = std_out_str.split("\r\n")
|
|
222
|
-
std_err = std_err_str.split("\r\n")
|
|
223
|
-
|
|
224
|
-
logger.debug("std_out:%s", std_out)
|
|
225
|
-
logger.debug("std_err:%s", std_err)
|
|
226
|
-
|
|
227
|
-
if print_output:
|
|
228
|
-
click.echo(
|
|
229
|
-
"{0}>>> {1}".format(host.print_prefix, "\n".join(std_out)),
|
|
230
|
-
err=True,
|
|
231
|
-
)
|
|
232
|
-
|
|
233
|
-
if success_exit_codes:
|
|
234
|
-
status = return_code in success_exit_codes
|
|
235
|
-
else:
|
|
236
|
-
status = return_code == 0
|
|
237
|
-
|
|
238
|
-
logger.debug("Command exit status: %s", status)
|
|
239
|
-
|
|
240
|
-
if return_combined_output:
|
|
241
|
-
std_out = [("stdout", line) for line in std_out]
|
|
242
|
-
std_err = [("stderr", line) for line in std_err]
|
|
243
|
-
return status, std_out + std_err
|
|
244
|
-
|
|
245
|
-
return status, std_out, std_err
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
def get_file(
|
|
249
|
-
state, host, remote_filename, filename_or_io, remote_temp_filename=None, **command_kwargs
|
|
250
|
-
):
|
|
251
|
-
raise PyinfraError("Not implemented")
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
def _put_file(state, host, filename_or_io, remote_location, chunk_size=2048):
|
|
255
|
-
# this should work fine on smallish files, but there will be perf issues
|
|
256
|
-
# on larger files both due to the full read, the base64 encoding, and
|
|
257
|
-
# the latency when sending chunks
|
|
258
|
-
with get_file_io(filename_or_io) as file_io:
|
|
259
|
-
data = file_io.read()
|
|
260
|
-
for i in range(0, len(data), chunk_size):
|
|
261
|
-
chunk = data[i : i + chunk_size]
|
|
262
|
-
ps = (
|
|
263
|
-
'$data = [System.Convert]::FromBase64String("{0}"); '
|
|
264
|
-
'{1} -Value $data -Encoding byte -Path "{2}"'
|
|
265
|
-
).format(
|
|
266
|
-
base64.b64encode(chunk).decode("utf-8"),
|
|
267
|
-
"Set-Content" if i == 0 else "Add-Content",
|
|
268
|
-
remote_location,
|
|
269
|
-
)
|
|
270
|
-
status, _stdout, stderr = run_shell_command(state, host, ps)
|
|
271
|
-
if status is False:
|
|
272
|
-
logger.error("File upload error: {0}".format("\n".join(stderr)))
|
|
273
|
-
return False
|
|
274
|
-
|
|
275
|
-
return True
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
def put_file(
|
|
279
|
-
state,
|
|
280
|
-
host,
|
|
281
|
-
filename_or_io,
|
|
282
|
-
remote_filename,
|
|
283
|
-
print_output=False,
|
|
284
|
-
print_input=False,
|
|
285
|
-
remote_temp_filename=None, # ignored
|
|
286
|
-
**command_kwargs,
|
|
287
|
-
):
|
|
288
|
-
"""
|
|
289
|
-
Upload file by chunking and sending base64 encoded via winrm
|
|
290
|
-
"""
|
|
291
|
-
|
|
292
|
-
# TODO: fix this? Workaround for circular import
|
|
293
|
-
from pyinfra.facts.windows_files import TempDir
|
|
294
|
-
|
|
295
|
-
# Always use temp file here in case of failure
|
|
296
|
-
temp_file = ntpath.join(
|
|
297
|
-
host.get_fact(TempDir),
|
|
298
|
-
"pyinfra-{0}".format(sha1_hash(remote_filename)),
|
|
299
|
-
)
|
|
300
|
-
|
|
301
|
-
if not _put_file(state, host, filename_or_io, temp_file):
|
|
302
|
-
return False
|
|
303
|
-
|
|
304
|
-
# Execute run_shell_command w/sudo and/or su_user
|
|
305
|
-
command = "Move-Item -Path {0} -Destination {1} -Force".format(temp_file, remote_filename)
|
|
306
|
-
status, _, stderr = run_shell_command(
|
|
307
|
-
state, host, command, print_output=print_output, print_input=print_input, **command_kwargs
|
|
308
|
-
)
|
|
309
|
-
|
|
310
|
-
if status is False:
|
|
311
|
-
logger.error("File upload error: {0}".format("\n".join(stderr)))
|
|
312
|
-
return False
|
|
313
|
-
|
|
314
|
-
if print_output:
|
|
315
|
-
click.echo(
|
|
316
|
-
"{0}file uploaded: {1}".format(host.print_prefix, remote_filename),
|
|
317
|
-
err=True,
|
|
318
|
-
)
|
|
319
|
-
|
|
320
|
-
return True
|
pyinfra/facts/windows.py
DELETED
|
@@ -1,366 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
from datetime import datetime
|
|
3
|
-
|
|
4
|
-
from dateutil.parser import parse as parse_date
|
|
5
|
-
|
|
6
|
-
from pyinfra.api import FactBase
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class Home(FactBase):
|
|
10
|
-
"""
|
|
11
|
-
Returns the home directory of the current user.
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
command = "echo %HOMEPATH%"
|
|
15
|
-
shell_executable = "cmd"
|
|
16
|
-
|
|
17
|
-
@staticmethod
|
|
18
|
-
def process(output):
|
|
19
|
-
return "".join(output).replace("\n", "")
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class Hostname(FactBase):
|
|
23
|
-
"""
|
|
24
|
-
Returns the current hostname of the server.
|
|
25
|
-
"""
|
|
26
|
-
|
|
27
|
-
command = "hostname"
|
|
28
|
-
|
|
29
|
-
@staticmethod
|
|
30
|
-
def process(output):
|
|
31
|
-
return "".join(output).replace("\n", "")
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class LastReboot(FactBase):
|
|
35
|
-
"""
|
|
36
|
-
Returns the date and time of the last reboot.
|
|
37
|
-
"""
|
|
38
|
-
|
|
39
|
-
command = (
|
|
40
|
-
"Get-CimInstance -ClassName Win32_OperatingSystem | "
|
|
41
|
-
"Select -ExpandProperty LastBootUptime"
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
@staticmethod
|
|
45
|
-
def process(output):
|
|
46
|
-
return "".join(output).replace("\n", "")
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
class Os(FactBase):
|
|
50
|
-
"""
|
|
51
|
-
Returns the OS name according to ``systeminfo``.
|
|
52
|
-
"""
|
|
53
|
-
|
|
54
|
-
command = 'systeminfo.exe | findstr /c:"OS Name:"'
|
|
55
|
-
|
|
56
|
-
@staticmethod
|
|
57
|
-
def process(output):
|
|
58
|
-
new_output = ""
|
|
59
|
-
match = re.match("OS Name:[ ]*(.*)", output[0])
|
|
60
|
-
if match:
|
|
61
|
-
new_output = match.group(1)
|
|
62
|
-
return new_output
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
class Bios(FactBase):
|
|
66
|
-
"""
|
|
67
|
-
Returns the BIOS info.
|
|
68
|
-
"""
|
|
69
|
-
|
|
70
|
-
command = "Get-CimInstance -ClassName Win32_BIOS"
|
|
71
|
-
|
|
72
|
-
@staticmethod
|
|
73
|
-
def process(output):
|
|
74
|
-
bios = {}
|
|
75
|
-
for line in output:
|
|
76
|
-
line_data = line.split(":")
|
|
77
|
-
if len(line_data) > 1:
|
|
78
|
-
bios.update({line_data[0].strip(): line_data[1].strip()})
|
|
79
|
-
return bios
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def _format_windows(output):
|
|
83
|
-
lines = {}
|
|
84
|
-
for line in output:
|
|
85
|
-
# split line on ':'
|
|
86
|
-
line_data = line.split(":")
|
|
87
|
-
if len(line_data) > 1:
|
|
88
|
-
# we have a data line
|
|
89
|
-
this_key = line_data[0].strip()
|
|
90
|
-
this_data = line_data[1].strip()
|
|
91
|
-
if len(line_data) > 2:
|
|
92
|
-
# there was a ':' in the data, so reconstitute the value
|
|
93
|
-
this_data = ":".join(line_data[1:]).strip()
|
|
94
|
-
lines[this_key] = this_data
|
|
95
|
-
return lines
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
def _format_windows_for_key(primary_key, output, return_primary_key=True):
|
|
99
|
-
"""Format the windows powershell output that uses 'Format-Line'
|
|
100
|
-
into a dict of dicts.
|
|
101
|
-
"""
|
|
102
|
-
primary_key = primary_key.strip()
|
|
103
|
-
lines = {}
|
|
104
|
-
one_item = {}
|
|
105
|
-
key_value = ""
|
|
106
|
-
for line in output:
|
|
107
|
-
# split line on ':'
|
|
108
|
-
line_data = line.split(":")
|
|
109
|
-
if len(line_data) > 1:
|
|
110
|
-
# we have a data line
|
|
111
|
-
this_key = line_data[0].strip()
|
|
112
|
-
this_data = line_data[1].strip()
|
|
113
|
-
if len(line_data) > 2:
|
|
114
|
-
# there was a ':' in the data, so reconstitute the value
|
|
115
|
-
this_data = ":".join(line_data[1:]).strip()
|
|
116
|
-
if this_key != primary_key:
|
|
117
|
-
one_item.update({this_key: this_data})
|
|
118
|
-
else:
|
|
119
|
-
key_value = this_data
|
|
120
|
-
else:
|
|
121
|
-
if line == "":
|
|
122
|
-
if one_item:
|
|
123
|
-
lines[key_value] = one_item
|
|
124
|
-
one_item = {}
|
|
125
|
-
key_value = ""
|
|
126
|
-
else:
|
|
127
|
-
# append this_data to the existing entry
|
|
128
|
-
this_data = line.strip()
|
|
129
|
-
appended_data = one_item[this_key] + this_data
|
|
130
|
-
one_item.update({this_key: appended_data})
|
|
131
|
-
if return_primary_key:
|
|
132
|
-
return {primary_key: lines}
|
|
133
|
-
return lines
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
class Processors(FactBase):
|
|
137
|
-
"""
|
|
138
|
-
Returns the processors info.
|
|
139
|
-
"""
|
|
140
|
-
|
|
141
|
-
command = "Get-CimInstance -ClassName Win32_Processor | Format-List -Property *"
|
|
142
|
-
|
|
143
|
-
@staticmethod
|
|
144
|
-
def process(output):
|
|
145
|
-
return _format_windows_for_key("DeviceID", output)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
class OsVersion(FactBase):
|
|
149
|
-
"""
|
|
150
|
-
Returns the OS version according to ``systeminfo``.
|
|
151
|
-
"""
|
|
152
|
-
|
|
153
|
-
command = 'systeminfo | findstr /c:"OS Version:"'
|
|
154
|
-
|
|
155
|
-
@staticmethod
|
|
156
|
-
def process(output):
|
|
157
|
-
new_output = ""
|
|
158
|
-
match = re.match("OS Version:[ ]*(.*)", output[0])
|
|
159
|
-
if match:
|
|
160
|
-
new_output = match.group(1)
|
|
161
|
-
return new_output
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
class SystemType(FactBase):
|
|
165
|
-
"""
|
|
166
|
-
Returns the system type according to ``systeminfo``.
|
|
167
|
-
"""
|
|
168
|
-
|
|
169
|
-
command = 'systeminfo | findstr /c:"System Type:"'
|
|
170
|
-
|
|
171
|
-
@staticmethod
|
|
172
|
-
def process(output):
|
|
173
|
-
new_output = ""
|
|
174
|
-
match = re.match("System Type:[ ]*(.*)", output[0])
|
|
175
|
-
if match:
|
|
176
|
-
new_output = match.group(1)
|
|
177
|
-
return new_output
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
class Date(FactBase):
|
|
181
|
-
"""
|
|
182
|
-
Returns the current datetime on the server.
|
|
183
|
-
"""
|
|
184
|
-
|
|
185
|
-
command = "echo %date%-%time%"
|
|
186
|
-
shell_executable = "cmd"
|
|
187
|
-
default = datetime.now
|
|
188
|
-
|
|
189
|
-
@staticmethod
|
|
190
|
-
def process(output):
|
|
191
|
-
new_output = "".join(output)
|
|
192
|
-
return parse_date(new_output)
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
class LocalGroups(FactBase):
|
|
196
|
-
"""
|
|
197
|
-
Returns a list of groups on the system.
|
|
198
|
-
"""
|
|
199
|
-
|
|
200
|
-
command = "net localgroup | findstr [^*]"
|
|
201
|
-
|
|
202
|
-
default = list
|
|
203
|
-
|
|
204
|
-
@staticmethod
|
|
205
|
-
def process(output):
|
|
206
|
-
groups = []
|
|
207
|
-
for group in output:
|
|
208
|
-
# Note: If run this command thru ps, there are headers/footer.
|
|
209
|
-
# remove empty groups and those groups that are not local
|
|
210
|
-
if group != "" and group[0] == "*":
|
|
211
|
-
groups.append(group)
|
|
212
|
-
return groups
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
class Where(FactBase):
|
|
216
|
-
"""
|
|
217
|
-
Returns the full path for a command, if available.
|
|
218
|
-
"""
|
|
219
|
-
|
|
220
|
-
shell_executable = "cmd"
|
|
221
|
-
|
|
222
|
-
@staticmethod
|
|
223
|
-
def command(name):
|
|
224
|
-
return "where {0}".format(name)
|
|
225
|
-
|
|
226
|
-
@staticmethod
|
|
227
|
-
def process(output):
|
|
228
|
-
return output[0].rstrip()
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
class Hotfixes(FactBase):
|
|
232
|
-
"""
|
|
233
|
-
Returns the Windows hotfixes.
|
|
234
|
-
"""
|
|
235
|
-
|
|
236
|
-
command = "Get-CimInstance -ClassName Win32_QuickFixEngineering | Format-List -Property *"
|
|
237
|
-
|
|
238
|
-
@staticmethod
|
|
239
|
-
def process(output):
|
|
240
|
-
return _format_windows_for_key("HotFixID", output)
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
class LocalDrivesInfo(FactBase):
|
|
244
|
-
"""
|
|
245
|
-
Returns the Windows local drives info.
|
|
246
|
-
"""
|
|
247
|
-
|
|
248
|
-
command = (
|
|
249
|
-
'Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3" '
|
|
250
|
-
"| Format-List -Property *"
|
|
251
|
-
)
|
|
252
|
-
|
|
253
|
-
@staticmethod
|
|
254
|
-
def process(output):
|
|
255
|
-
return _format_windows_for_key("DeviceID", output)
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
class LoggedInUserInfo(FactBase):
|
|
259
|
-
"""
|
|
260
|
-
Returns the Windows user logged in info.
|
|
261
|
-
"""
|
|
262
|
-
|
|
263
|
-
command = (
|
|
264
|
-
"Get-CimInstance -ClassName Win32_ComputerSystem -Property UserName "
|
|
265
|
-
"| Format-List -Property *"
|
|
266
|
-
)
|
|
267
|
-
|
|
268
|
-
@staticmethod
|
|
269
|
-
def process(output):
|
|
270
|
-
return _format_windows_for_key("Name", output)
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
class LogonSessionInfo(FactBase):
|
|
274
|
-
"""
|
|
275
|
-
Returns the Windows user logon session info.
|
|
276
|
-
"""
|
|
277
|
-
|
|
278
|
-
command = "Get-CimInstance -ClassName Win32_LogonSession | Format-List -Property *"
|
|
279
|
-
|
|
280
|
-
@staticmethod
|
|
281
|
-
def process(output):
|
|
282
|
-
return _format_windows_for_key("LogonId", output)
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
class Aliases(FactBase):
|
|
286
|
-
"""
|
|
287
|
-
Returns the Windows aliases.
|
|
288
|
-
"""
|
|
289
|
-
|
|
290
|
-
command = "Get-Alias | Format-List -Property *"
|
|
291
|
-
|
|
292
|
-
@staticmethod
|
|
293
|
-
def process(output):
|
|
294
|
-
return _format_windows_for_key("Name", output)
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
class Services(FactBase):
|
|
298
|
-
"""
|
|
299
|
-
Returns the Windows services.
|
|
300
|
-
"""
|
|
301
|
-
|
|
302
|
-
command = "Get-CimInstance -ClassName Win32_Service | Format-List -Property *"
|
|
303
|
-
|
|
304
|
-
@staticmethod
|
|
305
|
-
def process(output):
|
|
306
|
-
return _format_windows_for_key("Name", output)
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
class Service(FactBase):
|
|
310
|
-
"""
|
|
311
|
-
Returns info about a Windows service.
|
|
312
|
-
"""
|
|
313
|
-
|
|
314
|
-
def command(self, name):
|
|
315
|
-
return "Get-Service -Name {} | Format-List -Property *".format(name)
|
|
316
|
-
|
|
317
|
-
def process(self, output):
|
|
318
|
-
return _format_windows_for_key("Name", output, return_primary_key=False)
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
class Processes(FactBase):
|
|
322
|
-
"""
|
|
323
|
-
Returns the Windows processes.
|
|
324
|
-
"""
|
|
325
|
-
|
|
326
|
-
command = "Get-Process | Format-List -Property *"
|
|
327
|
-
|
|
328
|
-
@staticmethod
|
|
329
|
-
def process(output):
|
|
330
|
-
return _format_windows_for_key("Id", output)
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
class NetworkConfiguration(FactBase):
|
|
334
|
-
"""
|
|
335
|
-
Returns the Windows network configuration.
|
|
336
|
-
"""
|
|
337
|
-
|
|
338
|
-
command = "Get-CimInstance -Class Win32_NetworkAdapterConfiguration | Format-List -Property *"
|
|
339
|
-
|
|
340
|
-
@staticmethod
|
|
341
|
-
def process(output):
|
|
342
|
-
return _format_windows_for_key("Index", output)
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
class InstallerApplications(FactBase):
|
|
346
|
-
"""
|
|
347
|
-
Returns the Windows installer applications.
|
|
348
|
-
"""
|
|
349
|
-
|
|
350
|
-
command = "Get-CimInstance -Class Win32_Product | Format-List -Property *"
|
|
351
|
-
|
|
352
|
-
@staticmethod
|
|
353
|
-
def process(output):
|
|
354
|
-
return _format_windows_for_key("IdentifyingNumber", output)
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
class ComputerInfo(FactBase):
|
|
358
|
-
"""
|
|
359
|
-
Returns the Windows info.
|
|
360
|
-
"""
|
|
361
|
-
|
|
362
|
-
command = "Get-ComputerInfo | Format-List -Property *"
|
|
363
|
-
|
|
364
|
-
@staticmethod
|
|
365
|
-
def process(output):
|
|
366
|
-
return _format_windows(output)
|