addftool 0.1.4__py3-none-any.whl → 0.1.6__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.
addftool/addf_portal.py CHANGED
@@ -1,5 +1,7 @@
1
1
  import argparse
2
2
  from addftool.process import add_killer_args, killer_main
3
+ from addftool.sync import add_sync_args, sync_main
4
+ from addftool.deploy import add_deploy_args, deploy_main
3
5
 
4
6
 
5
7
  def get_args():
@@ -7,6 +9,8 @@ def get_args():
7
9
 
8
10
  subparsers = parser.add_subparsers(dest='command', help='Sub-command help')
9
11
  add_killer_args(subparsers)
12
+ add_sync_args(subparsers)
13
+ add_deploy_args(subparsers)
10
14
 
11
15
  return parser.parse_args()
12
16
 
@@ -15,6 +19,10 @@ def main():
15
19
  args = get_args()
16
20
  if args.command == "kill":
17
21
  killer_main(args)
22
+ elif args.command == "sync":
23
+ sync_main(args)
24
+ elif args.command == "deploy":
25
+ deploy_main(args)
18
26
  else:
19
27
  print("Unknown command: ", args.command)
20
28
 
@@ -0,0 +1,35 @@
1
+ import argparse
2
+
3
+ from .ssh_server import add_deploy_ssh_server_args, deploy_ssh_server_main
4
+ from .azure import add_deploy_azure_args, deploy_azure_main
5
+
6
+
7
+ def add_deploy_args(subparsers: argparse._SubParsersAction):
8
+ """
9
+ Add deploy arguments to the parser.
10
+ Args:
11
+ subparsers (argparse._SubParsersAction): The subparsers object to add the arguments to.
12
+ """
13
+ deploy_parsers = subparsers.add_parser('deploy', help='deploy/install software, script, tools, etc.')
14
+ deploy_subparsers = deploy_parsers.add_subparsers(dest='deploy_type', help='Deploy options')
15
+
16
+ ssh_server_parser = deploy_subparsers.add_parser('ssh-server', help='SSH options')
17
+ add_deploy_ssh_server_args(ssh_server_parser)
18
+
19
+ azure_parser = deploy_subparsers.add_parser('azure', help='Azure options')
20
+ add_deploy_azure_args(azure_parser)
21
+
22
+
23
+ def deploy_main(args):
24
+ """
25
+ Main function for deploy.
26
+ Args:
27
+ args (argparse.Namespace): The parsed arguments.
28
+ """
29
+ if args.deploy_type == 'ssh-server':
30
+ deploy_ssh_server_main(args)
31
+ elif args.deploy_type == 'azure':
32
+ deploy_azure_main(args)
33
+ else:
34
+ print("Unknown deploy type")
35
+ print("Deploy type: ", args.deploy_type)
@@ -0,0 +1,39 @@
1
+ from addftool.util import need_sudo, execute_command, get_ubuntu_version, install_packages
2
+
3
+
4
+ def deploy_azure(packages):
5
+ ubuntu_version = get_ubuntu_version()
6
+ print("Get ubuntu version: ", ubuntu_version)
7
+
8
+ command = f"wget https://packages.microsoft.com/config/ubuntu/{ubuntu_version}/packages-microsoft-prod.deb -O /tmp/packages-microsoft-prod.deb"
9
+ print("Install packages-microsoft-prod.deb")
10
+ execute_command(command)
11
+ command_prefix = "sudo " if need_sudo() else ""
12
+ command = "dpkg -i /tmp/packages-microsoft-prod.deb"
13
+ execute_command(command_prefix + command)
14
+
15
+ install_packages(packages)
16
+
17
+
18
+ def add_deploy_azure_args(parser):
19
+ """
20
+ Add Azure deployment arguments to the parser.
21
+ Args:
22
+ parser (argparse.ArgumentParser): The argument parser to add the arguments to.
23
+ """
24
+ parser.add_argument("packages", help="packages", default=['fuse3', 'blobfuse2', 'azcopy'], nargs="*")
25
+
26
+ def deploy_azure_main(args):
27
+ # print(args.packages)
28
+ deploy_azure(args.packages)
29
+
30
+
31
+ if __name__ == "__main__":
32
+ import argparse
33
+
34
+ parser = argparse.ArgumentParser(description="Azure deployment arguments")
35
+ add_deploy_azure_args(parser)
36
+
37
+ args = parser.parse_args()
38
+
39
+ deploy_azure_main(args)
@@ -0,0 +1,137 @@
1
+ import subprocess
2
+ import argparse
3
+ import os
4
+ from addftool.util import need_sudo, execute_command, is_running_in_docker
5
+
6
+
7
+ def convert_ssh2_to_openssh(ssh2_public_key_content):
8
+ lines = ssh2_public_key_content.strip().split('\n')
9
+ encoded_key = ""
10
+ start_found = False
11
+ for line in lines:
12
+ line = line.strip()
13
+ if line == "---- BEGIN SSH2 PUBLIC KEY ----":
14
+ start_found = True
15
+ continue
16
+ elif line == "---- END SSH2 PUBLIC KEY ----":
17
+ break
18
+ elif start_found and line.startswith("Comment:"):
19
+ comment = line.split(":", 1)[1].strip().strip('"')
20
+ elif start_found:
21
+ encoded_key += line
22
+
23
+ if encoded_key:
24
+ # Assuming it's an RSA key based on the comment
25
+ openssh_key = f"ssh-rsa {encoded_key} \"{comment}\""
26
+ return openssh_key
27
+ else:
28
+ return None
29
+
30
+
31
+ def parse_key_from_file(file_path):
32
+ """
33
+ 解析 SSH 公钥文件,支持 SSH2 和 OpenSSH 格式
34
+ :param file_path: 公钥文件路径
35
+ :return: 公钥内容
36
+ """
37
+ with open(file_path, "r") as f:
38
+ content = f.read()
39
+ if "---- BEGIN SSH2 PUBLIC KEY ----" in content:
40
+ return convert_ssh2_to_openssh(content)
41
+ else:
42
+ return content.strip()
43
+
44
+
45
+ def configure_ssh_on_ubuntu(port, username, ssh_public_key="", password=""):
46
+ if not is_running_in_docker():
47
+ print("This script is not running in a Docker container. Exiting...")
48
+ return
49
+ print(f"deploy ssh server on port: {port}, username: {username}, ssh_public_key: {ssh_public_key}, password: {password is not None}")
50
+ if not(len(ssh_public_key) > 0 or len(password) > 0):
51
+ print("ssh_public_key or password must be provided.")
52
+ return
53
+ command_prefix = "sudo " if need_sudo() else ""
54
+ try:
55
+ need_install_ssh = True
56
+ try:
57
+ # execute_command(["which", "sshd"])
58
+ response = execute_command("which sshd", only_stdout=False)
59
+ if response["returncode"] == 0:
60
+ print("SSH server is already installed.")
61
+ need_install_ssh = False
62
+ except subprocess.CalledProcessError:
63
+ pass
64
+ if need_install_ssh:
65
+ print("SSH server is not installed. Installing...")
66
+ execute_command(command_prefix + "apt-get update")
67
+ execute_command(command_prefix + "apt-get install -y openssh-server")
68
+
69
+ print("Modifying SSH configuration...")
70
+ execute_command(command_prefix + f'sed -i "s/#Port 22/Port {port}/" /etc/ssh/sshd_config')
71
+ execute_command(command_prefix + 'sed -i "s/#PermitRootLogin prohibit-password/PermitRootLogin yes/" /etc/ssh/sshd_config')
72
+
73
+ if not os.path.exists("/etc/ssh/ssh_host_rsa_key"):
74
+ print("SSH host keys not found. Generating new keys...")
75
+ execute_command(command_prefix + 'ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N ""')
76
+
77
+ print(f'Creating user {username} and configuring SSH key...')
78
+ try:
79
+ # run_command(["id", "-u", username])
80
+ execute_command(command_prefix + f"id -u {username}")
81
+ except subprocess.CalledProcessError:
82
+ print(f"User {username} does not exist. Creating user...")
83
+ execute_command(command_prefix + f"useradd -m -s /bin/bash {username}")
84
+
85
+ ssh_dir = f"/home/{username}/.ssh" if username != "root" else "/root/.ssh"
86
+ authorized_keys_file = f"{ssh_dir}/authorized_keys"
87
+
88
+
89
+ execute_command(command_prefix + f"mkdir -p {ssh_dir}")
90
+ execute_command(command_prefix + f"chmod 700 {ssh_dir}")
91
+
92
+ if ssh_public_key:
93
+ key_content = parse_key_from_file(ssh_public_key)
94
+ execute_command(command_prefix + f"bash -c 'echo \"{key_content}\" >> {authorized_keys_file}'", hide=True)
95
+ execute_command(command_prefix + f"chmod 600 {authorized_keys_file}")
96
+ execute_command(command_prefix + f"chown -R {username}:{username} {ssh_dir}")
97
+
98
+ if password:
99
+ execute_command(command_prefix + f"echo '{username}:{password}' | chpasswd", hide=True)
100
+
101
+ print("Restarting SSH service...")
102
+ # run_command(["sudo", "systemctl", "restart", "ssh"])
103
+ execute_command("/etc/init.d/ssh restart")
104
+
105
+ print(f"ssh is configured! You can connect using the following command: ssh -p {port} {username}@<host_ip>")
106
+
107
+ except subprocess.CalledProcessError as e:
108
+ print(f"Command called process error: {e}")
109
+ except FileNotFoundError as e:
110
+ print(f"File not found error: {e}")
111
+ except Exception as e:
112
+ print(f"An error occurred: {e}")
113
+
114
+ def add_deploy_ssh_server_args(parser):
115
+ """添加 SSH 配置参数"""
116
+ parser.add_argument("--port", type=int, required=True, help="SSH server port")
117
+ parser.add_argument("--username", required=True, help="SSH username")
118
+ parser.add_argument("--password", help="SSH password", type=str, default="")
119
+ parser.add_argument("--ssh-public-key", help="SSH public key", type=str, default="")
120
+
121
+
122
+
123
+ def deploy_ssh_server_main(args):
124
+ """
125
+ 部署 SSH 服务器
126
+ :param args: 命令行参数
127
+ """
128
+ configure_ssh_on_ubuntu(args.port, args.username, args.ssh_public_key, args.password)
129
+
130
+
131
+ if __name__ == "__main__":
132
+ parser = argparse.ArgumentParser(description="在 Ubuntu 系统中配置 SSH")
133
+ add_deploy_ssh_server_args(parser)
134
+
135
+ args = parser.parse_args()
136
+
137
+ deploy_ssh_server_main(args)
@@ -52,6 +52,7 @@ def kill_process(processes, timeout=5, try_count=3):
52
52
  if all_terminated:
53
53
  print("All processes terminated")
54
54
  break
55
+ time.sleep(timeout)
55
56
 
56
57
  if not all_terminated:
57
58
  print("Some processes are still running. Please check manually.")
File without changes
@@ -0,0 +1,42 @@
1
+ import os
2
+
3
+
4
+ def add_sync_args(subparsers):
5
+ process_killer_parser = subparsers.add_parser('sync', help='download and sync folder from master node to other nodes')
6
+
7
+ process_killer_parser.add_argument("--from_blob_url", help="download from blob url to master node before sync", type=str, default="")
8
+ process_killer_parser.add_argument("--sas_token", help="sas token for blob url", type=str, default="")
9
+ process_killer_parser.add_argument("--tool", help="tool name", type=str, default="torch_nccl", choices=["torch_nccl", "rsync"])
10
+ process_killer_parser.add_argument("--hostfile", help="host file, sync file from node-0 to others", type=str, default="")
11
+
12
+ # distributed downloader from blob
13
+ process_killer_parser.add_argument("--donwload_nodes", help="download nodes, default is node-0", type=int, default=1)
14
+
15
+ process_killer_parser.add_argument("folder", nargs='?', help="the folder need to sync", type=str, default="")
16
+
17
+
18
+ def sync_main(args):
19
+ print(args)
20
+ exit(0)
21
+ if args.source == "" or args.target == "":
22
+ print("Please provide source and target folder")
23
+ return
24
+
25
+ # check if source is a folder
26
+ if not os.path.isdir(args.source):
27
+ print(f"Source {args.source} is not a folder")
28
+ return
29
+
30
+ # check if target is a folder
31
+ if not os.path.isdir(args.target):
32
+ print(f"Target {args.target} is not a folder")
33
+ return
34
+
35
+ # check if source and target are the same
36
+ if os.path.abspath(args.source) == os.path.abspath(args.target):
37
+ print(f"Source and target are the same")
38
+ return
39
+
40
+ # sync source to target
41
+ command = f"rsync -avz --delete {args.source} {args.target}"
42
+ os.system(command)
addftool/util.py CHANGED
@@ -1,12 +1,75 @@
1
+ import os
1
2
  import subprocess
2
3
 
3
4
 
4
- def execute_command(command, to_file=None):
5
+ def execute_command(command, to_file=None, only_stdout=True, hide=False):
5
6
  if to_file is not None:
6
7
  to_file.write(command + "\n")
7
8
  return None
8
9
  else:
9
- print("Execute command: ", command)
10
- result = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE).stdout.read().decode()
11
- print("Result: ", result)
12
- return result
10
+ if not hide:
11
+ print("Execute command: ", command)
12
+ result = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
13
+ result.wait()
14
+ print(f"Return code: {result.returncode}")
15
+ if result.stdout is not None:
16
+ stdout = result.stdout.read().decode()
17
+ print(f"Stdout: {stdout}")
18
+ else:
19
+ stdout = None
20
+ if only_stdout:
21
+ if not hide and stdout is not None:
22
+ print(stdout)
23
+ return stdout
24
+ if result.stderr is not None:
25
+ stderr = result.stderr.read().decode()
26
+ print(f"Stderr: {stderr}")
27
+ else:
28
+ stderr = None
29
+
30
+ return {'stdout': stdout, 'stderr': stderr, 'returncode': result.returncode}
31
+
32
+
33
+ def need_sudo():
34
+ return os.name == 'posix' and os.getuid() != 0
35
+
36
+
37
+ def is_running_in_docker():
38
+ return os.path.exists('/.dockerenv') or \
39
+ any('docker' in line for line in open('/proc/self/cgroup', 'r')) if os.path.exists('/proc/self/cgroup') else False or \
40
+ os.environ.get('container') == 'docker' or \
41
+ os.environ.get('DOCKER') == 'true' or \
42
+ os.environ.get('DOCKER_CONTAINER') == 'yes'
43
+
44
+
45
+ def get_ubuntu_version():
46
+ with open("/etc/os-release") as f:
47
+ for line in f:
48
+ if line.startswith("VERSION_ID="):
49
+ version = line.split("=")[1].strip().strip('"')
50
+ return version
51
+ return "22.04"
52
+
53
+
54
+ def check_package_installed(package):
55
+ command = f"dpkg -l | grep {package}"
56
+ result = execute_command(command)
57
+ if result is not None and package in result:
58
+ return True
59
+ return False
60
+
61
+
62
+ def install_packages(package_list):
63
+ to_install = []
64
+ for package in package_list:
65
+ if check_package_installed(package):
66
+ print(f"{package} is already installed")
67
+ continue
68
+ to_install.append(package)
69
+
70
+ if len(to_install) > 0:
71
+ packages = " ".join(to_install)
72
+ command = f"apt-get install -y {packages}"
73
+ if need_sudo():
74
+ command = "sudo " + command
75
+ execute_command(command)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: addftool
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Requires-Dist: cryptography
5
5
  Requires-Dist: requests
6
6
  Requires-Dist: PyYAML
@@ -0,0 +1,17 @@
1
+ addftool/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ addftool/addf_portal.py,sha256=w2LgsoutfnrKhtrQAXouUMwLqnsp5ALlsBYUWg8n9NM,781
3
+ addftool/blob.py,sha256=NZOItDyFUIdV1tfhJZJJBEzGy296CE5NCictTzP4OPc,8282
4
+ addftool/tool.py,sha256=EuKQ2t2InN7yB-_oYLcdsA7vRqzRGTunwIxplUSqEG0,2054
5
+ addftool/util.py,sha256=zlNLu8Be8cGIpNRqBw8_0q7nFxWlsJ9cToN62ohjdXE,2335
6
+ addftool/deploy/__init__.py,sha256=tpyoTh3SqAQojPizsJDvQohu1Pcb3-w-DP5sO4-5lBM,1220
7
+ addftool/deploy/azure.py,sha256=UQR1hOEYUtsm2fbWBczsnEB_mh7yUuN2NDv3sgMMsac,1246
8
+ addftool/deploy/ssh_server.py,sha256=f2T8fgwACVljPfdcimMywUjsFnLCWRde7iWPAILpRz8,5463
9
+ addftool/process/__init__.py,sha256=gPdGsjMEET6crzOz4Iw5cmf6RR1toXGovydRXv8Uagk,3543
10
+ addftool/process/utils.py,sha256=me4HqMz5OgRcQMUJmVhKdTJh4SW5BB-pd_lq7g8-UwE,2252
11
+ addftool/ssh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ addftool/sync/__init__.py,sha256=wOqFCOA51rFUttBjOO44W3Fc66mhX5ir2R89lsO6gR0,1702
13
+ addftool-0.1.6.dist-info/METADATA,sha256=SQSnBFDxmD836XQAgZDtqvpzT_Z1LewNKTRCfdMC5ag,148
14
+ addftool-0.1.6.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
15
+ addftool-0.1.6.dist-info/entry_points.txt,sha256=9lkmuWMInwUAtev8w8poNkNd7iML9Bjd5CBCFVxg2b8,111
16
+ addftool-0.1.6.dist-info/top_level.txt,sha256=jqj56-plrBbyzY0tIxB6wPzjAA8kte4hUlajyyQygN4,9
17
+ addftool-0.1.6.dist-info/RECORD,,
@@ -1,12 +0,0 @@
1
- addftool/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- addftool/addf_portal.py,sha256=U52TdNcwWOEvv_C5r-guWYxn3ntzwYI2eBzJIE7IdcY,493
3
- addftool/blob.py,sha256=NZOItDyFUIdV1tfhJZJJBEzGy296CE5NCictTzP4OPc,8282
4
- addftool/tool.py,sha256=EuKQ2t2InN7yB-_oYLcdsA7vRqzRGTunwIxplUSqEG0,2054
5
- addftool/util.py,sha256=Q3A68vJDxgfeNiEFmk54HuMuworVndocXpSbVpvGMfc,362
6
- addftool/process/__init__.py,sha256=OB-cZXP1jK7l8uN8nKfhg_bCX6Slz6DeeBpEodt-IK4,3515
7
- addftool/process/utils.py,sha256=me4HqMz5OgRcQMUJmVhKdTJh4SW5BB-pd_lq7g8-UwE,2252
8
- addftool-0.1.4.dist-info/METADATA,sha256=ohQCdQdVevHRzMRu7ByPhBGxqPlxmEKnDxNmfcy_WII,148
9
- addftool-0.1.4.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
10
- addftool-0.1.4.dist-info/entry_points.txt,sha256=9lkmuWMInwUAtev8w8poNkNd7iML9Bjd5CBCFVxg2b8,111
11
- addftool-0.1.4.dist-info/top_level.txt,sha256=jqj56-plrBbyzY0tIxB6wPzjAA8kte4hUlajyyQygN4,9
12
- addftool-0.1.4.dist-info/RECORD,,