atomicshop 2.15.11__py3-none-any.whl → 3.10.5__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.
- atomicshop/__init__.py +1 -1
- atomicshop/{addons/mains → a_mains}/FACT/update_extract.py +3 -2
- atomicshop/a_mains/dns_gateway_setting.py +11 -0
- atomicshop/a_mains/get_local_tcp_ports.py +85 -0
- atomicshop/a_mains/github_wrapper.py +11 -0
- atomicshop/a_mains/install_ca_certificate.py +172 -0
- atomicshop/a_mains/process_from_port.py +119 -0
- atomicshop/a_mains/set_default_dns_gateway.py +90 -0
- atomicshop/a_mains/update_config_toml.py +38 -0
- atomicshop/basics/ansi_escape_codes.py +3 -1
- atomicshop/basics/argparse_template.py +2 -0
- atomicshop/basics/booleans.py +27 -30
- atomicshop/basics/bytes_arrays.py +43 -0
- atomicshop/basics/classes.py +149 -1
- atomicshop/basics/enums.py +2 -2
- atomicshop/basics/exceptions.py +5 -1
- atomicshop/basics/list_of_classes.py +29 -0
- atomicshop/basics/multiprocesses.py +374 -50
- atomicshop/basics/strings.py +72 -3
- atomicshop/basics/threads.py +14 -0
- atomicshop/basics/tracebacks.py +13 -3
- atomicshop/certificates.py +153 -52
- atomicshop/config_init.py +11 -6
- atomicshop/console_user_response.py +7 -14
- atomicshop/consoles.py +9 -0
- atomicshop/datetimes.py +1 -1
- atomicshop/diff_check.py +3 -3
- atomicshop/dns.py +128 -3
- atomicshop/etws/_pywintrace_fix.py +17 -0
- atomicshop/etws/trace.py +40 -42
- atomicshop/etws/traces/trace_dns.py +56 -44
- atomicshop/etws/traces/trace_tcp.py +130 -0
- atomicshop/file_io/csvs.py +27 -5
- atomicshop/file_io/docxs.py +34 -17
- atomicshop/file_io/file_io.py +31 -17
- atomicshop/file_io/jsons.py +49 -0
- atomicshop/file_io/tomls.py +139 -0
- atomicshop/filesystem.py +616 -291
- atomicshop/get_process_list.py +3 -3
- atomicshop/http_parse.py +149 -93
- atomicshop/ip_addresses.py +6 -1
- atomicshop/mitm/centered_settings.py +132 -0
- atomicshop/mitm/config_static.py +207 -0
- atomicshop/mitm/config_toml_editor.py +55 -0
- atomicshop/mitm/connection_thread_worker.py +875 -357
- atomicshop/mitm/engines/__parent/parser___parent.py +4 -17
- atomicshop/mitm/engines/__parent/recorder___parent.py +108 -51
- atomicshop/mitm/engines/__parent/requester___parent.py +116 -0
- atomicshop/mitm/engines/__parent/responder___parent.py +75 -114
- atomicshop/mitm/engines/__reference_general/parser___reference_general.py +10 -7
- atomicshop/mitm/engines/__reference_general/recorder___reference_general.py +5 -5
- atomicshop/mitm/engines/__reference_general/requester___reference_general.py +47 -0
- atomicshop/mitm/engines/__reference_general/responder___reference_general.py +95 -13
- atomicshop/mitm/engines/create_module_template.py +58 -14
- atomicshop/mitm/import_config.py +359 -139
- atomicshop/mitm/initialize_engines.py +160 -80
- atomicshop/mitm/message.py +64 -23
- atomicshop/mitm/mitm_main.py +892 -0
- atomicshop/mitm/recs_files.py +183 -0
- atomicshop/mitm/shared_functions.py +4 -10
- atomicshop/mitm/ssh_tester.py +82 -0
- atomicshop/mitm/statistic_analyzer.py +136 -40
- atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +265 -83
- atomicshop/monitor/checks/dns.py +1 -1
- atomicshop/networks.py +671 -0
- atomicshop/on_exit.py +39 -9
- atomicshop/package_mains_processor.py +84 -0
- atomicshop/permissions/permissions.py +22 -0
- atomicshop/permissions/ubuntu_permissions.py +239 -0
- atomicshop/permissions/win_permissions.py +33 -0
- atomicshop/print_api.py +24 -42
- atomicshop/process.py +24 -6
- atomicshop/process_poller/process_pool.py +0 -1
- atomicshop/process_poller/simple_process_pool.py +204 -5
- atomicshop/python_file_patcher.py +1 -1
- atomicshop/python_functions.py +27 -75
- atomicshop/speech_recognize.py +8 -0
- atomicshop/ssh_remote.py +158 -172
- atomicshop/system_resource_monitor.py +61 -47
- atomicshop/system_resources.py +8 -8
- atomicshop/tempfiles.py +1 -2
- atomicshop/urls.py +6 -0
- atomicshop/venvs.py +28 -0
- atomicshop/versioning.py +27 -0
- atomicshop/web.py +98 -27
- atomicshop/web_apis/google_custom_search.py +44 -0
- atomicshop/web_apis/google_llm.py +188 -0
- atomicshop/websocket_parse.py +450 -0
- atomicshop/wrappers/certauthw/certauth.py +1 -0
- atomicshop/wrappers/cryptographyw.py +29 -8
- atomicshop/wrappers/ctyping/etw_winapi/const.py +97 -47
- atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +178 -49
- atomicshop/wrappers/ctyping/file_details_winapi.py +67 -0
- atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py +2 -1
- atomicshop/wrappers/ctyping/msi_windows_installer/extract_msi_main.py +2 -2
- atomicshop/wrappers/ctyping/setup_device.py +466 -0
- atomicshop/wrappers/ctyping/win_console.py +39 -0
- atomicshop/wrappers/dockerw/dockerw.py +113 -2
- atomicshop/wrappers/elasticsearchw/config_basic.py +0 -12
- atomicshop/wrappers/elasticsearchw/elastic_infra.py +75 -0
- atomicshop/wrappers/elasticsearchw/elasticsearchw.py +2 -20
- atomicshop/wrappers/factw/get_file_data.py +12 -5
- atomicshop/wrappers/factw/install/install_after_restart.py +89 -5
- atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py +20 -14
- atomicshop/wrappers/githubw.py +537 -54
- atomicshop/wrappers/loggingw/consts.py +1 -1
- atomicshop/wrappers/loggingw/filters.py +23 -0
- atomicshop/wrappers/loggingw/formatters.py +12 -0
- atomicshop/wrappers/loggingw/handlers.py +214 -107
- atomicshop/wrappers/loggingw/loggers.py +19 -0
- atomicshop/wrappers/loggingw/loggingw.py +860 -22
- atomicshop/wrappers/loggingw/reading.py +134 -112
- atomicshop/wrappers/mongodbw/mongo_infra.py +31 -0
- atomicshop/wrappers/mongodbw/mongodbw.py +1324 -36
- atomicshop/wrappers/netshw.py +271 -0
- atomicshop/wrappers/playwrightw/engine.py +34 -19
- atomicshop/wrappers/playwrightw/infra.py +5 -0
- atomicshop/wrappers/playwrightw/javascript.py +7 -3
- atomicshop/wrappers/playwrightw/keyboard.py +14 -0
- atomicshop/wrappers/playwrightw/scenarios.py +172 -5
- atomicshop/wrappers/playwrightw/waits.py +9 -7
- atomicshop/wrappers/powershell_networking.py +80 -0
- atomicshop/wrappers/psutilw/processes.py +37 -1
- atomicshop/wrappers/psutilw/psutil_networks.py +85 -0
- atomicshop/wrappers/pyopensslw.py +9 -2
- atomicshop/wrappers/pywin32w/cert_store.py +116 -0
- atomicshop/wrappers/pywin32w/win_event_log/fetch.py +174 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +3 -105
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +3 -57
- atomicshop/wrappers/pywin32w/wmis/msft_netipaddress.py +113 -0
- atomicshop/wrappers/pywin32w/wmis/win32_networkadapterconfiguration.py +259 -0
- atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +112 -0
- atomicshop/wrappers/pywin32w/wmis/wmi_helpers.py +236 -0
- atomicshop/wrappers/socketw/accepter.py +21 -7
- atomicshop/wrappers/socketw/certificator.py +216 -150
- atomicshop/wrappers/socketw/creator.py +190 -50
- atomicshop/wrappers/socketw/dns_server.py +491 -182
- atomicshop/wrappers/socketw/exception_wrapper.py +45 -52
- atomicshop/wrappers/socketw/process_getter.py +86 -0
- atomicshop/wrappers/socketw/receiver.py +144 -102
- atomicshop/wrappers/socketw/sender.py +65 -35
- atomicshop/wrappers/socketw/sni.py +334 -165
- atomicshop/wrappers/socketw/socket_base.py +134 -0
- atomicshop/wrappers/socketw/socket_client.py +137 -95
- atomicshop/wrappers/socketw/socket_server_tester.py +11 -7
- atomicshop/wrappers/socketw/socket_wrapper.py +717 -116
- atomicshop/wrappers/socketw/ssl_base.py +15 -14
- atomicshop/wrappers/socketw/statistics_csv.py +148 -17
- atomicshop/wrappers/sysmonw.py +1 -1
- atomicshop/wrappers/ubuntu_terminal.py +65 -26
- atomicshop/wrappers/win_auditw.py +189 -0
- atomicshop/wrappers/winregw/__init__.py +0 -0
- atomicshop/wrappers/winregw/winreg_installed_software.py +58 -0
- atomicshop/wrappers/winregw/winreg_network.py +232 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/METADATA +31 -51
- atomicshop-3.10.5.dist-info/RECORD +306 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/WHEEL +1 -1
- atomicshop/_basics_temp.py +0 -101
- atomicshop/a_installs/win/fibratus.py +0 -9
- atomicshop/a_installs/win/mongodb.py +0 -9
- atomicshop/a_installs/win/pycharm.py +0 -9
- atomicshop/addons/a_setup_scripts/install_psycopg2_ubuntu.sh +0 -3
- atomicshop/addons/a_setup_scripts/install_pywintrace_0.3.cmd +0 -2
- atomicshop/addons/mains/__pycache__/install_fibratus_windows.cpython-312.pyc +0 -0
- atomicshop/addons/mains/__pycache__/msi_unpacker.cpython-312.pyc +0 -0
- atomicshop/addons/mains/install_docker_rootless_ubuntu.py +0 -11
- atomicshop/addons/mains/install_docker_ubuntu_main_sudo.py +0 -11
- atomicshop/addons/mains/install_elastic_search_and_kibana_ubuntu.py +0 -10
- atomicshop/addons/mains/install_wsl_ubuntu_lts_admin.py +0 -9
- atomicshop/addons/package_setup/CreateWheel.cmd +0 -7
- atomicshop/addons/package_setup/Setup in Edit mode.cmd +0 -6
- atomicshop/addons/package_setup/Setup.cmd +0 -7
- atomicshop/archiver/_search_in_zip.py +0 -189
- atomicshop/archiver/archiver.py +0 -34
- atomicshop/archiver/search_in_archive.py +0 -250
- atomicshop/archiver/sevenz_app_w.py +0 -86
- atomicshop/archiver/sevenzs.py +0 -44
- atomicshop/archiver/zips.py +0 -293
- atomicshop/file_types.py +0 -24
- atomicshop/mitm/config_editor.py +0 -37
- atomicshop/mitm/engines/create_module_template_example.py +0 -13
- atomicshop/mitm/initialize_mitm_server.py +0 -268
- atomicshop/pbtkmultifile_argparse.py +0 -88
- atomicshop/permissions.py +0 -151
- atomicshop/script_as_string_processor.py +0 -38
- atomicshop/ssh_scripts/process_from_ipv4.py +0 -37
- atomicshop/ssh_scripts/process_from_port.py +0 -27
- atomicshop/wrappers/_process_wrapper_curl.py +0 -27
- atomicshop/wrappers/_process_wrapper_tar.py +0 -21
- atomicshop/wrappers/dockerw/install_docker.py +0 -209
- atomicshop/wrappers/elasticsearchw/infrastructure.py +0 -265
- atomicshop/wrappers/elasticsearchw/install_elastic.py +0 -232
- atomicshop/wrappers/ffmpegw.py +0 -125
- atomicshop/wrappers/fibratusw/install.py +0 -81
- atomicshop/wrappers/mongodbw/infrastructure.py +0 -53
- atomicshop/wrappers/mongodbw/install_mongodb.py +0 -190
- atomicshop/wrappers/msiw.py +0 -149
- atomicshop/wrappers/nodejsw/install_nodejs.py +0 -139
- atomicshop/wrappers/process_wrapper_pbtk.py +0 -16
- atomicshop/wrappers/psutilw/networks.py +0 -45
- atomicshop/wrappers/pycharmw.py +0 -81
- atomicshop/wrappers/socketw/base.py +0 -59
- atomicshop/wrappers/socketw/get_process.py +0 -107
- atomicshop/wrappers/wslw.py +0 -191
- atomicshop-2.15.11.dist-info/RECORD +0 -302
- /atomicshop/{addons/mains → a_mains}/FACT/factw_fact_extractor_docker_image_main_sudo.py +0 -0
- /atomicshop/{addons → a_mains/addons}/PlayWrightCodegen.cmd +0 -0
- /atomicshop/{addons → a_mains/addons}/ScriptExecution.cmd +0 -0
- /atomicshop/{addons → a_mains/addons}/inits/init_to_import_all_modules.py +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/ReadMe.txt +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compile.cmd +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.dll +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.exp +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.lib +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/process_list.cpp +0 -0
- /atomicshop/{archiver → permissions}/__init__.py +0 -0
- /atomicshop/{wrappers/fibratusw → web_apis}/__init__.py +0 -0
- /atomicshop/wrappers/{nodejsw → pywin32w/wmis}/__init__.py +0 -0
- /atomicshop/wrappers/pywin32w/{wmi_win32process.py → wmis/win32process.py} +0 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info/licenses}/LICENSE.txt +0 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/top_level.txt +0 -0
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
# v1.0.1 - 26.03.2023 23:50
|
|
2
|
-
import sys
|
|
3
|
-
import argparse
|
|
4
|
-
from argparse import RawTextHelpFormatter
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class ArgparseWrapper:
|
|
8
|
-
"""
|
|
9
|
-
# Usage in the main:
|
|
10
|
-
args = ArgparseWrapper().parser_arguments
|
|
11
|
-
# Defining variables to each argument
|
|
12
|
-
input_path: str = args.input
|
|
13
|
-
output_path: str = args.output
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
def __init__(self):
|
|
17
|
-
self.application_short: str = 'pbtkMultiFile'
|
|
18
|
-
self.application_full: str = 'pbtk Multi File wrapper'
|
|
19
|
-
self.version: str = '1.0.0'
|
|
20
|
-
self.description: str = 'Find ".proto" files in directory of binaries.'
|
|
21
|
-
self.description_full: str = f'{self.application_full} v{self.version}\n' \
|
|
22
|
-
f'Description: {self.description}'
|
|
23
|
-
self.usage_variable: str = "%(prog)s [-h] -in folder_with_binary_files -out full_path_to_output_files\n" \
|
|
24
|
-
"Input or Output path shouldn't end with separator. Example: '\\'."
|
|
25
|
-
self.parser_arguments = None
|
|
26
|
-
|
|
27
|
-
# Execute argparse.
|
|
28
|
-
self.define_argparse()
|
|
29
|
-
|
|
30
|
-
# Function to define argument parser
|
|
31
|
-
def define_argparse(self):
|
|
32
|
-
# Create the parser
|
|
33
|
-
# formatter_class=RawTextHelpFormatter: shows raw text and not the default argparse text parsing.
|
|
34
|
-
parser = argparse.ArgumentParser(description=self.description_full,
|
|
35
|
-
usage=self.usage_variable,
|
|
36
|
-
formatter_class=RawTextHelpFormatter)
|
|
37
|
-
|
|
38
|
-
# Add arguments
|
|
39
|
-
parser.add_argument('-in', '--input',
|
|
40
|
-
action='store', type=str, metavar='PATH_TO_FOLDER_WITH_BINARY_FILES',
|
|
41
|
-
required=True,
|
|
42
|
-
help='Provide full path to folder that contains binary files.')
|
|
43
|
-
parser.add_argument('-out', '--output', action='store', type=str, metavar='PATH_TO_SAVE_EXPORTED_FILES',
|
|
44
|
-
required=True,
|
|
45
|
-
help='Provide full path where you want to store exported file.')
|
|
46
|
-
|
|
47
|
-
# A problem before executing 'parse_args()'.
|
|
48
|
-
# If we get directory path as argument, on windows we can get a path that ends with backslash:
|
|
49
|
-
# C:\Users\user\documents\
|
|
50
|
-
# This is the default behaviour of windows when copying path of only the directory.
|
|
51
|
-
# When the path contains spaces, we need to pass it with double quotes:
|
|
52
|
-
# "C:\Users\user\documents\some folder name\another\"
|
|
53
|
-
# When python receives the arguments from CMD they get already parsed, meaning python can do nothing about it.
|
|
54
|
-
# From input:
|
|
55
|
-
# python_script.py -in "C:\some folder name\another\" -out "C:\some folder name\another1\"
|
|
56
|
-
# You will get output:
|
|
57
|
-
# ['python_script.py',
|
|
58
|
-
# '-in',
|
|
59
|
-
# 'C:\some folder name\another" -out C:\some',
|
|
60
|
-
# 'folder',
|
|
61
|
-
# 'name\another1"]
|
|
62
|
-
# 'parse_args()' gets its input from 'sys.argv'. Meaning, you will need to do some manipulations on that
|
|
63
|
-
# Before executing the argparse argument parsing.
|
|
64
|
-
# Probably the fix should be individual for each case.
|
|
65
|
-
# The simplest solution though is to tell the user not to use backslash in the end of directory in case
|
|
66
|
-
# of exception.
|
|
67
|
-
|
|
68
|
-
try:
|
|
69
|
-
# Execute parse_args()
|
|
70
|
-
parsed_arguments = parser.parse_args()
|
|
71
|
-
# The only thing that you can catch on without modifying Argparse code is 'SystemExit' exception.
|
|
72
|
-
# You can also provide just 'except' without anything, which isn't the best practice.
|
|
73
|
-
# Another fix would be to use
|
|
74
|
-
# argparse.ArgumentParser(exit_on_error=False)
|
|
75
|
-
# But as of python 3.10.8 it is not working yet.
|
|
76
|
-
except SystemExit as exception_object:
|
|
77
|
-
print('======================================')
|
|
78
|
-
print('[*] Info: Error in provided arguments.')
|
|
79
|
-
print('[*] Tip: Check if you have backslash "\\" in the end of folder path, if so remove it.')
|
|
80
|
-
print('======================================')
|
|
81
|
-
sys.exit()
|
|
82
|
-
|
|
83
|
-
# if the folder path argument in the middle will have backslash "\" it will cause an exception.
|
|
84
|
-
# If the backslash will be in the end, it will not cause exception, but the string will end with double quotes.
|
|
85
|
-
parsed_arguments.input = parsed_arguments.input.replace('"', '')
|
|
86
|
-
parsed_arguments.output = parsed_arguments.output.replace('"', '')
|
|
87
|
-
|
|
88
|
-
self.parser_arguments = parsed_arguments
|
atomicshop/permissions.py
DELETED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import stat
|
|
3
|
-
import ctypes
|
|
4
|
-
import contextlib
|
|
5
|
-
import subprocess
|
|
6
|
-
|
|
7
|
-
# Import pwd only on linux.
|
|
8
|
-
if os.name == 'posix':
|
|
9
|
-
import pwd
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def is_admin() -> bool:
|
|
13
|
-
"""
|
|
14
|
-
Function checks on Windows or POSIX OSes if the script is executed under Administrative Privileges.
|
|
15
|
-
:return: True / False.
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
if os.name == 'nt':
|
|
19
|
-
if ctypes.windll.shell32.IsUserAnAdmin() == 0:
|
|
20
|
-
result = False
|
|
21
|
-
else:
|
|
22
|
-
result = True
|
|
23
|
-
else:
|
|
24
|
-
if 'SUDO_USER' in os.environ and os.geteuid() == 0:
|
|
25
|
-
result = True
|
|
26
|
-
else:
|
|
27
|
-
result = False
|
|
28
|
-
|
|
29
|
-
return result
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def get_ubuntu_sudo_executer_username() -> str:
|
|
33
|
-
"""
|
|
34
|
-
Function gets the username of the user who executed the script with sudo.
|
|
35
|
-
:return: str, username.
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
if 'SUDO_USER' in os.environ:
|
|
39
|
-
return os.environ['SUDO_USER']
|
|
40
|
-
else:
|
|
41
|
-
return ''
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def set_executable_permission(file_path: str):
|
|
45
|
-
"""
|
|
46
|
-
Function sets the executable permission on a file.
|
|
47
|
-
Equivalent to: chmod +x <file_path>
|
|
48
|
-
|
|
49
|
-
:param file_path: str, path to the file.
|
|
50
|
-
:return:
|
|
51
|
-
"""
|
|
52
|
-
|
|
53
|
-
# os.chmod(file_path, os.stat(file_path).st_mode | 0o111)
|
|
54
|
-
os.chmod(file_path, os.stat(file_path).st_mode | stat.S_IXUSR)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def change_file_owner_ubuntu(file_path: str, username: str):
|
|
58
|
-
"""
|
|
59
|
-
Function changes the owner of the file to the specified user.
|
|
60
|
-
:param file_path: str, path to the file.
|
|
61
|
-
:param username: str, username of the new owner.
|
|
62
|
-
:return:
|
|
63
|
-
"""
|
|
64
|
-
|
|
65
|
-
uid = pwd.getpwnam(username).pw_uid
|
|
66
|
-
os.chown(file_path, uid, -1)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
def is_executable_permission(file_path: str) -> bool:
|
|
70
|
-
"""
|
|
71
|
-
Function checks if the file has the executable permission.
|
|
72
|
-
Equivalent to: stat -c "%a %n" <file_path>
|
|
73
|
-
|
|
74
|
-
:param file_path: str, path to the file.
|
|
75
|
-
:return: bool, True / False.
|
|
76
|
-
"""
|
|
77
|
-
|
|
78
|
-
return bool(os.stat(file_path).st_mode & stat.S_IXUSR)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def run_as_root(command):
|
|
82
|
-
subprocess.check_call(['sudo'] + command)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
@contextlib.contextmanager
|
|
86
|
-
def temporary_regular_permissions():
|
|
87
|
-
"""
|
|
88
|
-
This function is used to temporarily change the effective user and group ID to the original user's.
|
|
89
|
-
This is used to run commands with the original user's permissions.
|
|
90
|
-
If you executed a script with 'sudo' and wanted certain action to execute as regular user and not root.
|
|
91
|
-
|
|
92
|
-
Example:
|
|
93
|
-
with temporary_regular_permissions():
|
|
94
|
-
# Do something with regular permissions.
|
|
95
|
-
pass
|
|
96
|
-
|
|
97
|
-
:return:
|
|
98
|
-
"""
|
|
99
|
-
# Save the current effective user and group ID
|
|
100
|
-
original_euid, original_egid = os.geteuid(), os.getegid()
|
|
101
|
-
|
|
102
|
-
try:
|
|
103
|
-
# Get the original user's UID and GID
|
|
104
|
-
orig_uid = int(os.environ.get('SUDO_UID', os.getuid()))
|
|
105
|
-
orig_gid = int(os.environ.get('SUDO_GID', os.getgid()))
|
|
106
|
-
|
|
107
|
-
# Set the effective user and group ID to the original user's
|
|
108
|
-
os.setegid(orig_gid)
|
|
109
|
-
os.seteuid(orig_uid)
|
|
110
|
-
|
|
111
|
-
# Provide the context to do something with these permissions
|
|
112
|
-
yield
|
|
113
|
-
finally:
|
|
114
|
-
# Revert to the original effective user and group ID
|
|
115
|
-
os.seteuid(original_euid)
|
|
116
|
-
os.setegid(original_egid)
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
def expand_user_path(user_name, path):
|
|
120
|
-
pwnam = pwd.getpwnam(user_name)
|
|
121
|
-
home_dir = pwnam.pw_dir
|
|
122
|
-
return path.replace("~", home_dir)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def unblock_file_windows(file_path):
|
|
126
|
-
"""
|
|
127
|
-
Unblock a file on Windows. This is used to unblock files downloaded from the internet.
|
|
128
|
-
When you Right-click then navigate to Properties, you will see the Unblock checkbox.
|
|
129
|
-
:param file_path:
|
|
130
|
-
:return:
|
|
131
|
-
"""
|
|
132
|
-
try:
|
|
133
|
-
subprocess.run(["powershell", "-Command", f"Unblock-File -Path '{file_path}'"], check=True)
|
|
134
|
-
print(f"Successfully unblocked the file: {file_path}")
|
|
135
|
-
except subprocess.CalledProcessError as e:
|
|
136
|
-
print(f"Failed to unblock the file: {file_path}\nError: {e}")
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
def get_command_to_run_as_admin_windows(command: str) -> str:
|
|
140
|
-
"""
|
|
141
|
-
Function returns the command to run a command as administrator on Windows.
|
|
142
|
-
:param command: str, command to run.
|
|
143
|
-
:return: str, command to run as administrator.
|
|
144
|
-
"""
|
|
145
|
-
|
|
146
|
-
executable = command.split()[0]
|
|
147
|
-
command = (
|
|
148
|
-
f"powershell -Command "
|
|
149
|
-
f"\"Start-Process {executable} -ArgumentList '{' '.join(command.split()[1:])}' -Verb RunAs\"")
|
|
150
|
-
|
|
151
|
-
return command
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
"""Loading resources using stdlib importlib.resources APIs (Python 3.7+)
|
|
2
|
-
https://docs.python.org/3/library/importlib.html#module-importlib.resources"""
|
|
3
|
-
import importlib.resources
|
|
4
|
-
|
|
5
|
-
from .print_api import print_api
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class ScriptAsStringProcessor:
|
|
9
|
-
def __init__(self):
|
|
10
|
-
self.resources_directory_name: str = 'ssh_scripts'
|
|
11
|
-
|
|
12
|
-
# string variable that is going to be exchanged with variable from main script.
|
|
13
|
-
self.exchange_input_variable_string: str = "exchange_input_variable"
|
|
14
|
-
self.script_string: str = str()
|
|
15
|
-
|
|
16
|
-
def read_script_to_string(self, script_file_name: str):
|
|
17
|
-
self.script_string = importlib.resources.read_text(
|
|
18
|
-
f'{__package__}.{self.resources_directory_name}',
|
|
19
|
-
f'{script_file_name}.py')
|
|
20
|
-
|
|
21
|
-
return self
|
|
22
|
-
|
|
23
|
-
def put_variable_into_script_string(self, input_variable: any, print_kwargs: dict = None):
|
|
24
|
-
# Defining variables
|
|
25
|
-
function_result: str = str()
|
|
26
|
-
|
|
27
|
-
if self.exchange_input_variable_string in self.script_string:
|
|
28
|
-
# string.replace(old, new, count)
|
|
29
|
-
# old – old substring you want to replace.
|
|
30
|
-
# new – new substring which would replace the old substring.
|
|
31
|
-
# count – the number of times you want to replace the old substring with the new substring. (Optional)
|
|
32
|
-
# We want to replace our string only one time in the beginning.
|
|
33
|
-
function_result = self.script_string.replace(self.exchange_input_variable_string, str(input_variable), 1)
|
|
34
|
-
else:
|
|
35
|
-
message = f"The script string provided doesn't contain {self.exchange_input_variable_string}"
|
|
36
|
-
print_api(message, error_type=True, logger_method='error', **print_kwargs)
|
|
37
|
-
|
|
38
|
-
return function_result
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# importing the psutil library to get the source ports and get the process full command line from it.
|
|
2
|
-
import psutil
|
|
3
|
-
# 'psutil.Process(connection.pid).cmdline()' returns list of full command line parts, it is needed to reassemble
|
|
4
|
-
# these parts to regular command line string.
|
|
5
|
-
import shlex
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
# User defined exception.
|
|
9
|
-
class StopAllIterations(Exception):
|
|
10
|
-
pass
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
# 'input_variable' will be string exchanged in the real script. It is the first line, so it won't take time to find the
|
|
14
|
-
# line for the main script.
|
|
15
|
-
# noinspection PyUnresolvedReferences
|
|
16
|
-
remote_ipv4_list = exchange_input_variable
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
try:
|
|
20
|
-
# for iteration in range(100):
|
|
21
|
-
# Iterating through all the connections on the computer.
|
|
22
|
-
for connection in psutil.net_connections(kind='all'):
|
|
23
|
-
# 'connection.raddr' is a tuple consisting of IPv4 address [0] and the port [1].
|
|
24
|
-
# Sometimes, if there's no remote address, "raddr" will be empty and since it's a tuple, we need to check that
|
|
25
|
-
# before getting the first [0] index.
|
|
26
|
-
if connection.raddr:
|
|
27
|
-
for address in remote_ipv4_list:
|
|
28
|
-
if connection.raddr[0] == address:
|
|
29
|
-
# Get the command line from the connection PID.
|
|
30
|
-
command_line = psutil.Process(connection.pid).cmdline()
|
|
31
|
-
# Command line object is returned as list of parameters. We need 'shlex.join' to join the iterables
|
|
32
|
-
# to regular, readable string.
|
|
33
|
-
print(shlex.join(command_line))
|
|
34
|
-
# Break the loops, when first match is found.
|
|
35
|
-
raise StopAllIterations
|
|
36
|
-
except StopAllIterations:
|
|
37
|
-
pass
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# importing the psutil library to get the source ports and get the process full command line from it.
|
|
2
|
-
import psutil
|
|
3
|
-
# 'psutil.Process(connection.pid).cmdline()' returns list of full command line parts, it is needed to reassemble
|
|
4
|
-
# these parts to regular command line string.
|
|
5
|
-
import shlex
|
|
6
|
-
|
|
7
|
-
# 'input_variable' will be string exchanged in the real script. It is the first line, so it won't take time to find the
|
|
8
|
-
# line for the main script.
|
|
9
|
-
# noinspection PyUnresolvedReferences
|
|
10
|
-
source_port = exchange_input_variable
|
|
11
|
-
|
|
12
|
-
# Iterating through all the connections on the computer.
|
|
13
|
-
for connection in psutil.net_connections():
|
|
14
|
-
# 'connection.laddr' is a tuple consisting of IPv4 address [0] and the port [1].
|
|
15
|
-
if connection.laddr[1] == source_port:
|
|
16
|
-
# Get the command line from the connection PID.
|
|
17
|
-
command_line = psutil.Process(connection.pid).cmdline()
|
|
18
|
-
# Command line object is returned as list of parameters. We need 'shlex.join' to join the iterables
|
|
19
|
-
# to regular, readable string.
|
|
20
|
-
result = shlex.join(command_line)
|
|
21
|
-
# If the result is still a PID, we'll try to get process name.
|
|
22
|
-
if result.isnumeric():
|
|
23
|
-
# Get the process name from the connection PID.
|
|
24
|
-
result = psutil.Process(connection.pid).name()
|
|
25
|
-
print(result)
|
|
26
|
-
# Break the loop, when first match is found.
|
|
27
|
-
break
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# v1.0.2 - 21.03.2023 13:40
|
|
2
|
-
import sys
|
|
3
|
-
import shlex
|
|
4
|
-
|
|
5
|
-
from .. import process
|
|
6
|
-
from .. import web
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def download_file_with_curl(file_url: str, target_directory: str) -> None:
|
|
10
|
-
"""
|
|
11
|
-
The function receives url and target filesystem directory to download the file.
|
|
12
|
-
|
|
13
|
-
:param file_url: full URL to download the file.
|
|
14
|
-
:param target_directory: The directory on the filesystem to save the file to.
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
# Get only the filename from URL.
|
|
18
|
-
file_name = web.get_filename_from_url(file_url=file_url)
|
|
19
|
-
|
|
20
|
-
cmd: str = f'curl -L {file_url} --output "{target_directory}"'
|
|
21
|
-
cmd_list: list = shlex.split(cmd)
|
|
22
|
-
|
|
23
|
-
output_list: list = process.execute_with_live_output(cmd=cmd_list)
|
|
24
|
-
# If there was error in curl.
|
|
25
|
-
if 'curl: ' in output_list[-1]:
|
|
26
|
-
print('Curl error. Exiting...')
|
|
27
|
-
sys.exit()
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# v1.0.2 - 21.03.2023 18:30
|
|
2
|
-
import shlex
|
|
3
|
-
|
|
4
|
-
from .. import process
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def extract_archive_with_tar(file_path: str, target_directory: str) -> None:
|
|
8
|
-
"""
|
|
9
|
-
Function extracts the archive to target directory.
|
|
10
|
-
|
|
11
|
-
:param file_path: Full file path to archived file to extract.
|
|
12
|
-
:param target_directory: The directory on the filesystem to extract the file to.
|
|
13
|
-
:return: None
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
# -v: Verbose, shows list of extracted files.
|
|
17
|
-
# -C: Output directory.
|
|
18
|
-
cmd: str = f'tar -xzvf "{file_path}" -C "{target_directory}"'
|
|
19
|
-
cmd_list: list = shlex.split(cmd)
|
|
20
|
-
|
|
21
|
-
output_list = process.execute_with_live_output(cmd=cmd_list)
|
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
import subprocess
|
|
3
|
-
import getpass
|
|
4
|
-
|
|
5
|
-
from ... import process, filesystem, permissions
|
|
6
|
-
from ...print_api import print_api
|
|
7
|
-
from .. import ubuntu_terminal
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def is_docker_installed():
|
|
11
|
-
"""
|
|
12
|
-
The function will check if docker is installed.
|
|
13
|
-
:return: bool.
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
try:
|
|
17
|
-
# Run the command 'docker --version'
|
|
18
|
-
result = subprocess.run(['docker', '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
19
|
-
|
|
20
|
-
# Check if the command was successful
|
|
21
|
-
if result.returncode == 0:
|
|
22
|
-
message = f"Docker is installed. Version: {result.stdout.strip()}"
|
|
23
|
-
print_api(message, color='green')
|
|
24
|
-
return True
|
|
25
|
-
else:
|
|
26
|
-
print_api("Docker is not installed.")
|
|
27
|
-
return False
|
|
28
|
-
except FileNotFoundError:
|
|
29
|
-
print_api("Docker command not found. Docker is not installed.")
|
|
30
|
-
return False
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def add_current_user_to_docker_group(print_kwargs: dict = None):
|
|
34
|
-
"""
|
|
35
|
-
The function will add the current user to the docker group.
|
|
36
|
-
|
|
37
|
-
:param print_kwargs: dict, the print arguments.
|
|
38
|
-
:return:
|
|
39
|
-
"""
|
|
40
|
-
# Check if current user that executed the script is a sudo user. If not, use the current user.
|
|
41
|
-
sudo_executer_username: str = permissions.get_ubuntu_sudo_executer_username()
|
|
42
|
-
if sudo_executer_username:
|
|
43
|
-
current_user = sudo_executer_username
|
|
44
|
-
else:
|
|
45
|
-
current_user = getpass.getuser()
|
|
46
|
-
|
|
47
|
-
# Add the current user to the docker group.
|
|
48
|
-
# subprocess.check_call(['sudo', 'usermod', '-aG', 'docker', current_user])
|
|
49
|
-
command = f"sudo usermod -aG docker {current_user}"
|
|
50
|
-
# Execute the command
|
|
51
|
-
subprocess.run(command, shell=True, capture_output=True, text=True)
|
|
52
|
-
|
|
53
|
-
# Check if the user was added to the docker group.
|
|
54
|
-
result = subprocess.run(['groups', current_user], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
55
|
-
if 'docker' in result.stdout:
|
|
56
|
-
print_api(f"User {current_user} was added to the docker group.", color='green', **(print_kwargs or {}))
|
|
57
|
-
return True
|
|
58
|
-
else:
|
|
59
|
-
print_api(f"User {current_user} was not added to the docker group. Try executing with sudo", color='red',
|
|
60
|
-
**(print_kwargs or {}))
|
|
61
|
-
return False
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def install_docker_ubuntu(
|
|
65
|
-
use_docker_installer: bool = True,
|
|
66
|
-
rootless: bool = False,
|
|
67
|
-
add_current_user_to_docker_group_bool: bool = False
|
|
68
|
-
):
|
|
69
|
-
"""
|
|
70
|
-
The function will install docker on ubuntu.
|
|
71
|
-
Note: If you want to install docker in rootless mode, you need to run the script without sudo.
|
|
72
|
-
|
|
73
|
-
:param rootless: bool, if True, the rootless installation will be performed.
|
|
74
|
-
Meaning, you will be able to run the 'docker' command without sudo and you will not need to add the
|
|
75
|
-
current user to the docker group.
|
|
76
|
-
:param use_docker_installer: bool, if True, the docker installer will be used.
|
|
77
|
-
If False, the docker will be installed using the apt package manager, custom repo and keyring.
|
|
78
|
-
:param add_current_user_to_docker_group_bool: bool, if True, the current user will be added to the docker group.
|
|
79
|
-
So the user will be able to run the 'docker' command without sudo. If you install docker in rootless mode
|
|
80
|
-
this is not needed.
|
|
81
|
-
|
|
82
|
-
Usage in main.py (run with sudo):
|
|
83
|
-
from atomicshop.wrappers.dockerw import install_docker
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def main():
|
|
87
|
-
install_docker.install_docker_ubuntu()
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if __name__ == '__main__':
|
|
91
|
-
main()
|
|
92
|
-
"""
|
|
93
|
-
|
|
94
|
-
if rootless and permissions.is_admin():
|
|
95
|
-
print_api('Rootless installation requires running the script without sudo.', color='red')
|
|
96
|
-
sys.exit()
|
|
97
|
-
|
|
98
|
-
if use_docker_installer:
|
|
99
|
-
if not ubuntu_terminal.is_executable_exists('curl'):
|
|
100
|
-
print_api('curl is not installed, installing...', color='yellow')
|
|
101
|
-
ubuntu_terminal.update_system_packages()
|
|
102
|
-
ubuntu_terminal.install_packages(['curl'])
|
|
103
|
-
|
|
104
|
-
# Use the docker installer script.
|
|
105
|
-
# The script will install docker and add the current user to the docker group.
|
|
106
|
-
# The script will also install docker-compose and docker-buildx.
|
|
107
|
-
# process.execute_script('curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh', shell=True)
|
|
108
|
-
process.execute_script('curl -fsSL https://get.docker.com | sh', shell=True)
|
|
109
|
-
# process.execute_script('curl -fsSL https://get.docker.com -o get-docker.sh', shell=True)
|
|
110
|
-
# process.execute_script('sh get-docker.sh', shell=True)
|
|
111
|
-
# filesystem.remove_file('get-docker.sh')
|
|
112
|
-
else:
|
|
113
|
-
# Remove the existing keyrings, so we will not be asked to overwrite it if it exists.
|
|
114
|
-
docker_keyring_file_path: str = "/etc/apt/keyrings/docker.gpg"
|
|
115
|
-
filesystem.remove_file(docker_keyring_file_path)
|
|
116
|
-
|
|
117
|
-
script = f"""
|
|
118
|
-
# Step 1: Set up Docker's apt repository
|
|
119
|
-
sudo apt-get update
|
|
120
|
-
sudo apt-get install -y ca-certificates curl gnupg
|
|
121
|
-
sudo install -m 0755 -d /etc/apt/keyrings
|
|
122
|
-
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
|
123
|
-
sudo chmod a+r /etc/apt/keyrings/docker.gpg
|
|
124
|
-
|
|
125
|
-
# Add the repository to Apt sources
|
|
126
|
-
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
|
127
|
-
sudo apt-get update
|
|
128
|
-
|
|
129
|
-
# Step 2: Install the Docker packages
|
|
130
|
-
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
|
|
131
|
-
|
|
132
|
-
# Step 3: Verify the installation
|
|
133
|
-
# sudo docker run hello-world
|
|
134
|
-
|
|
135
|
-
# Add Privileges to run docker without sudo. Add current user to Docker superuser group.
|
|
136
|
-
# sudo usermod -aG docker $USER
|
|
137
|
-
"""
|
|
138
|
-
|
|
139
|
-
process.execute_script(script, shell=True)
|
|
140
|
-
|
|
141
|
-
if rootless:
|
|
142
|
-
# Install uidmap package.
|
|
143
|
-
if not ubuntu_terminal.is_package_installed('uidmap'):
|
|
144
|
-
print_api('uidmap is not installed, installing...', color='yellow')
|
|
145
|
-
ubuntu_terminal.update_system_packages()
|
|
146
|
-
ubuntu_terminal.install_packages(['uidmap'])
|
|
147
|
-
|
|
148
|
-
with permissions.temporary_regular_permissions():
|
|
149
|
-
# After 'get-docker.sh' execution, we will install docker in rootless mode.
|
|
150
|
-
# process.execute_script('dockerd-rootless-setuptool.sh install', shell=True, as_regular_user=True)
|
|
151
|
-
process.execute_script(
|
|
152
|
-
'/usr/bin/dockerd-rootless-setuptool.sh install',
|
|
153
|
-
as_regular_user=True,
|
|
154
|
-
shell=True,
|
|
155
|
-
executable=None)
|
|
156
|
-
|
|
157
|
-
# Start and enable the docker service in user mode.
|
|
158
|
-
docker_start_command = ubuntu_terminal.get_command_execution_as_sudo_executer(
|
|
159
|
-
'systemctl --user start docker.service')
|
|
160
|
-
docker_enable_command = ubuntu_terminal.get_command_execution_as_sudo_executer(
|
|
161
|
-
'systemctl --user enable docker.service')
|
|
162
|
-
print_api('Starting and enabling the docker service in user mode...')
|
|
163
|
-
process.execute_script(docker_start_command, shell=True, executable=None)
|
|
164
|
-
process.execute_script(docker_enable_command, shell=True, executable=None)
|
|
165
|
-
|
|
166
|
-
print_api('Executing "loginctl enable-linger" to enable Docker to run when the user is not logged in...')
|
|
167
|
-
non_sudo_executer = permissions.get_ubuntu_sudo_executer_username()
|
|
168
|
-
# Enable lingering so Docker runs when the user is not logged in
|
|
169
|
-
process.execute_script(f'sudo loginctl enable-linger {non_sudo_executer}', shell=True)
|
|
170
|
-
|
|
171
|
-
print_api('Adding $HOME/bin to your PATH...')
|
|
172
|
-
# Add $HOME/bin to your PATH if it's not already there.
|
|
173
|
-
with permissions.temporary_regular_permissions():
|
|
174
|
-
ubuntu_terminal.add_path_to_bashrc(as_regular_user=True)
|
|
175
|
-
|
|
176
|
-
# Add appropriate permissions to the docker socket, so the user can run docker commands without sudo in python.
|
|
177
|
-
# with open('/etc/profile.d/docker_vars.sh', 'w') as file:
|
|
178
|
-
# file.write('export DOCKER_HOST=unix:///run/user/1000/docker.sock')
|
|
179
|
-
|
|
180
|
-
# Since we are installing the rootless mode, this script runs without sudo, so to add the DOCKER_HOST variable
|
|
181
|
-
# to the environment, we need to add it to the /etc/profile.d/docker_vars.sh file with sudo.
|
|
182
|
-
command = "echo 'export DOCKER_HOST=unix:///run/user/1000/docker.sock' | sudo tee /etc/profile.d/docker_vars.sh"
|
|
183
|
-
subprocess.run(command, shell=True, check=True)
|
|
184
|
-
|
|
185
|
-
# ubuntu_terminal.add_line_to_bashrc(
|
|
186
|
-
# 'export DOCKER_HOST=unix:///run/user/1000/docker.sock', as_regular_user=True)
|
|
187
|
-
# process.execute_script('export DOCKER_HOST=unix:///run/user/1000/docker.sock', shell=True)
|
|
188
|
-
# Restart shell.
|
|
189
|
-
# process.execute_script('source ~/.bashrc', shell=True)
|
|
190
|
-
|
|
191
|
-
if add_current_user_to_docker_group_bool:
|
|
192
|
-
# Check if current user that executed the script is a sudo user. If not, use the current user.
|
|
193
|
-
# Add the current user to the docker group.
|
|
194
|
-
add_current_user_to_docker_group()
|
|
195
|
-
|
|
196
|
-
# Verify the installation.
|
|
197
|
-
result: list = process.execute_with_live_output('sudo docker run hello-world')
|
|
198
|
-
else:
|
|
199
|
-
result: list = process.execute_with_live_output('docker run hello-world')
|
|
200
|
-
|
|
201
|
-
print_api('\n'.join(result))
|
|
202
|
-
|
|
203
|
-
if 'Hello from Docker!' in '\n'.join(result):
|
|
204
|
-
print_api('Docker installed successfully.', color='green')
|
|
205
|
-
return True
|
|
206
|
-
else:
|
|
207
|
-
print_api('Docker installation failed.', color='red')
|
|
208
|
-
print_api('Please check the logs above for more information.', color='red')
|
|
209
|
-
return False
|