add init pxe cmd
This commit is contained in:
@@ -8,10 +8,13 @@ import types
|
||||
import syslog
|
||||
import inspect
|
||||
import argparse
|
||||
import subprocess
|
||||
import sunhpc.util
|
||||
import sunhpc.utils
|
||||
|
||||
from io import StringIO
|
||||
from typing import Dict
|
||||
from pathlib import Path
|
||||
from typing import Dict, Optional, Tuple, List, Union
|
||||
|
||||
from sunhpc.logs import Logs
|
||||
from sunhpc.disks import DiskInfo
|
||||
@@ -19,6 +22,9 @@ from sunhpc.configs import Config
|
||||
from sunhpc.network import Network
|
||||
from sunhpc.memory import MemoryInfo
|
||||
from sunhpc.output import Output
|
||||
from sunhpc.firewalld import FWManager
|
||||
|
||||
from sunhpc.utils.shells import ShellExecutor
|
||||
|
||||
from xml.sax import saxutils
|
||||
from xml.sax import handler
|
||||
@@ -335,12 +341,15 @@ class Command:
|
||||
self.mem = MemoryInfo()
|
||||
self.disk = DiskInfo()
|
||||
self.fmt = Output()
|
||||
self.sh = ShellExecutor()
|
||||
self.fw = FWManager('sunhpc')
|
||||
|
||||
self.os = os.uname()[0].lower()
|
||||
self.arch = os.uname()[4]
|
||||
self.user = pwd.getpwuid(os.getuid()).pw_name
|
||||
|
||||
self.parser = argparse.ArgumentParser()
|
||||
self.parserArgs = []
|
||||
self.subcommand = 'Sub Command'
|
||||
self.subdesc = None
|
||||
self.epilog = None
|
||||
@@ -392,6 +401,77 @@ class Command:
|
||||
else:
|
||||
return 'no'
|
||||
|
||||
def rsync_copy(
|
||||
self,
|
||||
src: str,
|
||||
dst: str,
|
||||
options: str = '-ah --info=progress2'
|
||||
) -> bool:
|
||||
"""
|
||||
简化版本的rsync拷贝、专注于进度显示
|
||||
|
||||
Args:
|
||||
src: 源路径
|
||||
dst: 目标路径
|
||||
|
||||
Returns:
|
||||
bool: 是否成功
|
||||
"""
|
||||
options = options.split()
|
||||
|
||||
cmd = ["rsync"]
|
||||
cmd.extend(options)
|
||||
|
||||
cmd.append(src)
|
||||
cmd.append(dst)
|
||||
|
||||
self.log.info(f"执行命令: {' '.join(cmd)}")
|
||||
try:
|
||||
# 使用Popen实时显示输出
|
||||
process = subprocess.Popen(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
bufsize=1
|
||||
)
|
||||
|
||||
# 实时打印输出
|
||||
for line in process.stdout:
|
||||
# 去除末尾换行符
|
||||
line = line.rstrip('\n\r')
|
||||
|
||||
if line:
|
||||
# 计算需要覆盖的长度(使用退格符或直接回车)
|
||||
# 方法1:使用 \r 回车覆盖(推荐)
|
||||
print(f'\r{line}', end='', flush=True)
|
||||
last_line = line
|
||||
else:
|
||||
# 空行,换行
|
||||
print()
|
||||
|
||||
# 输出完成后换行,避免下一行输出覆盖进度信息
|
||||
if last_line:
|
||||
print()
|
||||
|
||||
return_code = process.wait()
|
||||
|
||||
if return_code == 0:
|
||||
self.log.info("\n✓ 拷贝成功完成")
|
||||
return True
|
||||
else:
|
||||
self.log.error(f"\n✗ 拷贝失败,返回码: {return_code}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 执行失败: {e}")
|
||||
return False
|
||||
|
||||
def is_remote_path(self, path: str) -> bool:
|
||||
"""判断是否为远程路径"""
|
||||
return '@' in path and ':' in path and not path.startswith(':')
|
||||
|
||||
|
||||
def dtons(self, data: dict) -> types.SimpleNamespace:
|
||||
'''递归将字典转换为 SimpleNamespace'''
|
||||
if isinstance(data, dict):
|
||||
@@ -544,6 +624,13 @@ class Command:
|
||||
else:
|
||||
return ' '.join(plist)
|
||||
|
||||
def output_dict(self, data={}):
|
||||
if not data: return
|
||||
|
||||
max_key_len = max(len(str(key)) for key in data.keys())
|
||||
for key, value in data.items():
|
||||
print(f"{str(key):<{max_key_len}} : {value}")
|
||||
|
||||
def command(self, command, args=[]):
|
||||
'''Import and run a Sunhpc command.
|
||||
Returns and output string.
|
||||
@@ -599,13 +686,14 @@ class Command:
|
||||
|
||||
rlist = []
|
||||
for (key, default) in dlist:
|
||||
if 'key' in params:
|
||||
if key in params:
|
||||
rlist.append(params[key])
|
||||
else:
|
||||
rlist.append(default)
|
||||
|
||||
return rlist
|
||||
|
||||
def fillPositionalArgs(self, names, params=None, args=None):
|
||||
def fillPostArgs(self, names, params=None, args=None):
|
||||
'''
|
||||
The helper function will allow named parameters
|
||||
to be used in lieu of positional arguments
|
||||
@@ -632,7 +720,7 @@ class Command:
|
||||
Returns:
|
||||
remaining args, Filled parameters
|
||||
Example::
|
||||
hostlist, iface, mac = self.fillPositionalArgs(
|
||||
hostlist, iface, mac = self.fillPostArgs(
|
||||
('iface','mac'), params, args)
|
||||
'''
|
||||
|
||||
@@ -690,9 +778,14 @@ class Command:
|
||||
plist = [] # arguments
|
||||
|
||||
nparams = 0
|
||||
flagpattern = re.compile(r'^-[a-zA-Z0-9-_+]+=')
|
||||
flagpattern = re.compile(r'^[a-zA-Z0-9-_+]+=')
|
||||
|
||||
for arg in args:
|
||||
# 检查 - 或 -- 开头
|
||||
if arg.startswith('--') or arg.startswith('-'):
|
||||
self.parserArgs.append(arg)
|
||||
continue
|
||||
|
||||
tokens = arg.split()
|
||||
if tokens[0] == 'select':
|
||||
plist.append(arg)
|
||||
|
||||
@@ -12,106 +12,107 @@ class Command(sunhpc.commands.init.command):
|
||||
提供一个内网的接口、例如: eth1
|
||||
</arg>
|
||||
|
||||
<arg type='string' name='mnt'>
|
||||
提供一个系统ISO文件、或者挂载路径、例如: /mnt/cdrom
|
||||
</arg>
|
||||
|
||||
<param type='string' name='iface'>
|
||||
提供一个内网的接口、例如: eth1
|
||||
</param>
|
||||
|
||||
<param type='string' name='mnt'>
|
||||
提供一个系统ISO文件、或者挂载路径、例如: /mnt/cdrom
|
||||
</param>
|
||||
|
||||
<arguments>
|
||||
-h --help 显示帮助信息
|
||||
-d --debug 开启调试模式
|
||||
-v --verbose 显示详细信息
|
||||
</arguments>
|
||||
|
||||
<example cmd='init config eth1 /mnt/cdrom'>
|
||||
使用eth1网络接口、和 /mnt/cdrom 挂载路径
|
||||
<example cmd='init config eth1 '>
|
||||
使用eth1网络接口
|
||||
</example>
|
||||
|
||||
<example cmd='init config iface=eth1 mnt=/mnt/cdrom'>
|
||||
使用eth1网络接口、和 /mnt/cdrom 挂载路径
|
||||
<example cmd='init config iface=eth1'>
|
||||
使用eth1网络接口
|
||||
</example>
|
||||
"""
|
||||
def run(self, params, args):
|
||||
self.parser_cmd_init()
|
||||
self.parser.add_argument('-i', '--iface', action='store', help='Interface name')
|
||||
self.parser.add_argument('-d', '--debug', action='store_true', help='Debug mode')
|
||||
self.parser.add_argument('-f', '--file', action='store_true', help='Configuration file')
|
||||
(args, iface) = self.fillPostArgs(('iface',))
|
||||
|
||||
self.parser.add_argument(
|
||||
'iface',
|
||||
help='Network interface (required, e.g., eth0, eth1)'
|
||||
)
|
||||
if not iface:
|
||||
self.abort('must supply an interface')
|
||||
|
||||
self.parser.add_argument(
|
||||
'mnt',
|
||||
nargs='?',
|
||||
default='/mnt/cdrom',
|
||||
help='Mount point (optional, default: /mnt/cdrom)'
|
||||
)
|
||||
self.net.setiface(iface)
|
||||
|
||||
parsed_params = self.parser_cmd_args(args)
|
||||
ipaddr = self.net.getip()
|
||||
if ipaddr is None:
|
||||
self.abort('interface "%s" has no ip address' % iface)
|
||||
|
||||
self.log.info('File "/opt/sunhpc/lib/sunhpc/sunhpc/commands/init/config/__init__.py", line 63, in run File "/opt/sunhpc/lib/sunhpc/sunhpc/commands/init/config/__init__.py", line 63, in run')
|
||||
#print (parsed_params)
|
||||
iface = parsed_params.get('iface', 'eth0')
|
||||
|
||||
|
||||
'''
|
||||
config = Config()
|
||||
config.iface = 'eth1'
|
||||
config.mnt = '/mnt/cdrom'
|
||||
config.network = '1.1.1.1'
|
||||
config.netmask = '255.255.255.0'
|
||||
config.gateway = '1.1.1.1'
|
||||
|
||||
config.dhcp = Config()
|
||||
config.dhcp.enabled = True
|
||||
config.dhcp.server = '1.1.1.1'
|
||||
config.dhcp.options = ['domain-name', 'domain-name-servers']
|
||||
|
||||
config.http = Config()
|
||||
config.http.enabled = True
|
||||
config.http.server = '1.1.1.1'
|
||||
|
||||
config.api = Config()
|
||||
config.api.enabled = True
|
||||
config.api.server = '1.1.1.1'
|
||||
|
||||
config.save('/tmp/sunhpc.yaml')
|
||||
|
||||
self.net.setiface('eth0')
|
||||
print (f'Interface: {self.net.iface}')
|
||||
print (f'IP : {self.net.getip()}')
|
||||
print (f'Network: {self.net.getnetwork()}')
|
||||
print (f'Netmask: {self.net.getnetmask()}')
|
||||
print (f'Gateway: {self.net.getgateway()}')
|
||||
print (f'MAC : {self.net.getmac()}')
|
||||
print (f'CIDR : {self.net.getcidr()}')
|
||||
print (f'IPv6 : {self.net.getipv6()}')
|
||||
|
||||
rx, tx = self.net.get_transfer_human()
|
||||
print (f'RX : {rx}')
|
||||
print (f'TX : {tx}')
|
||||
|
||||
#print (self.disk.get_disk_info('sda'))
|
||||
#print (self.mem.get_memory_summary())
|
||||
#print (self.mem.get_memory_info())
|
||||
|
||||
#self.fmt.add_header(['Interface', 'IP', 'Network', 'Netmask', 'Gateway', 'MAC', 'CIDR', 'IPv6'])
|
||||
|
||||
d1 = {
|
||||
'name', 'alice',
|
||||
'age', 18,
|
||||
'city', 'beijing',
|
||||
'occupation', 'student'
|
||||
config_file = self.conf.getConfFile()
|
||||
config_dict = {
|
||||
'iface': iface,
|
||||
'ipaddr': ipaddr,
|
||||
'netmask': self.net.getnetmask(),
|
||||
'network': self.net.getnetwork(),
|
||||
'mac': self.net.getmac(),
|
||||
'cidr': self.net.getcidr(),
|
||||
'dnsmasq': {
|
||||
'enabled': True,
|
||||
'config': '/etc/dnsmasq.d/sunhpc.conf',
|
||||
'server': self.net.getip(),
|
||||
'start_ip': '.'.join(ipaddr.split('.')[:-1]) + '.100',
|
||||
'end_ip': '.'.join(ipaddr.split('.')[:-1]) + '.200',
|
||||
'dns': '223.5.5.5',
|
||||
'systemd_name': 'dnsmasq',
|
||||
},
|
||||
'http': {
|
||||
'enabled': True,
|
||||
'wwwroot': '/var/www/html',
|
||||
'config': '/etc/httpd/conf.d/sunhpc.conf',
|
||||
'httpaddr': 'http://%s' % ipaddr,
|
||||
'systemd_name': 'httpd',
|
||||
},
|
||||
'tftp': {
|
||||
'enabled': False,
|
||||
'tftpboot': '/srv/pxelinux/tftpboot',
|
||||
'systemd_name': 'tftp-server',
|
||||
},
|
||||
'nfs': {
|
||||
'enabled': True,
|
||||
'paths': [
|
||||
{
|
||||
'path': '/home',
|
||||
'options': 'rw,sync'
|
||||
},
|
||||
{
|
||||
'path': '/opt',
|
||||
'options': 'rw,sync,no_root_squash'
|
||||
},
|
||||
],
|
||||
'systemd_name': 'nfs-server',
|
||||
},
|
||||
'ssh': {
|
||||
'key_types': [
|
||||
'ssh-rsa',
|
||||
'ssh-dss',
|
||||
'ssh-ed25519',
|
||||
]
|
||||
},
|
||||
'firewall': {
|
||||
'enabled': True,
|
||||
'backend': 'firewalld',
|
||||
},
|
||||
'osinfo': {
|
||||
'basename': 'sunhpc',
|
||||
'os': 'rocky',
|
||||
'version': '9.7',
|
||||
},
|
||||
'pxe':{
|
||||
'bios': 'boot/undionly.kpxe',
|
||||
'uefi': 'boot/bootx64.efi',
|
||||
'ipxe': 'boot/ipxe.efi',
|
||||
'ksfile': 'scripts/rhel.ks',
|
||||
'ipxeboot': 'scripts/ipxe.sh',
|
||||
'repo': 'sunhpc/rockylinux/9.7',
|
||||
'initrd': 'images/pxeboot/initrd.img',
|
||||
'vmlinuz': 'images/pxeboot/vmlinuz',
|
||||
},
|
||||
'paths': {
|
||||
'bin': '/opt/sunhpc/bin',
|
||||
'etc': '/opt/sunhpc/etc',
|
||||
'lib': '/opt/sunhpc/lib',
|
||||
'var': '/opt/sunhpc/var',
|
||||
'pkgs': '/srv/repos/pkgs',
|
||||
'repo': '/srv/repos/rockylinux/9.7',
|
||||
}
|
||||
}
|
||||
|
||||
self.fmt.dict_output(d1)
|
||||
'''
|
||||
self.conf.save(config_dict=config_dict)
|
||||
|
||||
264
lib/sunhpc/sunhpc/commands/init/pxe/__init__.py
Normal file
264
lib/sunhpc/sunhpc/commands/init/pxe/__init__.py
Normal file
@@ -0,0 +1,264 @@
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
import sunhpc.commands
|
||||
from sunhpc.configs import Config
|
||||
from sunhpc.paths import ipxe_path, scripts_path
|
||||
|
||||
class Command(sunhpc.commands.init.command):
|
||||
"""
|
||||
这个命令是初始化系统Pxe引导配置服务.
|
||||
<arg type='string' name='ISOFile'>
|
||||
提供一个系统ISO挂载点、例如: /mnt/cdrom
|
||||
或者提供一个ISO文件路径、例如: /path/to/linux.iso
|
||||
或者提供一个ISO文件URL、例如: http://example.com/linux.iso
|
||||
</arg>
|
||||
<example cmd='init pxe /mnt/cdrom'>
|
||||
初始化Pxe引导配置服务
|
||||
</example>
|
||||
"""
|
||||
def run(self, params, args):
|
||||
|
||||
(args, mnt_src) = self.fillPostArgs(('mntPath', ))
|
||||
|
||||
if not mnt_src:
|
||||
mnt_src = '/mnt/cdrom'
|
||||
|
||||
if not os.path.exists(mnt_src):
|
||||
self.log.error(f"挂载点不存在: {mnt_src}")
|
||||
self.abort("请挂载一下受支持的Linux系统ISO文件.")
|
||||
|
||||
# sunhpc
|
||||
base_nm = self.conf.osinfo.basename
|
||||
# /srv/repos/sunhpc
|
||||
mnt_dst = os.path.join('/srv/repos', base_nm)
|
||||
|
||||
iface = self.conf.iface
|
||||
ipaddr = self.conf.ipaddr
|
||||
|
||||
treeinfo = os.path.join(mnt_src, '.treeinfo')
|
||||
if not os.path.exists(treeinfo):
|
||||
self.log.error(f"不是一个有效或不受支持的Linux系统ISO挂载路径: {mnt_src}")
|
||||
self.abort("重新挂载一下受支持的Linux系统ISO文件.")
|
||||
|
||||
info = {}
|
||||
with open(treeinfo, 'r') as f:
|
||||
for i in f.readlines():
|
||||
tmp = i.strip().split('=', 1)
|
||||
if len(tmp) == 2:
|
||||
info[tmp[0].strip()] = tmp[1].strip()
|
||||
|
||||
osname = info.get('family', 'unknown').split()[0].lower()
|
||||
if osname not in ['rocky', 'rhel', 'centos']:
|
||||
self.log.error(f"不支持的系统类型: {osname}")
|
||||
self.abort("请提供一个受支持的Linux系统ISO文件. 只支持Rocky, RHEL, CentOS系统.")
|
||||
|
||||
kernel = info.get('kernel', None)
|
||||
if kernel is None:
|
||||
self.log.error(f"没有找到内核文件: {kernel}")
|
||||
self.abort("请提供一个支持 Pxe 的 vmlinuz 文件位置.")
|
||||
|
||||
initrd = info.get('initrd', None)
|
||||
if initrd is None:
|
||||
self.log.error(f"没有找到初始化文件: {initrd}")
|
||||
self.abort("请提供一个支持 Pxe 的 initrd 文件位置.")
|
||||
|
||||
osvers = info.get('version', 'unknown')
|
||||
http_head = self.conf.http.httpaddr
|
||||
http_root = f"{http_head}/{base_nm}/{osname}/{osvers}"
|
||||
http_ksfile = f"{http_root}/{base_nm}/{self.conf.pxe.ksfile}"
|
||||
http_init = f"{http_root}/{base_nm}/{self.conf.pxe.initfile}"
|
||||
lrepo_src = os.path.join(mnt_dst, osname, osvers)
|
||||
if not os.path.exists(lrepo_src):
|
||||
os.makedirs(lrepo_src)
|
||||
|
||||
# 复制 ISO 文件到目标目录
|
||||
if not mnt_src.endswith('/'):
|
||||
mnt_src = mnt_src + os.sep
|
||||
|
||||
if not lrepo_src.endswith('/'):
|
||||
lrepo_src = lrepo_src + os.sep
|
||||
|
||||
self.rsync_copy(mnt_src, lrepo_src)
|
||||
|
||||
# 拷贝scripts目录到目标目录.
|
||||
scripts_dst = mnt_dst + os.sep
|
||||
self.rsync_copy(scripts_path, scripts_dst)
|
||||
|
||||
# 安装 httpd、dnsmasq 服务
|
||||
#result = self.sh.execute("dnf install -y httpd dnsmasq")
|
||||
|
||||
wwwroot = self.conf.http.wwwroot
|
||||
tftpboot = self.conf.tftp.tftpboot
|
||||
vmlinuz = os.path.join(lrepo_src, kernel)
|
||||
initrd = os.path.join(lrepo_src, initrd)
|
||||
hostname = self.sh.execute("hostname", quiet=True).output().strip()
|
||||
|
||||
# 创建软连接
|
||||
self.sh.execute(f"ln -s {mnt_dst} {wwwroot}", quiet=True)
|
||||
|
||||
# 创建tftpboot目录
|
||||
pxe_boot_src = ipxe_path + os.sep
|
||||
pxe_boot_dst = os.path.join(tftpboot, 'boot') + os.sep
|
||||
self.sh.execute(f"mkdir -p {pxe_boot_dst}", quiet=True)
|
||||
|
||||
# 拷贝pxe引导文件到tftpboot目录
|
||||
self.rsync_copy(pxe_boot_src, pxe_boot_dst)
|
||||
|
||||
# 配置 httpd 服务
|
||||
httpd_conf = self.conf.http.config
|
||||
self.create_httpd(hostname, base_nm, wwwroot, httpd_conf)
|
||||
|
||||
# 配置 dnsmasq 服务
|
||||
start_ip = self.conf.dnsmasq.start_ip
|
||||
end_ip = self.conf.dnsmasq.end_ip
|
||||
addr_dns = self.conf.dnsmasq.dns
|
||||
bios = self.conf.pxe.bios
|
||||
ipxe = self.conf.pxe.ipxe
|
||||
ipxe_sh = self.conf.pxe.ipxeboot
|
||||
|
||||
ipxe_http = f"{http_head}/{base_nm}/{ipxe_sh}"
|
||||
dnsmasq_conf = self.conf.dnsmasq.config
|
||||
|
||||
self.create_dnsmasq(iface,
|
||||
ipaddr, tftpboot, dnsmasq_conf,
|
||||
start_ip, end_ip, addr_dns, bios, ipxe, ipxe_http)
|
||||
|
||||
# kickstart
|
||||
ksfile_src = self.conf.pxe.ksfile
|
||||
ksfile_dst = os.path.join(scripts_dst, ksfile_src)
|
||||
self.create_ksfile(hostname, osvers, http_root, http_init, ksfile_dst)
|
||||
|
||||
# 配置 firewalld 服务
|
||||
self.fw.load()
|
||||
self.fw.add_port('80', 'tcp')
|
||||
self.fw.add_port('443', 'tcp')
|
||||
self.fw.save()
|
||||
|
||||
def create_ksfile(self, hostname, osvers, http_root, http_init, ksfile_dst):
|
||||
ksfile_cnf = f"""
|
||||
# Kickstart file for {hostname}
|
||||
# Created by sunhpc
|
||||
# Version: {osvers}
|
||||
|
||||
graphical
|
||||
timezone Asia/Shanghai --utc
|
||||
keyboard --xlayouts="us"
|
||||
lang en_US.UTF-8
|
||||
selinux --disabled
|
||||
|
||||
url --url='{http_root}'
|
||||
|
||||
network --bootproto=dhcp --device=link --ipv6=auto --activate
|
||||
# autopart --type=lvm
|
||||
# autopart --type=plain
|
||||
# autopart --nohome
|
||||
# autopart --noswap
|
||||
|
||||
%include /tmp/diskinfo
|
||||
|
||||
%packages
|
||||
@^minimal-environment
|
||||
@development
|
||||
@standard
|
||||
vim
|
||||
wget
|
||||
curl
|
||||
autofs
|
||||
nfs-utils
|
||||
nfs4-acl-tools
|
||||
sssd-nfs-idmap
|
||||
%end
|
||||
|
||||
rootpw --plaintext "admin_b101"
|
||||
user --name=dell --plaintext --password="admin_b101" --gecos="dell"
|
||||
reboot
|
||||
|
||||
%pre --interpreter=/bin/bash
|
||||
if [ -d /sys/firmware/efi ]; then
|
||||
cat > /tmp/diskinfo <<EOF
|
||||
clearpart --all --initlabel
|
||||
part /boot/efi --fstype=efi --size=600 --fsoptions="umask=0077,shortname=uefi"
|
||||
part /boot --fstype=xfs --size=1024
|
||||
part pv.01 --size=1 --grow
|
||||
volgroup vg_sys pv.01
|
||||
logvol / --fstype=xfs --name=root --vgname=vg_sys --size=51200
|
||||
logvol swap --fstype=swap --name=swap --vgname=vg_sys --size=4096
|
||||
logvol /data --fstype=xfs --name=data --vgname=vg_sys --size=1 --grow
|
||||
EOF
|
||||
else
|
||||
cat > /tmp/diskinfo <<EOF
|
||||
clearpart --all --initlabel
|
||||
part /boot --fstype=xfs --size=1024 --asprimary
|
||||
part pv.01 --size=1 --grow
|
||||
volgroup vg_sys pv.01
|
||||
logvol / --fstype=xfs --name=root --vgname=vg_sys --size=51200
|
||||
logvol swap --fstype=swap --name=swap --vgname=vg_sys --size=4096
|
||||
logvol /data --fstype=xfs --name=data --vgname=vg_sys --size=1 --grow
|
||||
EOF
|
||||
fi
|
||||
%end
|
||||
|
||||
%post
|
||||
curl -s -o /tmp/init.sh {http_init}
|
||||
chmod +x /tmp/init.sh
|
||||
/tmp/init.sh
|
||||
%end
|
||||
|
||||
%addon com_redhat_kdump --disable
|
||||
%end
|
||||
"""
|
||||
with open(ksfile_dst, 'w') as f:
|
||||
f.write(textwrap.dedent(ksfile_cnf))
|
||||
|
||||
def create_dnsmasq(self,
|
||||
iface, ipaddr, tftpboot, dnsmasq_conf,
|
||||
start_ip, end_ip, addr_dns, bios, ipxe, ipxe_http):
|
||||
dnsmasq_tmpl = f"""
|
||||
interface={iface}
|
||||
bind-interfaces
|
||||
port=0
|
||||
|
||||
enable-tftp
|
||||
tftp-root={tftpboot}
|
||||
|
||||
# Gateway:3, DNS:6
|
||||
dhcp-range={start_ip},{end_ip},12h
|
||||
dhcp-option=3,{ipaddr}
|
||||
dhcp-option=6,{addr_dns}
|
||||
|
||||
dhcp-match=set:ipxe,175
|
||||
dhcp-match=set:bios,option:client-arch,0
|
||||
dhcp-match=set:uefi,option:client-arch,7
|
||||
dhcp-match=set:uefi,option:client-arch,9
|
||||
dhcp-match=set:ipxe,option:user-class,ipxe
|
||||
|
||||
dhcp-boot=tag:bios,tag:!ipxe,{bios}
|
||||
dhcp-boot=tag:uefi,tag:!ipxe,{ipxe}
|
||||
dhcp-boot=tag:ipxe,{ipxe_http}
|
||||
"""
|
||||
with open(dnsmasq_conf, 'w') as f:
|
||||
f.write(textwrap.dedent(dnsmasq_tmpl))
|
||||
|
||||
def create_httpd(self, hostname, base_nm, wwwroot, httpd_conf):
|
||||
httpd_tmpl = f"""
|
||||
Alias /{base_nm} {wwwroot}/{base_nm}
|
||||
|
||||
UseCanonicalName Off
|
||||
ServerName {hostname}
|
||||
|
||||
<Directory "{wwwroot}/{base_nm}">
|
||||
Options Indexes FollowSymLinks
|
||||
AllowOverride None
|
||||
Require all granted
|
||||
|
||||
EnableSendfile on
|
||||
</Directory>
|
||||
"""
|
||||
with open(httpd_conf, 'w') as f:
|
||||
f.write(textwrap.dedent(httpd_tmpl))
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -31,6 +31,9 @@ class Config:
|
||||
self._build_attributes()
|
||||
self._initialized = True
|
||||
|
||||
def getConfFile(self):
|
||||
return self._config_path
|
||||
|
||||
def _build_attributes(self):
|
||||
"""构建属性访问"""
|
||||
self._build_from_dict(self._data)
|
||||
@@ -98,17 +101,26 @@ class Config:
|
||||
# 如果属性不存在,返回 None(可选行为)
|
||||
return None
|
||||
|
||||
def save(self, path: Optional[str] = None):
|
||||
def save(self, path: Optional[str] = None, config_dict: Optional[Dict] = None):
|
||||
"""保存配置到文件"""
|
||||
save_path = path or self._config_path
|
||||
if not save_path:
|
||||
raise ValueError("未指定保存路径")
|
||||
|
||||
data = self.to_dict()
|
||||
if config_dict:
|
||||
data = config_dict
|
||||
|
||||
# 确保目录存在
|
||||
Path(save_path).parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with open(save_path, 'w', encoding='utf-8') as f:
|
||||
yaml.dump(self.to_dict(), f, default_flow_style=False, indent=2, allow_unicode=True)
|
||||
yaml.dump(data, f,
|
||||
indent=4,
|
||||
sort_keys=False,
|
||||
allow_unicode=True,
|
||||
default_flow_style=False,
|
||||
)
|
||||
|
||||
print(f"配置已保存到: {save_path}")
|
||||
|
||||
|
||||
328
lib/sunhpc/sunhpc/firewalld.py
Normal file
328
lib/sunhpc/sunhpc/firewalld.py
Normal file
@@ -0,0 +1,328 @@
|
||||
"""
|
||||
Firewalld 自定义服务管理工具
|
||||
用于创建和修改 /etc/firewalld/services/ 目录下的自定义服务 XML 文件
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
from xml.dom import minidom
|
||||
import xml.etree.ElementTree as ET
|
||||
from sunhpc.logs import Logs
|
||||
|
||||
slog = Logs(name="Firewd", show_time=True)
|
||||
|
||||
class FWManager:
|
||||
"""Firewalld 服务文件管理器"""
|
||||
|
||||
# firewalld 服务目录路径
|
||||
SYSTEM_SERVICES_DIR = Path('/usr/lib/firewalld/services')
|
||||
CUSTOM_SERVICES_DIR = Path('/etc/firewalld/services')
|
||||
|
||||
def __init__(self, service_name):
|
||||
"""
|
||||
初始化服务管理器
|
||||
|
||||
Args:
|
||||
service_name: 服务名称(不含 .xml 后缀)
|
||||
"""
|
||||
self.service_name = service_name
|
||||
self.service_file = self.CUSTOM_SERVICES_DIR / f"{service_name}.xml"
|
||||
self.xml_tree = None
|
||||
self.root = None
|
||||
|
||||
def _ensure_custom_dir(self):
|
||||
"""确保自定义服务目录存在"""
|
||||
self.CUSTOM_SERVICES_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def _create_xml_structure(self):
|
||||
"""创建基本的 XML 结构"""
|
||||
# 创建根元素
|
||||
self.root = ET.Element('service')
|
||||
|
||||
# 添加 short 元素
|
||||
short = ET.SubElement(self.root, 'short')
|
||||
short.text = self.service_name.capitalize()
|
||||
|
||||
# 添加 description 元素
|
||||
description = ET.SubElement(self.root, 'description')
|
||||
description.text = f"Custom service: {self.service_name}"
|
||||
|
||||
# 添加 port 元素(稍后添加)
|
||||
# 添加 protocol 元素(稍后添加)
|
||||
|
||||
self.xml_tree = ET.ElementTree(self.root)
|
||||
|
||||
def _prettify_xml(self, elem):
|
||||
"""
|
||||
格式化 XML 输出
|
||||
|
||||
Args:
|
||||
elem: XML 元素
|
||||
|
||||
Returns:
|
||||
str: 格式化后的 XML 字符串
|
||||
"""
|
||||
rough_string = ET.tostring(elem, 'utf-8')
|
||||
reparsed = minidom.parseString(rough_string)
|
||||
return reparsed.toprettyxml(indent=' ')
|
||||
|
||||
def _save_xml(self):
|
||||
"""保存 XML 文件到自定义服务目录"""
|
||||
self._ensure_custom_dir()
|
||||
|
||||
# 格式化 XML
|
||||
xml_str = self._prettify_xml(self.root)
|
||||
|
||||
# 写入文件
|
||||
with open(self.service_file, 'w', encoding='utf-8') as f:
|
||||
# 移除多余的 XML 声明(firewalld 不需要)
|
||||
if xml_str.startswith('<?xml'):
|
||||
xml_str = xml_str.split('\n', 1)[1]
|
||||
f.write(xml_str)
|
||||
|
||||
# 设置正确的权限(644)
|
||||
os.chmod(self.service_file, 0o644)
|
||||
|
||||
def load(self):
|
||||
"""
|
||||
加载现有服务文件或创建新文件
|
||||
|
||||
Returns:
|
||||
bool: 是否成功加载/创建
|
||||
"""
|
||||
if self.service_file.exists():
|
||||
# 加载现有文件
|
||||
try:
|
||||
self.xml_tree = ET.parse(self.service_file)
|
||||
self.root = self.xml_tree.getroot()
|
||||
slog.info(f"✓ 已加载现有服务: {self.service_file}")
|
||||
return True
|
||||
except ET.ParseError as e:
|
||||
slog.error(f"✗ 解析 XML 文件失败: {e}")
|
||||
return False
|
||||
else:
|
||||
# 创建新文件
|
||||
slog.info(f"服务不存在,将创建新服务: {self.service_name}")
|
||||
self._create_xml_structure()
|
||||
return True
|
||||
|
||||
def set_short_description(self, short_text):
|
||||
"""
|
||||
设置服务简短描述
|
||||
|
||||
Args:
|
||||
short_text: 简短描述文本
|
||||
"""
|
||||
short_elem = self.root.find('short')
|
||||
if short_elem is None:
|
||||
short_elem = ET.SubElement(self.root, 'short')
|
||||
short_elem.text = short_text
|
||||
slog.info(f"✓ 设置简短描述: {short_text}")
|
||||
|
||||
def set_description(self, desc_text):
|
||||
"""
|
||||
设置服务详细描述
|
||||
|
||||
Args:
|
||||
desc_text: 详细描述文本
|
||||
"""
|
||||
desc_elem = self.root.find('description')
|
||||
if desc_elem is None:
|
||||
desc_elem = ET.SubElement(self.root, 'description')
|
||||
desc_elem.text = desc_text
|
||||
slog.info(f"✓ 设置详细描述: {desc_text}")
|
||||
|
||||
def add_port(self, port, protocol='tcp'):
|
||||
"""
|
||||
添加端口规则
|
||||
|
||||
Args:
|
||||
port: 端口号或端口范围(例如:'8080' 或 '3000-3010')
|
||||
protocol: 协议类型(tcp/udp/sctp/dccp)
|
||||
"""
|
||||
# 查找是否已存在相同的端口规则
|
||||
for port_elem in self.root.findall('port'):
|
||||
if port_elem.get('port') == str(port) and port_elem.get('protocol') == protocol:
|
||||
slog.info(f"⚠ 跳过,已存在, 端口 {port}/{protocol}")
|
||||
return
|
||||
|
||||
# 添加新端口
|
||||
port_elem = ET.SubElement(self.root, 'port')
|
||||
port_elem.set('port', str(port))
|
||||
port_elem.set('protocol', protocol)
|
||||
slog.info(f"✓ 添加端口: {port}/{protocol}")
|
||||
|
||||
def remove_port(self, port, protocol='tcp'):
|
||||
"""
|
||||
移除端口规则
|
||||
|
||||
Args:
|
||||
port: 端口号或端口范围
|
||||
protocol: 协议类型
|
||||
"""
|
||||
for port_elem in self.root.findall('port'):
|
||||
if port_elem.get('port') == str(port) and port_elem.get('protocol') == protocol:
|
||||
self.root.remove(port_elem)
|
||||
slog.info(f"✓ 移除端口: {port}/{protocol}")
|
||||
return
|
||||
slog.info(f"⚠ 未找到端口: {port}/{protocol}")
|
||||
|
||||
def add_protocol(self, protocol_name):
|
||||
"""
|
||||
添加协议规则(IP 协议,不是传输层协议)
|
||||
|
||||
Args:
|
||||
protocol_name: 协议名称(如 ipv6-icmp, icmp, igmp 等)
|
||||
"""
|
||||
for proto_elem in self.root.findall('protocol'):
|
||||
if proto_elem.get('name') == protocol_name:
|
||||
slog.info(f"⚠ 协议 {protocol_name} 已存在,跳过")
|
||||
return
|
||||
|
||||
proto_elem = ET.SubElement(self.root, 'protocol')
|
||||
proto_elem.set('name', protocol_name)
|
||||
slog.info(f"✓ 添加协议: {protocol_name}")
|
||||
|
||||
def remove_protocol(self, protocol_name):
|
||||
"""
|
||||
移除协议规则
|
||||
|
||||
Args:
|
||||
protocol_name: 协议名称
|
||||
"""
|
||||
for proto_elem in self.root.findall('protocol'):
|
||||
if proto_elem.get('name') == protocol_name:
|
||||
self.root.remove(proto_elem)
|
||||
slog.info(f"✓ 移除协议: {protocol_name}")
|
||||
return
|
||||
slog.info(f"⚠ 未找到协议: {protocol_name}")
|
||||
|
||||
def add_module(self, module_name):
|
||||
"""
|
||||
添加内核模块依赖
|
||||
|
||||
Args:
|
||||
module_name: 模块名称(如 nf_conntrack_ftp)
|
||||
"""
|
||||
for module_elem in self.root.findall('module'):
|
||||
if module_elem.get('name') == module_name:
|
||||
slog.info(f"⚠ 模块 {module_name} 已存在,跳过")
|
||||
return
|
||||
|
||||
module_elem = ET.SubElement(self.root, 'module')
|
||||
module_elem.set('name', module_name)
|
||||
slog.info(f"✓ 添加模块: {module_name}")
|
||||
|
||||
def remove_module(self, module_name):
|
||||
"""
|
||||
移除内核模块依赖
|
||||
|
||||
Args:
|
||||
module_name: 模块名称
|
||||
"""
|
||||
for module_elem in self.root.findall('module'):
|
||||
if module_elem.get('name') == module_name:
|
||||
self.root.remove(module_elem)
|
||||
slog.info(f"✓ 移除模块: {module_name}")
|
||||
return
|
||||
slog.info(f"⚠ 未找到模块: {module_name}")
|
||||
|
||||
def get_ports(self):
|
||||
"""获取所有端口配置"""
|
||||
ports = []
|
||||
for port_elem in self.root.findall('port'):
|
||||
ports.append({
|
||||
'port': port_elem.get('port'),
|
||||
'protocol': port_elem.get('protocol')
|
||||
})
|
||||
return ports
|
||||
|
||||
def get_protocols(self):
|
||||
"""获取所有协议配置"""
|
||||
protocols = []
|
||||
for proto_elem in self.root.findall('protocol'):
|
||||
protocols.append(proto_elem.get('name'))
|
||||
return protocols
|
||||
|
||||
def display_info(self):
|
||||
"""显示服务信息"""
|
||||
slog.info("\n" + "="*50)
|
||||
slog.info(f"服务名称: {self.service_name}")
|
||||
slog.info(f"配置文件: {self.service_file}")
|
||||
|
||||
short = self.root.find('short')
|
||||
if short is not None and short.text:
|
||||
slog.info(f"简短描述: {short.text}")
|
||||
|
||||
desc = self.root.find('description')
|
||||
if desc is not None and desc.text:
|
||||
slog.info(f"详细描述: {desc.text}")
|
||||
|
||||
ports = self.get_ports()
|
||||
if ports:
|
||||
slog.info("\n端口规则:")
|
||||
for port in ports:
|
||||
slog.info(f" - {port['port']}/{port['protocol']}")
|
||||
|
||||
protocols = self.get_protocols()
|
||||
if protocols:
|
||||
print("\n协议规则:")
|
||||
for proto in protocols:
|
||||
print(f" - {proto}")
|
||||
|
||||
modules = [m.get('name') for m in self.root.findall('module')]
|
||||
if modules:
|
||||
slog.info("\n内核模块:")
|
||||
for module in modules:
|
||||
slog.info(f" - {module}")
|
||||
slog.info("="*50 + "\n")
|
||||
|
||||
def save(self):
|
||||
"""保存修改"""
|
||||
self._save_xml()
|
||||
|
||||
def main():
|
||||
"""示例用法"""
|
||||
# 创建或修改名为 'myapp' 的服务
|
||||
manager = FWManager('myapp')
|
||||
|
||||
# 加载或创建服务文件
|
||||
if not manager.load():
|
||||
return
|
||||
|
||||
# 设置描述信息
|
||||
manager.set_short_description('My Application Service')
|
||||
manager.set_description('Custom service for my web application with API and admin ports')
|
||||
|
||||
# 添加端口
|
||||
manager.add_port(8080, 'tcp') # Web 服务端口
|
||||
manager.add_port(8443, 'tcp') # HTTPS 替代端口
|
||||
manager.add_port(9090, 'tcp') # API 端口
|
||||
manager.add_port(3000, 'tcp') # 管理界面端口
|
||||
manager.add_port(5000-5010, 'tcp') # 端口范围示例
|
||||
manager.add_port(9000, 'udp') # UDP 端口
|
||||
|
||||
# 添加协议(如果需要)
|
||||
# manager.add_protocol('icmp')
|
||||
|
||||
# 添加内核模块(如果需要,例如 FTP 辅助模块)
|
||||
# manager.add_module('nf_conntrack_ftp')
|
||||
|
||||
# 显示当前配置
|
||||
manager.display_info()
|
||||
|
||||
# 保存修改
|
||||
manager.save()
|
||||
|
||||
# 示例:移除端口
|
||||
# manager.remove_port(5000-5010, 'tcp')
|
||||
# manager.save()
|
||||
|
||||
slog.info("\n✅ 操作完成!")
|
||||
slog.info("提示:")
|
||||
slog.info("1. 运行 'sudo firewall-cmd --reload' 重新加载防火墙")
|
||||
slog.info("2. 使用 'sudo firewall-cmd --get-services' 查看所有服务")
|
||||
slog.info("3. 使用 'sudo firewall-cmd --info-service=myapp' 查看服务详情")
|
||||
slog.info(f"4. 使用 'sudo firewall-cmd --add-service={manager.service_name}' 启用服务")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -5,6 +5,7 @@ import yaml
|
||||
import sunhpc
|
||||
import signal
|
||||
import syslog
|
||||
import traceback
|
||||
import sunhpc.util
|
||||
import sunhpc.error as error
|
||||
|
||||
@@ -70,7 +71,6 @@ def _main(argv=None):
|
||||
command.isRootUser() or command.isApacheUser()):
|
||||
os.system('sudo %s' % ' '.join(sys.argv))
|
||||
else:
|
||||
#import sunhpc
|
||||
try:
|
||||
command.runWrapper(name, args[i:])
|
||||
text = command.getText()
|
||||
@@ -81,8 +81,10 @@ def _main(argv=None):
|
||||
print (text)
|
||||
print ()
|
||||
except CommandError as e:
|
||||
print ('Error: ', e)
|
||||
print (command.usage())
|
||||
print ('Error: ', e)
|
||||
#slog.info(command.usage())
|
||||
#slog.error(str(e))
|
||||
return 1
|
||||
|
||||
config_file = '/etc/sunhpc/sunhpc.yaml'
|
||||
@@ -107,9 +109,9 @@ def main(argv=None):
|
||||
tty.error("Keyboard interrupt.")
|
||||
return signal.SIGINT.value
|
||||
|
||||
except AttributeError:
|
||||
except AttributeError as e:
|
||||
sys.stderr.write("\n")
|
||||
tty.error("Attribute error.")
|
||||
slog.error(str(e))
|
||||
return 1
|
||||
|
||||
except SystemExit as e:
|
||||
|
||||
@@ -22,8 +22,20 @@ sunhpc_root = prefix
|
||||
#: bin directory in the sunhpc prefix
|
||||
bin_path = os.path.join(prefix, "bin")
|
||||
|
||||
#: var directory in the sunhpc
|
||||
var_path = os.path.join(prefix, "var")
|
||||
|
||||
#: pkgs directory in the sunhpc
|
||||
pkgs_path = os.path.join(var_path, "pkgs")
|
||||
|
||||
#: ipxe directory in the sunhpc
|
||||
ipxe_path = os.path.join(pkgs_path, "ipxe")
|
||||
|
||||
#: scripts directory in the sunhpc
|
||||
scripts_path = os.path.join(pkgs_path, "scripts")
|
||||
|
||||
#: The sunhpc script itself
|
||||
sunhpc_script = os.path.join(bin_path, "sunhpc")
|
||||
sunhpc_command = os.path.join(bin_path, "sunhpc")
|
||||
|
||||
#: The sbang script in the sunhpc installation
|
||||
sbang_script = os.path.join(bin_path, "sbang")
|
||||
|
||||
611
lib/sunhpc/sunhpc/utils/shells.py
Normal file
611
lib/sunhpc/sunhpc/utils/shells.py
Normal file
@@ -0,0 +1,611 @@
|
||||
import sys
|
||||
import time
|
||||
import shlex
|
||||
import threading
|
||||
import subprocess
|
||||
from collections import deque
|
||||
from typing import Optional, Union, List, Dict, Any, Callable
|
||||
|
||||
|
||||
class ShellResult:
|
||||
"""封装命令执行结果的类,支持布尔判断、输出获取、错误获取和返回码获取"""
|
||||
def __init__(self,
|
||||
returncode: int,
|
||||
stdout: str,
|
||||
stderr: str,
|
||||
metadata: Optional[Dict[str, Any]] = None):
|
||||
self._returncode = returncode
|
||||
self._stdout = stdout
|
||||
self._stderr = stderr
|
||||
self._metadata = metadata or {} # 存储额外信息,如包名、版本等
|
||||
|
||||
def __bool__(self):
|
||||
"""支持 if result: 直接判断命令是否成功"""
|
||||
return self._returncode == 0
|
||||
|
||||
def output(self) -> str:
|
||||
"""获取命令的标准输出"""
|
||||
return self._stdout
|
||||
|
||||
def error(self) -> str:
|
||||
"""获取命令的标准错误"""
|
||||
return self._stderr
|
||||
|
||||
def code(self) -> int:
|
||||
"""获取命令的返回码"""
|
||||
return self._returncode
|
||||
|
||||
def output_lines(self) -> List[str]:
|
||||
"""返回输出行列表,过滤空行"""
|
||||
return [line for line in self._stdout.splitlines() if line]
|
||||
|
||||
def error_lines(self) -> List[str]:
|
||||
return [line for line in self._stderr.splitlines() if line]
|
||||
|
||||
def get_metadata(self, key: str, default=None):
|
||||
"""获取元数据"""
|
||||
return self._metadata.get(key, default)
|
||||
|
||||
def set_metadata(self, key: str, value: Any):
|
||||
"""设置元数据"""
|
||||
self._metadata[key] = value
|
||||
|
||||
|
||||
class ShellExecutor:
|
||||
"""
|
||||
Shell命令执行器基类,提供通用的命令执行功能
|
||||
子类可重写方法以实现特定命令的定制行为
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
show_animation: bool = True,
|
||||
animation_chars: str = '|/-\\',
|
||||
show_last_line: bool = True,
|
||||
max_display_lines: int = 1
|
||||
):
|
||||
"""
|
||||
初始化执行器
|
||||
|
||||
参数:
|
||||
show_animation : 是否显示动态动画
|
||||
animation_chars : 动画字符集
|
||||
show_last_line : 是否显示最后一行
|
||||
max_display_lines : 最大显示行数,超过则省略号显示
|
||||
"""
|
||||
self.show_animation = show_animation
|
||||
self.animation_chars = animation_chars
|
||||
self.show_last_line = show_last_line
|
||||
self.max_display_lines = max_display_lines
|
||||
self._line_count = 0
|
||||
self._last_lines = deque(maxlen=max_display_lines)
|
||||
|
||||
def pre_execute_hook(self, cmd: Union[str, List[str]]) -> Union[str, List[str]]:
|
||||
"""
|
||||
执行前的钩子函数,可以修改命令或做预处理
|
||||
子类可重写此方法
|
||||
"""
|
||||
return cmd
|
||||
|
||||
def post_execute_hook(self, result: ShellResult, cmd: Union[str, List[str]]) -> ShellResult:
|
||||
"""
|
||||
执行后的钩子函数,可以处理结果、提取信息等
|
||||
子类可重写此方法
|
||||
"""
|
||||
return result
|
||||
|
||||
def get_display_message(self, cmd: Union[str, List[str]]) -> str:
|
||||
"""
|
||||
获取执行时显示的消息
|
||||
子类可重写以显示不同的提示信息
|
||||
"""
|
||||
return "Running..."
|
||||
|
||||
def get_completion_message(self, cmd: Union[str, List[str]], result: ShellResult) -> str:
|
||||
"""
|
||||
获取完成时显示的消息
|
||||
子类可重写以显示不同的完成信息
|
||||
"""
|
||||
if self._line_count > 0:
|
||||
return f"Completed! (lines: {self._line_count})"
|
||||
else:
|
||||
return "Completed!"
|
||||
|
||||
def get_realtime_info(self, line: str) -> str:
|
||||
"""
|
||||
获取实时显示的信息(可被子类重写以显示不同的信息格式)
|
||||
|
||||
参数:
|
||||
line: 最新读取的一行输出
|
||||
|
||||
返回:
|
||||
要显示的附加信息字符串
|
||||
"""
|
||||
# 默认显示最后一行内容(截断过长内容)
|
||||
if self.show_last_line and line:
|
||||
# 限制行长度,避免显示过长
|
||||
max_length = 80
|
||||
if len(line) > max_length:
|
||||
line = line[:max_length-3] + "..."
|
||||
return f" [{line}]"
|
||||
return ""
|
||||
|
||||
def update_realtime_output(self, line: str):
|
||||
"""
|
||||
更新实时输出信息(可被子类重写以处理特殊输出)
|
||||
|
||||
参数:
|
||||
line: 最新读取的一行输出
|
||||
"""
|
||||
self._last_lines.append(line.rstrip('\n\r'))
|
||||
|
||||
def parse_output_for_metadata(self,
|
||||
result: ShellResult,
|
||||
cmd: Union[str, List[str]]) -> Dict[str, Any]:
|
||||
"""
|
||||
解析输出提取元数据
|
||||
子类可重写此方法
|
||||
"""
|
||||
return {}
|
||||
|
||||
def _RRread_output_thread(self, process):
|
||||
"""读取输出的线程函数"""
|
||||
for line in iter(process.stdout.readline, ''):
|
||||
if line:
|
||||
self._line_count += 1
|
||||
process.stdout.close()
|
||||
|
||||
def _read_output_thread(self, process, is_stderr=False):
|
||||
"""读取输出的线程函数"""
|
||||
if is_stderr:
|
||||
# 错误输出只读取,不显示在动画中
|
||||
for line in iter(process.stderr.readline, ''):
|
||||
if line:
|
||||
pass # 可以在这里处理stderr
|
||||
process.stderr.close()
|
||||
else:
|
||||
# 标准输出需要计数和显示
|
||||
for line in iter(process.stdout.readline, ''):
|
||||
if line:
|
||||
self._line_count += 1
|
||||
# 更新实时输出
|
||||
self.update_realtime_output(line)
|
||||
# 可以添加一个回调,让子类实时处理每一行
|
||||
self.on_output_line(line)
|
||||
process.stdout.close()
|
||||
|
||||
def _display_animation(self, process):
|
||||
"""显示动画的函数"""
|
||||
if not self.show_animation:
|
||||
return
|
||||
|
||||
idx = 0
|
||||
while process.poll() is None:
|
||||
spin_char = self.animation_chars[idx % len(self.animation_chars)]
|
||||
if self._line_count > 0:
|
||||
display = f"\r{spin_char} {self.get_display_message(process.args)} (lines: {self._line_count})"
|
||||
else:
|
||||
display = f"\r{spin_char} {self.get_display_message(process.args)}"
|
||||
sys.stdout.write(display)
|
||||
sys.stdout.flush()
|
||||
idx += 1
|
||||
time.sleep(0.1)
|
||||
|
||||
# 清除当前行并显示完成信息
|
||||
completion_msg = self.get_completion_message(process.args, ShellResult(0, "", ""))
|
||||
sys.stdout.write(f"\r✓ {completion_msg} \n")
|
||||
sys.stdout.flush()
|
||||
|
||||
def on_output_line(self, line: str):
|
||||
"""
|
||||
当有新的输出行时的回调函数(可被子类重写)
|
||||
|
||||
参数:
|
||||
line: 新输出的行
|
||||
"""
|
||||
pass
|
||||
|
||||
def execute(self,
|
||||
cmd: Union[str, List[str]],
|
||||
t_cmd: Optional[Union[str, List[str]]] = None,
|
||||
quiet: bool = False,
|
||||
timeout: Optional[int] = None,
|
||||
show_animation: bool = True,
|
||||
show_real_time: bool = True,
|
||||
) -> ShellResult:
|
||||
"""
|
||||
执行shell命令
|
||||
|
||||
参数:
|
||||
cmd : 要执行的字符串或列表
|
||||
t_cmd : 可选,执行完成后的测试命令
|
||||
timeout : 超时时间(秒)
|
||||
show_real_time : 是否显示实时输出(仅当show_animation为True时有效)
|
||||
|
||||
返回:
|
||||
ShellResult 实例
|
||||
"""
|
||||
# 执行预处理钩子
|
||||
processed_cmd = self.pre_execute_hook(cmd)
|
||||
|
||||
# 转换命令为列表形式
|
||||
if isinstance(processed_cmd, str):
|
||||
cmd_list = shlex.split(processed_cmd)
|
||||
else:
|
||||
cmd_list = processed_cmd
|
||||
|
||||
# 重置计数器
|
||||
self._line_count = 0
|
||||
self._last_lines.clear()
|
||||
|
||||
# 启动子进程
|
||||
process = subprocess.Popen(
|
||||
cmd_list,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
bufsize=1
|
||||
)
|
||||
|
||||
# 用于存储输出
|
||||
stdout_lines = []
|
||||
stderr_lines = []
|
||||
|
||||
# 创建读取线程
|
||||
def collect_stdout():
|
||||
for line in iter(process.stdout.readline, ''):
|
||||
if line:
|
||||
stdout_lines.append(line)
|
||||
self._line_count += 1
|
||||
self.update_realtime_output(line)
|
||||
self.on_output_line(line)
|
||||
process.stdout.close()
|
||||
|
||||
def collect_stderr():
|
||||
for line in iter(process.stderr.readline, ''):
|
||||
if line:
|
||||
stderr_lines.append(line)
|
||||
process.stderr.close()
|
||||
|
||||
stdout_thread = threading.Thread(target=collect_stdout)
|
||||
stderr_thread = threading.Thread(target=collect_stderr)
|
||||
stdout_thread.daemon = True
|
||||
stderr_thread.daemon = True
|
||||
|
||||
stdout_thread.start()
|
||||
stderr_thread.start()
|
||||
|
||||
# 显示动画
|
||||
if self.show_animation:
|
||||
idx = 0
|
||||
last_display = ""
|
||||
while process.poll() is None:
|
||||
spin_char = self.animation_chars[idx % len(self.animation_chars)]
|
||||
|
||||
# 构建显示内容
|
||||
if self._line_count > 0:
|
||||
base_display = f"{spin_char} {self.get_display_message(cmd_list)} (lines: {self._line_count})"
|
||||
# 添加实时输出信息
|
||||
if show_real_time and self._last_lines:
|
||||
# 显示最后一行内容
|
||||
last_line = list(self._last_lines)[-1]
|
||||
realtime_info = self.get_realtime_info(last_line)
|
||||
display = f"\r{base_display}{realtime_info}"
|
||||
else:
|
||||
display = f"\r{base_display}"
|
||||
else:
|
||||
display = f"\r{spin_char} {self.get_display_message(cmd_list)}"
|
||||
|
||||
# 只在内容变化时更新,减少闪烁
|
||||
if display != last_display or self._line_count != last_line_count:
|
||||
sys.stdout.write(f'\r{display}\033[K')
|
||||
sys.stdout.flush()
|
||||
last_display = display
|
||||
last_line_count = self._line_count
|
||||
|
||||
idx += 1
|
||||
time.sleep(0.1)
|
||||
|
||||
# 等待线程结束
|
||||
stdout_thread.join(timeout=1)
|
||||
stderr_thread.join(timeout=1)
|
||||
|
||||
# 清除当前行
|
||||
self._clear_line()
|
||||
|
||||
# 显示完成信息
|
||||
if not quiet:
|
||||
completion_msg = self.get_completion_message(cmd_list, ShellResult(0, "", ""))
|
||||
# 清除当前行并显示完成信息
|
||||
sys.stdout.write(f"\r✓ {completion_msg}\n")
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
# 不显示动画时,直接等待进程结束
|
||||
process.wait()
|
||||
stdout_thread.join()
|
||||
stderr_thread.join()
|
||||
|
||||
# 合并输出
|
||||
stdout = ''.join(stdout_lines)
|
||||
stderr = ''.join(stderr_lines)
|
||||
|
||||
# 如果有测试命令,执行测试命令
|
||||
if t_cmd is not None:
|
||||
if isinstance(t_cmd, str):
|
||||
test_cmd_list = shlex.split(t_cmd)
|
||||
else:
|
||||
test_cmd_list = t_cmd
|
||||
test_process = subprocess.run(
|
||||
test_cmd_list,
|
||||
input=stdout,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
final_returncode = 0 if test_process.returncode == 0 else 1
|
||||
final_stderr = stderr + test_process.stderr
|
||||
else:
|
||||
final_returncode = process.returncode
|
||||
final_stderr = stderr
|
||||
|
||||
# 创建结果对象
|
||||
result = ShellResult(final_returncode, stdout, final_stderr)
|
||||
|
||||
# 解析元数据(如果子类需要)
|
||||
metadata = self.parse_output_for_metadata(result, processed_cmd)
|
||||
for key, value in metadata.items():
|
||||
result.set_metadata(key, value)
|
||||
|
||||
# 执行后置钩子
|
||||
result = self.post_execute_hook(result, processed_cmd)
|
||||
|
||||
return result
|
||||
|
||||
def _clear_line(self):
|
||||
"""彻底清除当前行"""
|
||||
# 先移动到行首,然后清除到行尾
|
||||
sys.stdout.write('\r\033[K') # \033[K 清除从光标到行尾的内容
|
||||
sys.stdout.flush()
|
||||
|
||||
class DnfExecutor(ShellExecutor):
|
||||
"""针对dnf命令的专用执行器"""
|
||||
|
||||
def get_display_message(self, cmd: Union[str, List[str]]) -> str:
|
||||
"""显示dnf特定消息"""
|
||||
cmd_str = ' '.join(cmd) if isinstance(cmd, list) else cmd
|
||||
if 'install' in cmd_str:
|
||||
return "Installing packages..."
|
||||
elif 'remove' in cmd_str or 'erase' in cmd_str:
|
||||
return "Removing packages..."
|
||||
elif 'update' in cmd_str:
|
||||
return "Updating packages..."
|
||||
elif 'search' in cmd_str:
|
||||
return "Searching packages..."
|
||||
else:
|
||||
return "DNF Running..."
|
||||
|
||||
def parse_output_for_metadata(self, result: ShellResult, cmd: Union[str, List[str]]) -> Dict[str, Any]:
|
||||
"""从dnf输出中提取包信息"""
|
||||
metadata = {}
|
||||
cmd_str = ' '.join(cmd) if isinstance(cmd, list) else cmd
|
||||
|
||||
# 提取安装的包名
|
||||
if 'install' in cmd_str or 'remove' in cmd_str:
|
||||
packages = []
|
||||
for line in result.output_lines():
|
||||
if 'Installing:' in line or 'Removing:' in line:
|
||||
# 提取包名
|
||||
parts = line.split()
|
||||
for part in parts:
|
||||
if '.x86_64' in part or '.noarch' in part:
|
||||
packages.append(part)
|
||||
if packages:
|
||||
metadata['packages'] = packages
|
||||
metadata['package_count'] = len(packages)
|
||||
|
||||
return metadata
|
||||
|
||||
def post_execute_hook(self, result: ShellResult, cmd: Union[str, List[str]]) -> ShellResult:
|
||||
"""dnf执行后的额外处理"""
|
||||
if result and 'install' in str(cmd):
|
||||
# 如果安装成功,提取安装的包列表
|
||||
packages = result.get_metadata('packeds', [])
|
||||
if packages:
|
||||
result.set_metadata('installed_packages', packages)
|
||||
return result
|
||||
|
||||
|
||||
class RpmExecutor(ShellExecutor):
|
||||
"""针对rpm命令的专用执行器"""
|
||||
|
||||
def __init__(self, query_format: Optional[str] = None, **kwargs):
|
||||
"""
|
||||
初始化rpm执行器
|
||||
|
||||
参数:
|
||||
query_format: 查询格式,如 "%{NAME} %{VERSION}"
|
||||
"""
|
||||
super().__init__(**kwargs)
|
||||
self.query_format = query_format
|
||||
|
||||
def pre_execute_hook(self, cmd: Union[str, List[str]]) -> Union[str, List[str]]:
|
||||
"""预处理rpm命令"""
|
||||
if isinstance(cmd, str):
|
||||
cmd_parts = shlex.split(cmd)
|
||||
else:
|
||||
cmd_parts = cmd.copy()
|
||||
|
||||
# 如果是查询命令且指定了格式,添加--qf参数
|
||||
if self.query_format and len(cmd_parts) > 1 and cmd_parts[0] == 'rpm':
|
||||
if cmd_parts[1] in ['-q', '--query', '-qa', '--query', '-qi']:
|
||||
# 插入格式参数
|
||||
if '--qf' not in cmd_parts and '--queryformat' not in cmd_parts:
|
||||
cmd_parts.insert(2, '--qf')
|
||||
cmd_parts.insert(3, self.query_format)
|
||||
|
||||
return cmd_parts
|
||||
|
||||
def get_display_message(self, cmd: Union[str, List[str]]) -> str:
|
||||
"""显示rpm特定消息"""
|
||||
cmd_str = ' '.join(cmd) if isinstance(cmd, list) else cmd
|
||||
if '-i' in cmd_str and 'install' in cmd_str:
|
||||
return "Installing RPM packages..."
|
||||
elif '-e' in cmd_str:
|
||||
return "Erasing RPM packages..."
|
||||
elif '-q' in cmd_str:
|
||||
return "Querying RPM database..."
|
||||
elif '-U' in cmd_str or '-F' in cmd_str:
|
||||
return "Upgrading RPM packages..."
|
||||
else:
|
||||
return "RPM Running..."
|
||||
|
||||
def parse_output_for_metadata(self, result: ShellResult, cmd: Union[str, List[str]]) -> Dict[str, Any]:
|
||||
"""从rpm输出中提取包信息"""
|
||||
metadata = {}
|
||||
cmd_str = ' '.join(cmd) if isinstance(cmd, list) else cmd
|
||||
|
||||
# 提取查询结果的包名和版本
|
||||
if '-q' in cmd_str and result and result.output():
|
||||
packages = []
|
||||
for line in result.output_lines():
|
||||
if line.strip():
|
||||
parts = line.split()
|
||||
if len(parts) >= 2:
|
||||
packages.append({
|
||||
'name': parts[0],
|
||||
'version': parts[1] if len(parts) > 1 else ''
|
||||
})
|
||||
if packages:
|
||||
metadata['packages'] = packages
|
||||
metadata['package_count'] = len(packages)
|
||||
|
||||
return metadata
|
||||
|
||||
|
||||
class SystemdExecutor(ShellExecutor):
|
||||
"""针对systemctl命令的专用执行器"""
|
||||
|
||||
def get_display_message(self, cmd: Union[str, List[str]]) -> str:
|
||||
"""显示systemctl特定消息"""
|
||||
cmd_str = ' '.join(cmd) if isinstance(cmd, list) else cmd
|
||||
if 'start' in cmd_str:
|
||||
return "Starting service..."
|
||||
elif 'stop' in cmd_str:
|
||||
return "Stopping service..."
|
||||
elif 'restart' in cmd_str:
|
||||
return "Restarting service..."
|
||||
elif 'status' in cmd_str:
|
||||
return "Checking service status..."
|
||||
elif 'enable' in cmd_str:
|
||||
return "Enabling service..."
|
||||
elif 'disable' in cmd_str:
|
||||
return "Disabling service..."
|
||||
else:
|
||||
return "Systemctl Running..."
|
||||
|
||||
def parse_output_for_metadata(self, result: ShellResult, cmd: Union[str, List[str]]) -> Dict[str, Any]:
|
||||
"""从systemctl输出中提取服务状态"""
|
||||
metadata = {}
|
||||
cmd_str = ' '.join(cmd) if isinstance(cmd, list) else cmd
|
||||
|
||||
# 提取服务状态
|
||||
if 'status' in cmd_str and result:
|
||||
for line in result.output_lines():
|
||||
if 'Active:' in line:
|
||||
status = line.split('Active:')[1].strip()
|
||||
metadata['service_status'] = status
|
||||
if 'active' in status:
|
||||
metadata['is_active'] = True
|
||||
else:
|
||||
metadata['is_active'] = False
|
||||
|
||||
return metadata
|
||||
|
||||
|
||||
# ========== 使用示例 ==========
|
||||
if __name__ == "__main__":
|
||||
|
||||
# 示例1:使用基础执行器
|
||||
print("=== 基础执行器 ===")
|
||||
executor = ShellExecutor()
|
||||
result = executor.execute("ls -la")
|
||||
print(f"命令成功: {bool(result)}")
|
||||
print(f"输出行数: {len(result.output_lines())}")
|
||||
print(f"前3行输出:\n{chr(10).join(result.output_lines()[:3])}")
|
||||
print("-" * 50)
|
||||
|
||||
# 示例2:使用dnf执行器(如果有dnf命令)
|
||||
print("=== DNF执行器 ===")
|
||||
dnf = DnfExecutor()
|
||||
# 搜索命令示例(不会实际修改系统)
|
||||
result = dnf.execute("dnf search python3", show_animation=False) # 测试时关闭动画
|
||||
print(f"搜索完成: {bool(result)}")
|
||||
if result.get_metadata('package_count', 0) > 0:
|
||||
print(f"找到 {result.get_metadata('package_count')} 个包")
|
||||
|
||||
# 示例3:使用rpm执行器
|
||||
print("=== RPM执行器 ===")
|
||||
rpm = RpmExecutor(query_format="%{NAME} %{VERSION}")
|
||||
# 查询已安装的包(前5个)
|
||||
result = rpm.execute("rpm -qa | head -5", show_animation=False)
|
||||
print(f"查询完成: {bool(result)}")
|
||||
print("前5个包:")
|
||||
for line in result.output_lines()[:5]:
|
||||
print(f" {line}")
|
||||
|
||||
# 示例4:使用systemd执行器
|
||||
print("=== Systemd执行器 ===")
|
||||
systemd = SystemdExecutor()
|
||||
result = systemd.execute("systemctl status sshd", show_animation=False)
|
||||
print(f"服务状态: {result.get_metadata('service_status', 'unknown')}")
|
||||
print(f"服务活跃: {result.get_metadata('is_active', False)}")
|
||||
|
||||
# 示例5:带测试命令的示例
|
||||
print("=== 带测试命令 ===")
|
||||
executor = ShellExecutor()
|
||||
result = executor.execute("ls -la", t_cmd="grep README")
|
||||
print(f"包含README文件: {bool(result)}")
|
||||
if not result:
|
||||
print(f"未找到README文件")
|
||||
|
||||
# 示例6:如何扩展自己的专用执行器
|
||||
print("=== 自定义扩展示例 ===")
|
||||
|
||||
class GitExecutor(ShellExecutor):
|
||||
"""Git命令专用执行器"""
|
||||
|
||||
def get_display_message(self, cmd: Union[str, List[str]]) -> str:
|
||||
cmd_str = ' '.join(cmd) if isinstance(cmd, list) else cmd
|
||||
if 'status' in cmd_str:
|
||||
return "Checking git status..."
|
||||
elif 'pull' in cmd_str:
|
||||
return "Pulling from remote..."
|
||||
elif 'push' in cmd_str:
|
||||
return "Pushing to remote..."
|
||||
elif 'commit' in cmd_str:
|
||||
return "Committing changes..."
|
||||
else:
|
||||
return "Git Running..."
|
||||
|
||||
def parse_output_for_metadata(self, result: ShellResult, cmd: Union[str, List[str]]) -> Dict[str, Any]:
|
||||
"""提取git信息"""
|
||||
metadata = {}
|
||||
cmd_str = ' '.join(cmd) if isinstance(cmd, list) else cmd
|
||||
|
||||
if 'status' in cmd_str:
|
||||
# 统计未跟踪、修改、新增的文件
|
||||
untracked = 0
|
||||
modified = 0
|
||||
for line in result.output_lines():
|
||||
if 'Untracked files:' in line:
|
||||
untracked = 1
|
||||
elif 'modified:' in line:
|
||||
modified += 1
|
||||
metadata['untracked'] = untracked > 0
|
||||
metadata['modified_count'] = modified
|
||||
|
||||
return metadata
|
||||
|
||||
git = GitExecutor()
|
||||
result = git.execute("git status", show_animation=False)
|
||||
if result:
|
||||
print(f"有未跟踪文件: {result.get_metadata('untracked', False)}")
|
||||
print(f"修改文件数: {result.get_metadata('modified_count', 0)}")
|
||||
13607
var/pkgs/cuda/13.0/include/nvml.h
Normal file
13607
var/pkgs/cuda/13.0/include/nvml.h
Normal file
File diff suppressed because it is too large
Load Diff
BIN
var/pkgs/cuda/13.0/lib64/stubs/libnvidia-ml.a
Normal file
BIN
var/pkgs/cuda/13.0/lib64/stubs/libnvidia-ml.a
Normal file
Binary file not shown.
504
var/pkgs/cuda/13.0/nvml/doc/nvml_changelog.txt
Normal file
504
var/pkgs/cuda/13.0/nvml/doc/nvml_changelog.txt
Normal file
@@ -0,0 +1,504 @@
|
||||
/*! @page KnownIssues Known issues in the current version of NVML library
|
||||
*
|
||||
* This is a list of known NVML issues in the current driver:
|
||||
* - NVML Field Values from #251 - #273 (Power Smoothing, Clock Event Reason, and Sync Power Balancing related field values) have changed between 13.0 and 13.0U1/v580TRD2.
|
||||
* - Any application that is using these field IDs must be recompiled using the NVML header file from CUDA 13.0 Update 1 in order to continue working correctly with NVIDIA drivers v580 TRD2 and beyond.
|
||||
* - On systems where GPUs are NUMA nodes, the accuracy of FB memory utilization provided by NVML depends on the memory accounting of the operating system.
|
||||
* This is because FB memory is managed by the operating system instead of the NVIDIA GPU driver.
|
||||
* Typically, pages allocated from FB memory are not released even after the process terminates to enhance performance. In scenarios where
|
||||
* the operating system is under memory pressure, it may resort to utilizing FB memory. Such actions can result in discrepancies in the accuracy of memory reporting.
|
||||
* - On Linux GPU Reset can't be triggered when there is pending GPU Operation Mode (GOM) change
|
||||
* - On Linux GPU Reset may not successfully change pending ECC mode. A full reboot may be required to enable the mode change.
|
||||
* - \ref nvmlAccountingStats supports only one process per GPU at a time (CUDA proxy server counts as one process).
|
||||
* - \ref nvmlAccountingStats_t.time reports time and utilization values starting from cuInit till process termination. Next driver versions might change this behavior slightly and account process only from cuCtxCreate till cuCtxDestroy.
|
||||
* - On GPUs from Fermi family current P0 clocks (reported by \ref nvmlDeviceGetClockInfo) can differ from max clocks by few MHz.
|
||||
*/
|
||||
/*! @page Changelog Change log of NVML library
|
||||
* This chapter list changes in API and bug fixes that were introduced to the library
|
||||
* \section changelog32 Changes between NVML v575 and v580 ===
|
||||
* - Fixed bug with NVML_FI_PWR_SMOOTHING_* Field Value numbering, which was different than the v570 values.
|
||||
* - Adjusted NVML_FI_DEV_CLOCKS_EVENT_REASON_* and NVML_FI_DEV_POWER_SYNC_BALANCING_* field value numbering to resolve overlap with NVML_FI_PWR_SMOOTHING_* field values.
|
||||
*
|
||||
* - Added \ref nvmlDeviceGetSramUniqueUncorrectedEccErrorCounts to get the counts of SRAM unique uncorrected ECC errors.
|
||||
* - Deprecated Applications Clocks APIs, which will be removed in CUDA 14.0:
|
||||
* - \ref nvmlDeviceSetApplicationsClocks
|
||||
* - \ref nvmlDeviceGetApplicationsClock
|
||||
* - \ref nvmlDeviceGetDefaultApplicationsClock
|
||||
* - \ref nvmlDeviceResetApplicationsClocks
|
||||
* - Deprecated \ref nvmlDeviceGetViolationStatus, which will be removed in CUDA 14.0
|
||||
* - Added \ref nvmlDeviceGetNvLinkInfo to query device NVLINK info.
|
||||
* - Added \ref nvmlDeviceGetPdi to retrieve the device GPU PDI.
|
||||
* - Added Multi-GPU mode NVLINK Encryption \ref NVML_CC_SYSTEM_MULTIGPU_NVLE
|
||||
* - Added V2 struct to \ref nvmlDeviceGetNvLinkInfo to query NVLINK Firmware info.
|
||||
* - Added \ref nvmlDeviceReadWritePRM_v1 to retrieve GPU PRM register contents
|
||||
* - Added \ref nvmlDeviceGetAddressingMode to retrieve the addressing mode for the device.
|
||||
* - Added \ref nvmlDeviceGetRepairStatus to get ECC status info.
|
||||
* - Added \ref nvmlDeviceGetGpuInstanceProfileInfoByIdV which allows for MIG GPU instance profile info to be queried with profileId instead of profile name.
|
||||
* - Updated nvmlGpuFabricInfoV_t to v3 to include a new Health Summary field, and new Incorrect Configuration statuses.
|
||||
- nvmlGpuFabricInfo_v2_t is deprecated and will be removed in a future release
|
||||
* - Added \ref nvmlDeviceGetPowerMizerMode_v1 to query the current and supported power mizer modes on Maxwell and newer gpus. Power mizer mode provides a hint to the driver as to how to manage the performance of the GPU.
|
||||
* - Added \ref nvmlDeviceSetPowerMizerMode_v1 to set the power mizer mode on Maxwell and newer gpus.
|
||||
* - Added new Incorrect Configuration Statuses to nvmlGpuFabricInfoV_t
|
||||
* - NVML_GPU_FABRIC_HEALTH_MASK_INCORRECT_CONFIGURATION_INCOMPATIBLE_GPU_FW
|
||||
* - NVML_GPU_FABRIC_HEALTH_MASK_INCORRECT_CONFIGURATION_INVALID_LOCATION
|
||||
* - Added \ref nvmlDeviceSetHostname_v1 and \ref nvmlDeviceGetHostname_v1 to allow custom GPU hostname configuration.
|
||||
* \section changelog31 Changes between NVML v570 and v575 ===
|
||||
*
|
||||
* - Added \ref nvmlSystemEventSetCreate to create a system event set.
|
||||
* - Added \ref nvmlSystemEventSetFree to free a system event set.
|
||||
* - Added \ref nvmlSystemRegisterEvents to register system events on a system event set.
|
||||
* - Added \ref nvmlSystemEventSetWait to wait for system event notification and obtain system event data.
|
||||
* - Added \ref nvmlGpuInstanceGetCreatableVgpus to query the currently creatable vGPU types on the user provided GPU Instance
|
||||
* - Added \ref nvmlVgpuTypeGetMaxInstancesPerGpuInstance to query the maximum number of vGPU instances per GPU Instance for the given vGPU type
|
||||
* - Added \ref nvmlGpuInstanceSetVgpuSchedulerState to set the vGPU scheduler state for the given GPU Instance
|
||||
* - Added \ref nvmlGpuInstanceGetActiveVgpus to query the currently active vGPU instances on the user provided GPU Instance
|
||||
* - Added \ref nvmlGpuInstanceGetVgpuSchedulerState to query the vGPU software scheduler state for the given GPU Instance.
|
||||
* - Added \ref nvmlGpuInstanceGetVgpuSchedulerLog to query the vGPU software scheduler logs for the given GPU Instance.
|
||||
* - Added \ref nvmlGpuInstanceGetVgpuTypeCreatablePlacements to query the creatable vGPU placement IDs of the vGPU type within a GPU instance
|
||||
* - Added \ref nvmlGpuInstanceSetVgpuHeterogeneousMode to enable or disable vGPU heterogenous mode for the GPU Instance.
|
||||
* - Added \ref nvmlGpuInstanceGetVgpuHeterogeneousMode to query the vGPU heterogenous mode for the GPU Instance.
|
||||
* - Updated \ref nvmlDeviceGetVgpuCapabilities to report whether GPU supports timesliced vGPU on MIG and whether MIG timesliced mode is enabled or not vGPU capabilities.
|
||||
* - Updated \ref nvmlDeviceSetVgpuCapabilities to set the MIG timesliced mode vGPU capability of a device.
|
||||
* - Updated \ref nvmlDeviceSetVgpuHeterogeneousMode to return \ref NVML_ERROR_NOT_SUPPORTED when in MIG mode.
|
||||
* - Updated \ref nvmlDeviceGetVgpuHeterogeneousMode to return \ref NVML_ERROR_NOT_SUPPORTED when in MIG mode.
|
||||
* - Updated \ref nvmlDeviceGetVgpuTypeCreatablePlacements to return \ref NVML_ERROR_NOT_SUPPORTED when in MIG mode.
|
||||
* - Updated \ref nvmlDeviceGetVgpuSchedulerLog to return \ref NVML_ERROR_NOT_SUPPORTED when in MIG mode.
|
||||
* - Updated \ref nvmlDeviceSetVgpuSchedulerState to return \ref NVML_ERROR_NOT_SUPPORTED when in MIG mode.
|
||||
* - Updated \ref nvmlDeviceGetVgpuSchedulerState to return \ref NVML_ERROR_NOT_SUPPORTED when in MIG mode.
|
||||
* - Added 3 new NVML_FI_DEV_C2C_LINK_ERROR fieldIds
|
||||
* - \ref NVML_FI_DEV_C2C_LINK_ERROR_INTR
|
||||
* - \ref NVML_FI_DEV_C2C_LINK_ERROR_REPLAY
|
||||
* - \ref NVML_FI_DEV_C2C_LINK_ERROR_REPLAY_B2B
|
||||
* - Added new NVML_FI_DEV_C2C_LINK_POWER_STATE fieldId
|
||||
* - Added new CTXSW GPM Metrics
|
||||
* - Added \ref nvmlDeviceGetHandleByUUIDV that supports both the ASCII and binary format UUID to retrieve the device handle.
|
||||
* - Added 2 new NVML_FI_DEV_POWER_SYNC_BALANCING fieldIds
|
||||
* - \ref NVML_FI_DEV_POWER_SYNC_BALANCING_FREQ
|
||||
* - \ref NVML_FI_DEV_POWER_SYNC_BALANCING_AF
|
||||
* - Added 5 new Clock Event Reason Counters fieldIds
|
||||
* - \ref NVML_FI_DEV_CLOCKS_EVENT_REASON_SW_POWER_CAP
|
||||
* - \ref NVML_FI_DEV_CLOCKS_EVENT_REASON_SYNC_BOOST
|
||||
* - \ref NVML_FI_DEV_CLOCKS_EVENT_REASON_SW_THERM_SLOWDOWN
|
||||
* - \ref NVML_FI_DEV_CLOCKS_EVENT_REASON_HW_THERM_SLOWDOWN
|
||||
* - \ref NVML_FI_DEV_CLOCKS_EVENT_REASON_HW_POWER_BRAKE_SLOWDOWN
|
||||
* - Updated \ref nvmlDeviceGetMemoryErrorCounter to better account for transient vs. permanent errors
|
||||
* - Added MIG profiles that can allocate all or none of Decoder, Encoder, JPEG and OFA engines.
|
||||
*
|
||||
* \section changelog30 Changes between NVML v565 Update and v570 ===
|
||||
* - Revert the fix for the issue where PCIe throughput (reported via \ref nvmlDeviceGetPcieThroughput and nvidia-smi -q) is 1000 times bigger than its actual value
|
||||
* - Added field values for data related to Power Smoothing
|
||||
* - Added \ref nvmlDevicePowerSmoothingActivatePresetProfile to activate a specific Preset Profile for Power Smoothing
|
||||
* - Added \ref nvmlDevicePowerSmoothingSetState to enable/disable the Power Smoothing feature
|
||||
* - Added \ref nvmlDevicePowerSmoothingUpdatePresetProfileParam to update parameters to preset profiles for Power Smoothing
|
||||
* - Added new enums for fieldId NVML_FI_DEV_NVLINK_GET_STATE to expose INACTIVE, ACTIVE, and SLEEP state for a link
|
||||
* - Added \ref nvmlDeviceGetMarginTemperature to retrieve the thermal margin temperature (distance to nearest slowdown threshold).
|
||||
* - Added \ref nvmlDeviceGetNvlinkSupportedBwModes to get all supported Nvlink Bandwidth modes
|
||||
* - Added \ref nvmlDeviceGetNvlinkBwMode to get the current Nvlink Bandwidth mode
|
||||
* - Added \ref nvmlDeviceSetNvlinkBwMode to set the Nvlink Bandwidth mode
|
||||
* - Added MIG profiles with support for graphics.
|
||||
* - Added support for new recovery action - NVML_GPU_RECOVERY_ACTION_DRAIN_AND_RESET
|
||||
* - Deprecated nvml fieldIds NVML_FI_DEV_RESET_STATUS and NVML_FI_DEV_DRAIN_AND_RESET_STATUS. Usee NVML_FI_DEV_GET_GPU_RECOVERY_ACTION instead
|
||||
* - Added \ref nvmlDeviceGetDramEncryptionMode and \ref nvmlDeviceSetDramEncryptionMode to query and configure DRAM Encryption Mode
|
||||
* - Added 3 new flags to GPU Fabric Health Mask
|
||||
* - NVML_GPU_FABRIC_HEALTH_MASK_SHIFT_ROUTE_RECOVERY
|
||||
* - NVML_GPU_FABRIC_HEALTH_MASK_SHIFT_ROUTE_UNHEALTHY
|
||||
* - NVML_GPU_FABRIC_HEALTH_MASK_SHIFT_ACCESS_TIMEOUT_RECOVERY
|
||||
* - Added 4 new GPM metrics
|
||||
* - NVML_GPM_METRIC_NVENC_0_UTIL
|
||||
* - NVML_GPM_METRIC_NVENC_1_UTIL
|
||||
* - NVML_GPM_METRIC_NVENC_2_UTIL
|
||||
* - NVML_GPM_METRIC_NVENC_3_UTIL
|
||||
* - Added new counters for Nvlink5
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_EFFECTIVE_ERRORS to get sum of the number of errors in each Nvlink packet
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_EFFECTIVE_BER to get Effective BER for effective errors
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_FEC_HISTORY_0 to 15 to get count of symbol errors that are corrected
|
||||
* - Swapped the values of field IDs \ref NVML_FI_DEV_IS_MIG_MODE_INDEPENDENT_MIG_QUERY_CAPABLE and \ref NVML_FI_DEV_NVLINK_GET_POWER_THRESHOLD_MAX to fix backwards compatibility with v550.
|
||||
* - New revision of nvmlPlatformInfo_t -- nvmlPlatformInfo_v2 has been added. In this version the following fields from v1 have been renamed
|
||||
* - rackGuid to chassisSerialNumber
|
||||
* - chassisPhysicalSlotNumber to slotNumber
|
||||
* - computeSlotIndex to trayIndex
|
||||
* - nodeIndex to hostId
|
||||
* - nvmlPlatformInfo_v1 is deprecated and will be removed in subsequent releases
|
||||
*
|
||||
* \section changelog29 Changes between NVML v560 Update and v565 ===
|
||||
* - Fixed the ECC error count mismatch between nvidia-smi query output and NVML APIs, \ref nvmlDeviceGetMemoryErrorCounter and \ref nvmlDeviceGetFieldValues.
|
||||
* - Added new value NVML_CC_SYSTEM_CPU_CAPS_AMD_SNP_VTOM for CC CPU capability reporting
|
||||
* - Added \ref nvmlDeviceGetCoolerInfo to retrieve a cooler's control signal characteristics and target that cooler cools.
|
||||
* - Added new value NVML_CC_SYSTEM_CPU_CAPS_AMD_SEV_SNP for CC CPU capability reporting
|
||||
* - Added \ref nvmlDeviceGetFanSpeedRPM to report the intended operating speed in rotations per minute (RPM) of the device's specified fan.
|
||||
* - Added \ref nvmlDeviceGetPerformanceModes to retrieve a performance modes string with all the performance modes defined for this device along with their associated GPU Clock and Memory Clock values.
|
||||
* - Added \ref nvmlDeviceGetCurrentClockFreqs to retrieve a string with the associated GPU Clock and Memory Clock values for the current pstate.
|
||||
* - Added \ref nvmlNvlinkVersion_t enum to define NvLink Version
|
||||
* - Added \ref nvmlDeviceGetPlatformInfo to retrieve the platform information of a device
|
||||
* - Added new event type nvmlEventTypeGpuUnavailableError
|
||||
* - Removed support for \p nvmlDeviceGetNvLinkCrcLaneErrorCounter \p nvmlDeviceGetNvLinkEccLaneErrorCounter \p nvmlDeviceGetNvLinkErrorCounter on Blackwell
|
||||
* - Removed support for fieldIds \ref NVML_FI_DEV_NVLINK_ERROR_DL_REPLAY \ref NVML_FI_DEV_NVLINK_ERROR_DL_RECOVERY \ref NVML_FI_DEV_NVLINK_ERROR_DL_CRC on Blackwell
|
||||
* - Added \ref nvmlVgpuInstanceGetRuntimeStateSize to get the vGPU runtime state size
|
||||
* - Updated nvmlDeviceGetVgpuTypeSupportedPlacements function to report both Heterogeneous and Homogeneous vGPU placements.
|
||||
* - Updated nvmlDeviceGetVgpuCapabilities to report the Homogeneous vGPU capability.
|
||||
* - Added \ref nvmlDeviceWorkloadPowerProfileGetProfilesInfo to retrieve Workload Power Profile Info
|
||||
* - Added \ref nvmlDeviceWorkloadPowerProfileGetCurrentProfiles to retrieve current Requested and Enforced Workload Power Profiles
|
||||
* - Added \ref nvmlDeviceWorkloadPowerProfileSetRequestedProfiles to set Requested Workload Power Profiles
|
||||
* - Added \ref nvmlDeviceWorkloadPowerProfileClearRequestedProfiles to clear Requested Performance Profiles
|
||||
* - Added new event type nvmlEventTypeGpuRecoveryAction
|
||||
* - Added new fieldId to query gpu recovery action NVML_FI_DEV_GET_GPU_RECOVERY_ACTION
|
||||
* - Deprecated fieldIds
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_VL15_DROPPED to get Number of VL15 MADs dropped on a link in NVLink5
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_RAW_BER_LANE0 to get BER per lane for lane 0
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_RAW_BER_LANE1 to get BER per lane for lane 1
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_RAW_BER to get BER per link. Sum of all the raw errors per lane/Bits received per link
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_EFFECTIVE_ERRORS to get Sum of the number of errors in each Nvlink packet
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_EFFECTIVE_BER to get Effective BER for effective errors
|
||||
*
|
||||
* \section changelog28 Changes between NVML v555 Update and v560 ===
|
||||
*
|
||||
* - Added field values NVML_FI_DEV_PCIE_OUTBOUND_ATOMICS_MASK and NVML_FI_DEV_PCIE_INBOUND_ATOMICS_MASK for nvmlDeviceGetFieldValues.
|
||||
* - Added field ids NVML_FI_DEV_RESET_STATUS and NVML_FI_DEV_DRAIN_AND_RESET_STATUS which correspond to the nvidia-smi output.
|
||||
* - Added NVML_DEVICE_ARCH_T23X architecture type.
|
||||
* - Added \ref nvmlVgpuTypeGetBAR1Info to query the BAR1 information of a vGPU type.
|
||||
* - Added new event types, nvmlEventTypeSingleBitEccErrorStorm, nvmlEventTypeDramRetirementEvent, nvmlEventTypeDramRetirementFailure, nvmlEventTypeNonFatalPoisonError and nvmlEventTypeFatalPoisonError.
|
||||
* - Added \ref nvmlSystemGetDriverBranch to query the driver branch information.
|
||||
*
|
||||
* \section changelog27 Changes between NVML v550 Update and v555 ===
|
||||
*
|
||||
* - Added \ref nvmlDeviceGetClockOffsets to query min, max and current clock offset value on a Maxwell and later GPU for a specified clock.
|
||||
* - Added \ref nvmlDeviceSetClockOffsets to control clock offset value on a Maxwell and later GPU for a specified clock.
|
||||
* - Added new fieldIds for Nvlink5 telemetry on Blackwell
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_XMIT_PACKETS to get Total Tx packets on the link in NVLink5
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_XMIT_BYTES to get Total Tx bytes on the link in NVLink5
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_RCV_PACKETS to get Total Rx packets on the link in NVLink5
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_RCV_BYTES to get Total Rx bytes on the link in NVLink5
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_VL15_DROPPED to get Number of VL15 MADs dropped on a link in NVLink5
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_MALFORMED_PACKET_ERRORS to get Number of packets Rx on a link where packets are malformed
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_BUFFER_OVERRUN_ERRORS to get Number of packets that were discarded on Rx due to buffer overrun
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_RCV_ERRORS to get Total number of packets with errors Rx on a link
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_RCV_REMOTE_ERRORS to get Total number of packets Rx - stomp/EBP marker
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_RCV_GENERAL_ERRORS to get Total number of packets Rx with header mismatch
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_LOCAL_LINK_INTEGRITY_ERRORS to get Total number of times that the count of local errors exceeded a threshold
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_XMIT_DISCARDS to get Total number of tx error packets that were discarded
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_LINK_RECOVERY_SUCCESSFUL_EVENTS to get Number of times link went from Up to recovery, succeeded and link came back up
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_LINK_RECOVERY_FAILED_EVENTS to get Number of times link went from Up to recovery, failed and link was declared down
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_LINK_RECOVERY_EVENTS to get Number of times link went from Up to recovery, irrespective of the result
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_RAW_BER_LANE0 to get BER per lane for lane 0
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_RAW_BER_LANE1 to get BER per lane for lane 1
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_RAW_BER to get BER per link. Sum of all the raw errors per lane/Bits received per link
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_EFFECTIVE_ERRORS to get Sum of the number of errors in each Nvlink packet
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_EFFECTIVE_BER to get Effective BER for effective errors
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_SYMBOL_ERRORS to get Number of errors in rx symbols
|
||||
* - \ref NVML_FI_DEV_NVLINK_COUNT_SYMBOL_BER to get BER for symbol errors
|
||||
* - Added two new field ids NVML_FI_DEV_PCIE_COUNT_TX_BYTES and NVML_FI_DEV_PCIE_COUNT_RX_BYTES for nvmlDeviceGetFieldValues.
|
||||
* - Added new API nvmlDeviceGetCapabilities with the first capability bit NVML_DEV_CAP_EGM for Extended GPU Memory (EGM) capability.
|
||||
* - Added multiGpuMode display on CC enabled system via new API nvmlSystemGetConfComputeSettings or "nvidia-smi conf-compute --get-multigpu-mode" or "nvidia-smi conf-compute -mgm".
|
||||
* - Added new field ID \ref NVML_FI_DEV_NVLINK_GET_POWER_THRESHOLD_MAX to get the Max Nvlink Power Threshold for a device.
|
||||
* - Deprecated \ref nvmlDeviceGetTemperature and replaced with a new API \ref nvmlDeviceGetTemperatureV to retrieve device temperature.
|
||||
* - Added new field ID \ref NVML_VGPU_DRIVER_CAP_WARM_UPDATE and NVML_DEVICE_VGPU_CAP_WARM_UPDATE to query whether the driver and the device supports FSR and warm update of vGPU host driver without terminating the running guest VM respectively.
|
||||
* - Added new field ID \ref NVML_FI_DEV_NVLINK_GET_POWER_THRESHOLD_MIN to get the Min Nvlink Power Threshold for a device.
|
||||
* - Added new field ID \ref NVML_FI_DEV_NVLINK_GET_POWER_THRESHOLD_UNITS to get the Units of the Nvlink Power Threshold for a device.
|
||||
* - Added new field ID \ref NVML_FI_DEV_NVLINK_GET_POWER_THRESHOLD_SUPPORTED to get if Nvlink Power Threshold is supported for a device.
|
||||
*
|
||||
*
|
||||
* \section changelog26 Changes between NVML v545 Update and v550 ===
|
||||
*
|
||||
* - Added \ref nvmlDeviceGetNumaNodeId to query the NUMA node of a GPU.
|
||||
* - Fix the issue where PCIe throughput (reported via nvmlDeviceGetPcieThroughput and nvidia-smi -q) is 1000 times bigger than its actual value.
|
||||
* - Added new GPM metric Id NVML_GPM_METRIC_NVOFA_1_UTIL to \ref nvmlGpmMetricId_t.
|
||||
* - Added new field ID \ref NVML_FI_DEV_IS_MIG_MODE_INDEPENDENT_MIG_QUERY_CAPABLE, to check MIG query capable device irrespective of MIG mode.
|
||||
* - Deprecated NVML_P2P_CAPS_INDEX_PROP and added NVML_P2P_CAPS_INDEX_PCI to reflect the same P2P capability.
|
||||
* - Added \ref nvmlDeviceGetProcessesUtilizationInfo to retrieve the recent utilization and process ID for all running processes.
|
||||
* - Added new struct \ref nvmlProcessesUtilizationInfo_v1_t, which includes the new utilization of NVJPG and NVOFA.
|
||||
* - Added \ref nvmlDeviceGetVgpuInstancesUtilizationInfo to retrieve the recent utilization for vGPU instances running on a physical GPU.
|
||||
* - Added \ref nvmlDeviceGetVgpuProcessesUtilizationInfo to retrieve the recent utilization for processes running on vGPU instances on a physical GPU.
|
||||
* - Added \ref nvmlDeviceSetVgpuHeterogeneousMode to enable or disable vGPU heterogenous mode for the device.
|
||||
* - Added \ref nvmlDeviceGetVgpuHeterogeneousMode to query the vGPU heterogenous mode for the device.
|
||||
* - Added \ref nvmlVgpuInstanceGetPlacementId to query placement ID of the active vGPU instance.
|
||||
* - Added \ref nvmlDeviceGetVgpuTypeSupportedPlacements to query the supported vGPU placement IDs of a vGPU type.
|
||||
* - Added \ref nvmlDeviceGetVgpuTypeCreatablePlacements to query the creatable vGPU placement IDs of a vGPU type.
|
||||
* - Added support to display confidential compute protected memory along with fb & bar1 in nvidia-smi pmon & dmon commands.
|
||||
* - Added \ref nvmlDeviceGetGpuFabricInfoV to query Gpu Fabric Probe Info for the device.
|
||||
* - Deprecated \ref nvmlDeviceGetGpuFabricInfo. This function should not be used, and will be removed in a future release. Use \ref nvmlDeviceGetGpuFabricInfoV instead.
|
||||
* - Modified \ref nvmlDeviceGetGpuInstanceProfileInfo and \ref nvmlDeviceGetGpuInstancePossiblePlacements_v2 to no longer require MIG being enabled
|
||||
* - Added \ref nvmlSystemSetConfComputeKeyRotationThresholdInfo to set confidential compute key rotation threshold.
|
||||
* - Added \ref nvmlSystemGetConfComputeKeyRotationThresholdInfo to query confidential compute key rotation threshold detail.
|
||||
* - Added \ref nvmlDeviceSetVgpuCapabilities to set the desirable vGPU capability of a device.
|
||||
*
|
||||
*
|
||||
* \section changelog25 Changes between NVML v535 Update and v545 ===
|
||||
*
|
||||
* - Added a new error code \ref NVML_ERROR_GPU_NOT_FOUND to be returned if no supported GPUS are found during initialization.
|
||||
* - In \ref nvmlGpuFabricInfo_t \p partitionId has been renamed to \p cliqueId.
|
||||
* - Added new versioned structs \ref nvmlGpuInstanceProfileInfo_v3_t and \ref nvmlComputeInstanceProfileInfo_v3_t.
|
||||
* - Added \ref nvmlDeviceGetLastBBXFlushTime for retrieving the timestamp and duration of the latest flush of the BBX object to the inforom storage.
|
||||
* - Added \ref NVML_POWER_SCOPE_MEMORY to report out power usage for GPU Memory.
|
||||
* - Added \ref nvmlDeviceGetPciInfoExt which expands \ref nvmlDeviceGetPciInfo_v3 to also report PCI base and sub classcodes.
|
||||
* - Added new struct \ref nvmlPciInfoExt_v1_t, which is used in \ref nvmlDeviceGetPciInfoExt.
|
||||
* - Added \ref nvmlDeviceGetRunningProcessDetailList api to get information about Compute, Graphics or MPS-Compute processes running on a GPU with protected memory usage info.
|
||||
*
|
||||
*
|
||||
* \section changelog24 Changes between NVML v530 Update and v535 ===
|
||||
*
|
||||
* - Fixed \ref nvmlDeviceGetMemoryErrorCounter and \ref nvmlDeviceGetFieldValues to return correct SRAM volatile total error counts.
|
||||
* - Added \ref nvmlDeviceGetSramEccErrorStatus to query SRAM ECC error status for the device.
|
||||
* - Added \ref nvmlDeviceGetModuleId for getting device module id
|
||||
* - Updated \ref nvmlDeviceGetPowerSource API to report undersized power source.
|
||||
* - Added \ref nvmlDeviceGetJpgUtilization and \ref nvmlDeviceGetOfaUtilization APIs
|
||||
* - Added \ref nvmlSystemGetNvlinkBwMode and \ref nvmlSystemSetNvlinkBwMode APIs
|
||||
* - Added \ref nvmlDeviceSetVgpuSchedulerState to set the vGPU scheduler state.
|
||||
* - Added new field ID \ref NVML_FI_DEV_IS_RESETLESS_MIG_SUPPORTED for device's resetless MIG capability
|
||||
* - Added \ref nvmlDeviceGetComputeRunningProcesses_v3 to get information about Compute processes running on a GPU.
|
||||
* - Added \ref nvmlDeviceGetGraphicsRunningProcesses_v3 to get information about Graphics processes running on a GPU.
|
||||
* - Added \ref nvmlDeviceGetMPSComputeRunningProcesses_v3 to get information about MPS-Compute processes running on a GPU.
|
||||
* - Added \ref nvmlDeviceGetRunningProcessDetailList to get information about Compute, Graphics or MPS-Compute processes running on a GPU with protected memory usage info. Currently returns NVML_ERROR_NOT_SUPPORTED. Functionality will be implemented in next release.
|
||||
* - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_CORRECTABLE_ERRORS for PCIe correctable errors counter
|
||||
* - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_NAKS_RECEIVED for PCIe NAK Receive counter
|
||||
* - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_RECEIVER_ERROR for PCIe receiver error counter
|
||||
* - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_BAD_TLP for PCIe bad TLP counter
|
||||
* - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_NAKS_SENT for NAK Send counter
|
||||
* - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_BAD_DLLP for PCIe bad DLLP counter
|
||||
* - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_NON_FATAL_ERROR for PCIe non fatal error counter
|
||||
* - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_FATAL_ERROR for PCIe fatal error counter
|
||||
* - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_UNSUPPORTED_REQ for PCIe unsupported request counter
|
||||
* - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_LCRC_ERROR for PCIe LCRC error counter
|
||||
* - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_LANE_ERROR for per lane error counter with scope as PCIe lane number.
|
||||
* - Added \ref nvmlDeviceGetPowerUsage to retrieve current power usage
|
||||
* - Added \ref nvmlDeviceGetTotalEnergyConsumption to get current energy consumption
|
||||
* - Added \ref nvmlDeviceSetPowerManagementLimit_v2 to set the power limit
|
||||
* - Renamed nvmlDeviceCcuGetStreamState to nvmlGpmQueryIfStreamingEnabled and nvmlDeviceCcuSetStreamState to nvmlGpmSetStreamingEnabled.
|
||||
*
|
||||
*
|
||||
* \section changelog23 Changes between NVML v525 Update and v530 ===
|
||||
*
|
||||
* - Fixed a typo in nvmlGpuP2PStatus_t: added a new enum entry for NVML_P2P_STATUS_CHIPSET_NOT_SUPPORTED with the same numeric value as the existing erroneous entry ("NVML_P2P_STATUS_CHIPSET_NOT_SUPPORED")
|
||||
* - Added \ref nvmlDeviceGetVgpuSchedulerLog to fetch the vGPU software scheduler logs.
|
||||
* - Added \ref nvmlDeviceGetVgpuSchedulerState to fetch the vGPU software scheduler state.
|
||||
* - Added \ref nvmlDeviceGetVgpuSchedulerCapabilities to fetch the vGPU software scheduler capabilities.
|
||||
*
|
||||
*
|
||||
* \section changelog22 Changes between NVML v520 Update and v525 ===
|
||||
*
|
||||
* - Added \ref nvmlDeviceSetNvLinkDeviceLowPowerThreshold to set the NvLink low power threshold.
|
||||
* - Added \p nvmlDeviceGetPcieAtomicCaps to report PCIe atomic capabilities.
|
||||
* - Added \p nvmlDeviceCcuGetStreamState API to report the counter collection unit stream state.
|
||||
* - Added \p nvmlDeviceCcuSetStreamState API to set the counter collection unit stream state.
|
||||
* - Removed support for NVML_FI_DEV_LINK_SPEED_MBPS_L{0..} field Ids in Hopper. Replaced with NVML_FI_DEV_NVLINK_GET_SPEED with scope as link Id.
|
||||
* - Removed support for NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT{0..} field Ids in Hopper. Replaced with NVML_FI_DEV_NVLINK_ERROR_DL_CRC with scope as link Id.
|
||||
* - Removed support for NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L{0..} field Ids in Hopper. Replaced with NVML_FI_DEV_NVLINK_ERROR_DL_REPLAY with scope as link Id.
|
||||
* - Removed support for NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_{0..} field Ids in Hopper. Replaced with NVML_FI_DEV_NVLINK_ERROR_DL_RECOVERY with scope as link Id.
|
||||
* - Added new field ID \ref NVML_FI_DEV_NVLINK_GET_STATE to get nvlink state
|
||||
* - Added new field ID \ref NVML_FI_DEV_NVLINK_GET_VERSION to get nvlink version
|
||||
* - Added new field ID \ref NVML_FI_DEV_C2C_LINK_COUNT to get C2C link count
|
||||
* - Added new field ID \ref NVML_FI_DEV_C2C_LINK_GET_STATUS to get C2C link status
|
||||
* - Added new field ID \ref NVML_FI_DEV_C2C_LINK_GET_MAX_BW to get C2C link bandwidth
|
||||
*
|
||||
*
|
||||
* \section changelog21 Changes between NVML v515 Update and v520 ===
|
||||
*
|
||||
* - Added \ref nvmlDeviceGetMemClkVfOffset API to report the MemClk VF offset value.
|
||||
* - Added \ref nvmlDeviceGetMemClkMinMaxVfOffset API to report the Memory clock min and max VF offset that user can set for a specified GPU.
|
||||
* - Added \ref nvmlDeviceGetGpcClkMinMaxVfOffset API to report the Graphics clock min and max VF offset that user can set for a specified GPU.
|
||||
* - Added \ref nvmlGpmMetricsGet to calculate GPM metrics from two GPM samples
|
||||
* - Added \ref nvmlGpmSampleFree to free allocated GPM sample
|
||||
* - Added \ref nvmlGpmSampleAlloc to allocate a GPM sample
|
||||
* - Added \ref nvmlGpmSampleGet to retrieve a GPM snapshot
|
||||
* - Added \ref nvmlGpmQueryDeviceSupport to query whether a device supports GPM
|
||||
* - Added \ref nvmlDeviceGetFanControlPolicy_v2 API to report the control policy for a specified GPU fan.
|
||||
* - Added \ref nvmlDeviceSetFanControlPolicy API to set the control policy for a specified GPU fan.
|
||||
*
|
||||
*
|
||||
* \section changelog20 Changes between NVML v510 Update and v515 ===
|
||||
*
|
||||
* - Added \ref nvmlDeviceGetMinMaxClockOfPState API to report the min and max clocks of some clock domain for a given PState.
|
||||
* - Added \ref nvmlDeviceGetSupportedPerformanceStates API to get all supported Performance States (P-States) for the GPU.
|
||||
* - Added \ref nvmlDeviceGetGpcClkVfOffset API to report the GPCCLK VF offset value.
|
||||
* - Added \ref nvmlDeviceGetMinMaxFanSpeed API to report the min and max fan speed that user can set for a specified GPU fan.
|
||||
*
|
||||
*
|
||||
* \section changelog19 Changes between NVML v495 Update and v510 ===
|
||||
*
|
||||
* - Added \ref nvmlDeviceGetGpuInstanceProfileInfoV and \ref nvmlGpuInstanceGetComputeInstanceProfileInfoV APIs to include the profile name in their output.
|
||||
* - Added \ref nvmlDeviceGetMemoryBusWidth API to report the GPU's Memory Bus Width.
|
||||
* - Added \ref nvmlDeviceGetPcieLinkMaxSpeed API to report the GPU's PCIe Max Speed.
|
||||
* - Added \ref nvmlDeviceGetPowerSource API to report the GPU's power source as AC or battery.
|
||||
* - Added \ref nvmlDeviceGetNumFans API to report the GPU's number of fans.
|
||||
* - Added \ref nvmlDeviceGetNumGpuCores API to report the GPU's number of cores.
|
||||
* - Added \ref nvmlDeviceGetMemoryInfo_v2. The new version accounts separately for system-reserved memory, and includes it in the used memory amount. The previous version of the API reduced the total memory amount by the amount of system-reserved memory.
|
||||
* - Added \ref nvmlDeviceGetAdaptiveClockInfoStatus API to report the status of adaptive clocking for the GPU.
|
||||
*
|
||||
*
|
||||
* \section changelog18 Changes between NVML v465 Update and v470 ===
|
||||
*
|
||||
* - Added new MIG GPU instance profile NVML_GPU_INSTANCE_PROFILE_1_SLICE_REV1.
|
||||
* - Added \ref nvmlDeviceGetGpuInstancePossiblePlacements_v2. The previous version of the API will not support the profiles with possible placements greater than its total capacity, such as NVML_GPU_INSTANCE_PROFILE_1_SLICE_REV1.
|
||||
*
|
||||
*
|
||||
* \section changelog17 Changes between NVML v460 Update and v465 ===
|
||||
*
|
||||
* - Added new NVML_BRAND_* enumeration values for NVIDIA, NVIDIA_RTX, GEFORCE_RTX, QUADRO_RTX and TITAN_RTX
|
||||
* - Updated \ref nvmlDeviceGetHandleByUUID to make it MIG-aware.
|
||||
* - Updated \ref nvmlDeviceGetUUID to return MIG UUIDs in the canonical format, 'MIG-UUID'.
|
||||
* - Updated \ref nvmlDeviceGetHandleByUUID to accept both UUID formats, 'MIG-UUID' and 'MIG-GPU UUID/GID/CID'.
|
||||
* - The \ref nvmlDeviceSetAPIRestriction and \ref nvmlDeviceGetAPIRestriction APIs would no longer support the ability to toggle root-only requirement for \ref nvmlDeviceSetApplicationsClocks and \ref nvmlDeviceResetApplicationsClocks.
|
||||
*
|
||||
*
|
||||
* \section changelog16 Changes between NVML v450 Update and v460 ===
|
||||
*
|
||||
* - Added \ref nvmlDeviceCreateGpuInstanceWithPlacement to allow placement specification when creating a new MIG GPU instance.
|
||||
*
|
||||
*
|
||||
* \section changelog15 Changes between NVML v445 Update and v450 ===
|
||||
*
|
||||
* - Updated \ref nvmlDeviceGetFanSpeed and \ref nvmlDeviceGetFanSpeed_v2 for allowing fan speeds greater than 100% to be reported.
|
||||
* - Added \ref nvmlDeviceGetCpuAffinityWithinScope to determine the closest processor(s) within a NUMA node or socket.
|
||||
* - Added \ref nvmlDeviceGetMemoryAffinity to determine the closest NUMA node(s) within a NUMA node or socket.
|
||||
* - Added support to query and disable MIG mode on Windows.
|
||||
*
|
||||
*
|
||||
* \section changelog14 Changes between NVML v418 Update and v445 ===
|
||||
*
|
||||
* - Added support for NVIDIA Ampere architecture.
|
||||
* - Added support for Multi Instance GPU management. Refer "Multi Instance GPU Management" section for details.
|
||||
*
|
||||
*
|
||||
* \section changelog13 Changes between NVML v361 Update and v418
|
||||
*
|
||||
* - Support for Volta and Turing architectures, bug fixes, performance improvements, and new features
|
||||
*
|
||||
*
|
||||
* \section changelog12 Changes between NVML v349 Update and v361
|
||||
*
|
||||
* - Added \ref nvmlDeviceGetBoardPartNumber to return GPU part numbers
|
||||
* - Removed support for exclusive thread compute mode (Deprecated in 7.5)
|
||||
* - Added NVML_CLOCK_VIDEO (encoder/decoder) clock type as a supported clock type for \ref nvmlDeviceGetClockInfo and \ref nvmlDeviceGetMaxClockInfo.
|
||||
*
|
||||
*
|
||||
* \section changelog11 Changes between NVML v346 Update and v349
|
||||
*
|
||||
* The following new functionality is exposed on NVIDIA display drivers version 349 Production or later
|
||||
* - Updated \ref nvmlDeviceGetMemoryInfo to report Used/Free memory under Windows WDDM mode
|
||||
* - Added \ref nvmlDeviceGetTopologyCommonAncestor to find the common path between two devices
|
||||
* - Added \ref nvmlDeviceGetTopologyNearestGpus to get a set of GPUs given a path level
|
||||
* - Added \ref nvmlSystemGetTopologyGpuSet to retrieve a set of GPUs with a given CPU affinity
|
||||
* - Updated \ref nvmlDeviceGetAccountingPids, \ref nvmlDeviceGetAccountingBufferSize and \ref nvmlDeviceGetAccountingStats to report accounting information for both active and terminated processes. The execution time field in \ref nvmlAccountingStats_t structure is populated only when the process is terminated.
|
||||
*
|
||||
*
|
||||
* \section changelog10 Changes between NVML v340 Update and v346
|
||||
*
|
||||
* The following new functionality is exposed on NVIDIA display drivers version 346 Production or later
|
||||
* - added the public APIs nvmlDeviceGetPcieReplayCounter and nvmlDeviceGetPcieThroughput
|
||||
* - Discontinued Perl bindings support
|
||||
* - Added \p nvmlDeviceGetGraphicsRunningProcesses_v2 to get information about Graphics processes running on a GPU.
|
||||
*
|
||||
*
|
||||
* \section changelog9 Changes between NVML v331 Update and v340
|
||||
*
|
||||
* The following new functionality is exposed on NVIDIA display drivers version 340 Production or later
|
||||
* - Added \ref nvmlDeviceGetSamples to get recent power, utilization and clock samples for the GPU.
|
||||
* - Added \ref nvmlDeviceGetTemperatureThreshold to retrieve temperature threshold information.
|
||||
* - Added \ref nvmlDeviceGetBrand to retrieve brand information (e.g. Tesla, Quadro, etc.)
|
||||
* - Added support for K40d and K80
|
||||
* - Added nvmlDeviceGetTopology internal API to retrieve path info between PCI devices (remove this for DITA)
|
||||
* - Added \ref nvmlDeviceGetViolationStatus to get the duration of time during which the device was throttled (lower than requested clocks) due to thermal or power constraints.
|
||||
* - Added \ref nvmlDeviceGetEncoderUtilization and \ref nvmlDeviceGetDecoderUtilization APIs
|
||||
* - Added \ref nvmlDeviceGetCpuAffinity to determine the closest processor(s) affinity to a specific GPU
|
||||
* - Added \ref nvmlDeviceSetCpuAffinity to bind a specific GPU to the closest processor
|
||||
* - Added \ref nvmlDeviceClearCpuAffinity to unbind a specific GPU
|
||||
* - Added \ref nvmlDeviceGetBoardId to get a unique boardId for the running system
|
||||
* - Added \ref nvmlDeviceGetMultiGpuBoard to get whether the device is on a multiGPU board
|
||||
* - Added \ref nvmlDeviceGetAutoBoostedClocksEnabled and nvmlDeviceSetAutoBoostedClocksEnabled for querying and setting the state of auto boosted clocks on supporting hardware.
|
||||
* - Added \ref nvmlDeviceSetDefaultAutoBoostedClocksEnabled for setting the default state of auto boosted clocks on supporting hardware.
|
||||
*
|
||||
*
|
||||
* \section changelog8 Changes between NVML v5.319 Update and v331
|
||||
*
|
||||
* The following new functionality is exposed on NVIDIA display drivers version 331 Production or later
|
||||
* - Added \ref nvmlDeviceGetMinorNumber to get the minor number for the device.
|
||||
* - Added \ref nvmlDeviceGetBAR1MemoryInfo to get BAR1 total, available and used memory size.
|
||||
* - Added \ref nvmlDeviceGetBridgeChipInfo to get the information related to bridge chip firmware.
|
||||
* - Added enforced power limit query API \ref nvmlDeviceGetEnforcedPowerLimit
|
||||
* - Updated \ref nvmlEventSetWait_v2 to return xid event data in case of xid error event.
|
||||
* - Added support for K8
|
||||
*
|
||||
* \section changelog7 Changes between NVML v5.319 RC and v5.319 Update
|
||||
*
|
||||
* The following new functionality is exposed on NVIDIA display drivers version 319 Update or later
|
||||
*
|
||||
* - Added \ref nvmlDeviceSetAPIRestriction and \ref nvmlDeviceGetAPIRestriction, with initial ability to toggle root-only requirement for \ref nvmlDeviceSetApplicationsClocks and \ref nvmlDeviceResetApplicationsClocks.
|
||||
*
|
||||
* \section changelog6 Changes between NVML v4.304 and v5.319 RC
|
||||
*
|
||||
* The following new functionality is exposed on NVIDIA display drivers version 319 Production or later
|
||||
*
|
||||
* - IMPORTANT: Added _v2 versions of \ref nvmlDeviceGetHandleByIndex_v2 and \ref nvmlDeviceGetCount_v2 that also count devices not accessible by current user
|
||||
* - IMPORTANT: nvmlDeviceGetHandleByIndex_v2 (default) can also return NVML_ERROR_NO_PERMISSION
|
||||
* - Added nvmlInit_v2 and nvmlDeviceGetHandleByIndex_v2 that is safer and thus recommended function for initializing the library
|
||||
* - nvmlInit_v2 lazily initializes only requested devices (queried with nvmlDeviceGetHandle*)
|
||||
* - nvml.h defines nvmlInit_v2 and nvmlDeviceGetHandleByIndex_v2 as default functions
|
||||
* - Added \ref nvmlDeviceGetIndex
|
||||
* - Added \ref NVML_ERROR_GPU_IS_LOST to report GPUs that have fallen off the bus.
|
||||
* - Note: All NVML device APIs can return this error code, as a GPU can fall off the bus at any time.
|
||||
* - Added new class of APIs for gathering process statistics (\ref nvmlAccountingStats)
|
||||
* - Application Clocks are no longer supported on GPU's from Quadro product line
|
||||
* - Added APIs to support dynamic page retirement. See \ref nvmlDeviceGetRetiredPages and
|
||||
* \ref nvmlDeviceGetRetiredPagesPendingStatus
|
||||
* - Renamed nvmlClocksThrottleReasonUserDefinedClocks to nvmlClocksThrottleReasonApplicationsClocksSetting. Old name is deprecated and can be removed in one of the next major releases.
|
||||
* - Added \ref nvmlDeviceGetDisplayActive and updated documentation to clarify how it differs from \ref nvmlDeviceGetDisplayMode
|
||||
*
|
||||
* \section changelog5 Changes between NVML v4.304 RC and v4.304 Production
|
||||
*
|
||||
* The following new functionality is exposed on NVIDIA display drivers version 304 Production or later
|
||||
*
|
||||
* - Added \ref nvmlDeviceGetGpuOperationMode and \ref nvmlDeviceSetGpuOperationMode
|
||||
*
|
||||
* \section changelog4 Changes between NVML v3.295 and v4.304 RC
|
||||
*
|
||||
* The following new functionality is exposed on NVIDIA display drivers version 304 RC or later
|
||||
*
|
||||
* - Added \ref nvmlDeviceGetInforomConfigurationChecksum and \ref nvmlDeviceValidateInforom
|
||||
* - Added new error return value for initialization failure due to kernel module not receiving interrupts
|
||||
* - Added \ref nvmlDeviceSetApplicationsClocks, \ref nvmlDeviceGetApplicationsClock, \ref nvmlDeviceResetApplicationsClocks
|
||||
* - Added \ref nvmlDeviceGetSupportedMemoryClocks and \ref nvmlDeviceGetSupportedGraphicsClocks
|
||||
* - Added \ref nvmlDeviceGetPowerManagementLimitConstraints, \ref nvmlDeviceGetPowerManagementDefaultLimit and \ref nvmlDeviceSetPowerManagementLimit
|
||||
* - Added \ref nvmlDeviceGetInforomImageVersion
|
||||
* - Expanded \ref nvmlDeviceGetUUID to support all CUDA capable GPUs
|
||||
* - Deprecated \ref nvmlDeviceGetDetailedEccErrors in favor of \ref nvmlDeviceGetMemoryErrorCounter
|
||||
* - Added \ref NVML_MEMORY_LOCATION_TEXTURE_MEMORY to support reporting of texture memory error counters
|
||||
* - Added \ref nvmlDeviceGetCurrentClocksThrottleReasons and \ref nvmlDeviceGetSupportedClocksThrottleReasons
|
||||
* - \ref NVML_CLOCK_SM is now also reported on supported Kepler devices.
|
||||
* - Dropped support for GT200 based Tesla brand GPUs: C1060, M1060, S1070
|
||||
*
|
||||
* \section changelog3 Changes between NVML v2.285 and v3.295
|
||||
*
|
||||
* The following new functionality is exposed on NVIDIA display drivers version 295 or later
|
||||
*
|
||||
* - deprecated \ref nvmlDeviceGetHandleBySerial in favor of newly added \ref nvmlDeviceGetHandleByUUID
|
||||
* - Marked the input parameters of \ref nvmlDeviceGetHandleBySerial, \ref nvmlDeviceGetHandleByUUID and \ref nvmlDeviceGetHandleByPciBusId_v2 as const
|
||||
* - Added \ref nvmlDeviceOnSameBoard
|
||||
* - Added \ref nvmlConstants defines
|
||||
* - Added \ref nvmlDeviceGetMaxPcieLinkGeneration, \ref nvmlDeviceGetMaxPcieLinkWidth, \ref nvmlDeviceGetCurrPcieLinkGeneration,\ref nvmlDeviceGetCurrPcieLinkWidth
|
||||
* - Format change of \ref nvmlDeviceGetUUID output to match the UUID standard. This function will return a different value.
|
||||
* - \ref nvmlDeviceGetDetailedEccErrors will report zero for unsupported ECC error counters when a subset of ECC error counters are supported
|
||||
* \section changelog1 Changes between NVML v1.0 and v2.285
|
||||
*
|
||||
* The following new functionality is exposed on NVIDIA display drivers version 285 or later
|
||||
*
|
||||
* - Added possibility to query separately current and pending driver model with \p nvmlDeviceGetDriverModel
|
||||
* - Added API \ref nvmlDeviceGetVbiosVersion function to report VBIOS version.
|
||||
* - Added pciSubSystemId to \ref nvmlPciInfo_t struct
|
||||
* - Added API \ref nvmlErrorString function to convert error code to string
|
||||
* - Updated docs to indicate we support M2075 and C2075
|
||||
* - Added API \ref nvmlSystemGetHicVersion function to report HIC firmware version
|
||||
* - Added NVML versioning support
|
||||
* - Functions that changed API and/or size of structs have appended versioning suffix
|
||||
* (e.g. nvmlDeviceGetPciInfo_v2). Appropriate C defines have been
|
||||
* added that map old function names to the newer version of the function
|
||||
* - Added support for concurrent library usage by multiple libraries
|
||||
* - Added API \ref nvmlDeviceGetMaxClockInfo function for reporting device's clock limits
|
||||
* - Added new error code NVML_ERROR_DRIVER_NOT_LOADED used by \ref nvmlInit_v2
|
||||
* - Extended \ref nvmlPciInfo_t struct with new field: sub system id
|
||||
* - Added NVML support on Windows guest account
|
||||
* - Changed format of pciBusId string (to XXXX:XX:XX.X) of \ref nvmlPciInfo_t
|
||||
* - Parsing of busId in \ref nvmlDeviceGetHandleByPciBusId_v2 is less restrictive. You can pass 0:2:0.0 or 0000:02:00 and other variations
|
||||
* - Added API for events waiting for GPU events (Linux only) see docs of \ref nvmlEvents
|
||||
* - Added API \p nvmlDeviceGetComputeRunningProcesses_v2 and \ref nvmlSystemGetProcessName functions for looking up currently running compute applications
|
||||
* - Deprecated \ref nvmlDeviceGetPowerState in favor of \ref nvmlDeviceGetPerformanceState.
|
||||
* - Added \ref NVML_FI_DEV_POWER_REQUESTED_LIMIT to report out the power limit requested by the client.
|
||||
*/
|
||||
33
var/pkgs/cuda/13.0/nvml/doc/nvml_deprecation_and_removal.txt
Normal file
33
var/pkgs/cuda/13.0/nvml/doc/nvml_deprecation_and_removal.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
/*! @page DeprecationNotices Deprecation and/or removal notices for the NVML library
|
||||
* This chap†er lists the NVML functions marked for deprecation and/or removal. Starting from CUDA 13.1 deprecated functions will generate a compiler warning. Removed functions will return the NVML error code NVML_ERROR_DEPRECATED.
|
||||
*
|
||||
* \section depNotice1 CUDA 13.0 ===
|
||||
* The following functions are deprecated starting CUDA 13.0; they will be removed in CUDA 14.0.
|
||||
*
|
||||
* - nvmlDeviceSetApplicationsClocks
|
||||
* - nvmlDeviceGetApplicationsClock
|
||||
* - nvmlDeviceGetDefaultApplicationsClock
|
||||
* - nvmlDeviceResetApplicationsClocks
|
||||
* - nvmlDeviceGetViolationStatus
|
||||
* - nvmlVgpuInstanceGetLicenseStatus
|
||||
* - nvmlDeviceResetNvLinkUtilizationCounter
|
||||
* - nvmlDeviceFreezeNvLinkUtilizationCounter
|
||||
* - nvmlDeviceGetNvLinkUtilizationCounter
|
||||
* - nvmlDeviceGetNvLinkUtilizationControl
|
||||
* - nvmlDeviceSetNvLinkUtilizationControl
|
||||
* - nvmlDeviceSetMemClkVfOffset
|
||||
* - nvmlDeviceSetGpcClkVfOffset
|
||||
* - nvmlDeviceGetGpuFabricInfo
|
||||
* - nvmlDeviceGetDetailedEccErrors
|
||||
* - nvmlDeviceGetPowerManagementMode
|
||||
* - nvmlDeviceGetPowerState
|
||||
* - nvmlDeviceGetSupportedClocksThrottleReasons
|
||||
* - nvmlDeviceGetCurrentClocksThrottleReasons
|
||||
* - nvmlDeviceGetTemperature
|
||||
* - nvmlDeviceGetHandleBySerial
|
||||
*
|
||||
* The following data structures are deprecated starting CUDA 13.0
|
||||
*
|
||||
* - nvmlGpuFabricInfo_v2_t
|
||||
*
|
||||
*/
|
||||
87
var/pkgs/cuda/13.0/nvml/example/Makefile
Normal file
87
var/pkgs/cuda/13.0/nvml/example/Makefile
Normal file
@@ -0,0 +1,87 @@
|
||||
ARCH := $(shell getconf LONG_BIT)
|
||||
OS := $(shell cat /etc/issue)
|
||||
|
||||
ifneq (,$(wildcard /etc/redhat-release))
|
||||
RHEL_OS := $(shell cat /etc/redhat-release)
|
||||
endif
|
||||
|
||||
# Gets Driver Branch
|
||||
DRIVER_BRANCH := $(shell nvidia-smi | grep Driver | cut -f 3 -d' ' | cut -f 1 -d '.')
|
||||
|
||||
# Location of the CUDA Toolkit
|
||||
CUDA_PATH ?= "/usr/local/cuda-8.0"
|
||||
|
||||
ifeq (${ARCH},$(filter ${ARCH},32 64))
|
||||
# If correct architecture and libnvidia-ml library is not found
|
||||
# within the environment, build using the stub library
|
||||
|
||||
ifneq (,$(findstring Ubuntu,$(OS)))
|
||||
DEB := $(shell dpkg -l | grep cuda)
|
||||
ifneq (,$(findstring cuda, $(DEB)))
|
||||
NVML_LIB := /usr/lib/nvidia-$(DRIVER_BRANCH)
|
||||
else
|
||||
NVML_LIB := /lib${ARCH}
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring SUSE,$(OS)))
|
||||
RPM := $(shell rpm -qa cuda*)
|
||||
ifneq (,$(findstring cuda, $(RPM)))
|
||||
NVML_LIB := /usr/lib${ARCH}
|
||||
else
|
||||
NVML_LIB := /lib${ARCH}
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring CentOS,$(RHEL_OS)))
|
||||
RPM := $(shell rpm -qa cuda*)
|
||||
ifneq (,$(findstring cuda, $(RPM)))
|
||||
NVML_LIB := /usr/lib${ARCH}/nvidia
|
||||
else
|
||||
NVML_LIB := /lib${ARCH}
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring Red Hat,$(RHEL_OS)))
|
||||
RPM := $(shell rpm -qa cuda*)
|
||||
ifneq (,$(findstring cuda, $(RPM)))
|
||||
NVML_LIB := /usr/lib${ARCH}/nvidia
|
||||
else
|
||||
NVML_LIB := /lib${ARCH}
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring Fedora,$(RHEL_OS)))
|
||||
RPM := $(shell rpm -qa cuda*)
|
||||
ifneq (,$(findstring cuda, $(RPM)))
|
||||
NVML_LIB := /usr/lib${ARCH}/nvidia
|
||||
else
|
||||
NVML_LIB := /lib${ARCH}
|
||||
endif
|
||||
endif
|
||||
|
||||
else
|
||||
NVML_LIB := ../../lib${ARCH}/stubs/
|
||||
$(info "libnvidia-ml.so.1" not found, using stub library.)
|
||||
endif
|
||||
|
||||
ifneq (${ARCH},$(filter ${ARCH},32 64))
|
||||
$(error Unknown architecture!)
|
||||
endif
|
||||
|
||||
NVML_LIB += ../lib/
|
||||
NVML_LIB_L := $(addprefix -L , $(NVML_LIB))
|
||||
|
||||
CFLAGS := -I ../../include -I ../include
|
||||
LDFLAGS := -lnvidia-ml $(NVML_LIB_L)
|
||||
|
||||
all: example supportedVgpus
|
||||
example: example.o
|
||||
$(CC) $< $(CFLAGS) $(LDFLAGS) -o $@
|
||||
supportedVgpus: supportedVgpus.o
|
||||
$(CC) $< $(CFLAGS) $(LDFLAGS) -o $@
|
||||
clean:
|
||||
-@rm -f example.o
|
||||
-@rm -f example
|
||||
-@rm -f supportedVgpus.o
|
||||
-@rm -f supportedVgpus
|
||||
10
var/pkgs/cuda/13.0/nvml/example/README.txt
Normal file
10
var/pkgs/cuda/13.0/nvml/example/README.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
The NVIDIA GDK provides a simple example program that shows how to build an
|
||||
NVML client. When running an NVML client while the GDK is installed, be
|
||||
sure your library path first includes the actual NVML library (installed
|
||||
with the driver), not the stub library that exists solely for
|
||||
compilation on systems without an NVIDIA driver available.
|
||||
|
||||
If you have installed this example code via your packaging system,
|
||||
you should first copy it to a user directory before compilation.
|
||||
The packaging system uninstall feature will not remove this directory if it
|
||||
contains new files beyond what were installed as part of the GDK.
|
||||
180
var/pkgs/cuda/13.0/nvml/example/example.c
Normal file
180
var/pkgs/cuda/13.0/nvml/example/example.c
Normal file
@@ -0,0 +1,180 @@
|
||||
/***************************************************************************\
|
||||
|* *|
|
||||
|* Copyright 2010-2016 NVIDIA Corporation. All rights reserved. *|
|
||||
|* *|
|
||||
|* NOTICE TO USER: *|
|
||||
|* *|
|
||||
|* This source code is subject to NVIDIA ownership rights under U.S. *|
|
||||
|* and international Copyright laws. Users and possessors of this *|
|
||||
|* source code are hereby granted a nonexclusive, royalty-free *|
|
||||
|* license to use this code in individual and commercial software. *|
|
||||
|* *|
|
||||
|* NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE *|
|
||||
|* CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR *|
|
||||
|* IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH *|
|
||||
|* REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF *|
|
||||
|* MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR *|
|
||||
|* PURPOSE. IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, *|
|
||||
|* INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES *|
|
||||
|* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN *|
|
||||
|* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING *|
|
||||
|* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE *|
|
||||
|* CODE. *|
|
||||
|* *|
|
||||
|* U.S. Government End Users. This source code is a "commercial item" *|
|
||||
|* as that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting *|
|
||||
|* of "commercial computer software" and "commercial computer software *|
|
||||
|* documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) *|
|
||||
|* and is provided to the U.S. Government only as a commercial end item. *|
|
||||
|* Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through *|
|
||||
|* 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the *|
|
||||
|* source code with only those rights set forth herein. *|
|
||||
|* *|
|
||||
|* Any use of this source code in individual and commercial software must *|
|
||||
|* include, in the user documentation and internal comments to the code, *|
|
||||
|* the above Disclaimer and U.S. Government End Users Notice. *|
|
||||
|* *|
|
||||
|* *|
|
||||
\***************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <nvml.h>
|
||||
|
||||
static const char * convertToComputeModeString(nvmlComputeMode_t mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case NVML_COMPUTEMODE_DEFAULT:
|
||||
return "Default";
|
||||
case NVML_COMPUTEMODE_EXCLUSIVE_THREAD:
|
||||
return "Exclusive_Thread";
|
||||
case NVML_COMPUTEMODE_PROHIBITED:
|
||||
return "Prohibited";
|
||||
case NVML_COMPUTEMODE_EXCLUSIVE_PROCESS:
|
||||
return "Exclusive Process";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
nvmlReturn_t result;
|
||||
unsigned int device_count, i;
|
||||
|
||||
// First initialize NVML library
|
||||
result = nvmlInit();
|
||||
if (NVML_SUCCESS != result)
|
||||
{
|
||||
printf("Failed to initialize NVML: %s\n", nvmlErrorString(result));
|
||||
|
||||
printf("Press ENTER to continue...\n");
|
||||
getchar();
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = nvmlDeviceGetCount(&device_count);
|
||||
if (NVML_SUCCESS != result)
|
||||
{
|
||||
printf("Failed to query device count: %s\n", nvmlErrorString(result));
|
||||
goto Error;
|
||||
}
|
||||
printf("Found %u device%s\n\n", device_count, device_count != 1 ? "s" : "");
|
||||
|
||||
printf("Listing devices:\n");
|
||||
for (i = 0; i < device_count; i++)
|
||||
{
|
||||
nvmlDevice_t device;
|
||||
char name[NVML_DEVICE_NAME_BUFFER_SIZE];
|
||||
nvmlPciInfo_t pci;
|
||||
nvmlComputeMode_t compute_mode;
|
||||
|
||||
// Query for device handle to perform operations on a device
|
||||
// You can also query device handle by other features like:
|
||||
// nvmlDeviceGetHandleBySerial
|
||||
// nvmlDeviceGetHandleByPciBusId
|
||||
result = nvmlDeviceGetHandleByIndex(i, &device);
|
||||
if (NVML_SUCCESS != result)
|
||||
{
|
||||
printf("Failed to get handle for device %u: %s\n", i, nvmlErrorString(result));
|
||||
goto Error;
|
||||
}
|
||||
|
||||
result = nvmlDeviceGetName(device, name, NVML_DEVICE_NAME_BUFFER_SIZE);
|
||||
if (NVML_SUCCESS != result)
|
||||
{
|
||||
printf("Failed to get name of device %u: %s\n", i, nvmlErrorString(result));
|
||||
goto Error;
|
||||
}
|
||||
|
||||
// pci.busId is very useful to know which device physically you're talking to
|
||||
// Using PCI identifier you can also match nvmlDevice handle to CUDA device.
|
||||
result = nvmlDeviceGetPciInfo(device, &pci);
|
||||
if (NVML_SUCCESS != result)
|
||||
{
|
||||
printf("Failed to get pci info for device %u: %s\n", i, nvmlErrorString(result));
|
||||
goto Error;
|
||||
}
|
||||
|
||||
printf("%u. %s [%s]\n", i, name, pci.busId);
|
||||
|
||||
// This is a simple example on how you can modify GPU's state
|
||||
result = nvmlDeviceGetComputeMode(device, &compute_mode);
|
||||
if (NVML_ERROR_NOT_SUPPORTED == result)
|
||||
printf("\t This is not CUDA capable device\n");
|
||||
else if (NVML_SUCCESS != result)
|
||||
{
|
||||
printf("Failed to get compute mode for device %u: %s\n", i, nvmlErrorString(result));
|
||||
goto Error;
|
||||
}
|
||||
else
|
||||
{
|
||||
// try to change compute mode
|
||||
printf("\t Changing device's compute mode from '%s' to '%s'\n",
|
||||
convertToComputeModeString(compute_mode),
|
||||
convertToComputeModeString(NVML_COMPUTEMODE_PROHIBITED));
|
||||
|
||||
result = nvmlDeviceSetComputeMode(device, NVML_COMPUTEMODE_PROHIBITED);
|
||||
if (NVML_ERROR_NO_PERMISSION == result)
|
||||
printf("\t\t Need root privileges to do that: %s\n", nvmlErrorString(result));
|
||||
else if (NVML_ERROR_NOT_SUPPORTED == result)
|
||||
printf("\t\t Compute mode prohibited not supported. You might be running on\n"
|
||||
"\t\t windows in WDDM driver model or on non-CUDA capable GPU\n");
|
||||
else if (NVML_SUCCESS != result)
|
||||
{
|
||||
printf("\t\t Failed to set compute mode for device %u: %s\n", i, nvmlErrorString(result));
|
||||
goto Error;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\t Restoring device's compute mode back to '%s'\n",
|
||||
convertToComputeModeString(compute_mode));
|
||||
result = nvmlDeviceSetComputeMode(device, compute_mode);
|
||||
if (NVML_SUCCESS != result)
|
||||
{
|
||||
printf("\t\t Failed to restore compute mode for device %u: %s\n", i, nvmlErrorString(result));
|
||||
goto Error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = nvmlShutdown();
|
||||
if (NVML_SUCCESS != result)
|
||||
printf("Failed to shutdown NVML: %s\n", nvmlErrorString(result));
|
||||
|
||||
printf("All done.\n");
|
||||
|
||||
printf("Press ENTER to continue...\n");
|
||||
getchar();
|
||||
return 0;
|
||||
|
||||
Error:
|
||||
result = nvmlShutdown();
|
||||
if (NVML_SUCCESS != result)
|
||||
printf("Failed to shutdown NVML: %s\n", nvmlErrorString(result));
|
||||
|
||||
printf("Press ENTER to continue...\n");
|
||||
getchar();
|
||||
return 1;
|
||||
}
|
||||
160
var/pkgs/cuda/13.0/nvml/example/supportedVgpus.c
Normal file
160
var/pkgs/cuda/13.0/nvml/example/supportedVgpus.c
Normal file
@@ -0,0 +1,160 @@
|
||||
/***************************************************************************\
|
||||
|* *|
|
||||
|* Copyright 2010-2016 NVIDIA Corporation. All rights reserved. *|
|
||||
|* *|
|
||||
|* NOTICE TO USER: *|
|
||||
|* *|
|
||||
|* This source code is subject to NVIDIA ownership rights under U.S. *|
|
||||
|* and international Copyright laws. Users and possessors of this *|
|
||||
|* source code are hereby granted a nonexclusive, royalty-free *|
|
||||
|* license to use this code in individual and commercial software. *|
|
||||
|* *|
|
||||
|* NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE *|
|
||||
|* CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR *|
|
||||
|* IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH *|
|
||||
|* REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF *|
|
||||
|* MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR *|
|
||||
|* PURPOSE. IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, *|
|
||||
|* INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES *|
|
||||
|* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN *|
|
||||
|* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING *|
|
||||
|* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE *|
|
||||
|* CODE. *|
|
||||
|* *|
|
||||
|* U.S. Government End Users. This source code is a "commercial item" *|
|
||||
|* as that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting *|
|
||||
|* of "commercial computer software" and "commercial computer software *|
|
||||
|* documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) *|
|
||||
|* and is provided to the U.S. Government only as a commercial end item. *|
|
||||
|* Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through *|
|
||||
|* 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the *|
|
||||
|* source code with only those rights set forth herein. *|
|
||||
|* *|
|
||||
|* Any use of this source code in individual and commercial software must *|
|
||||
|* include, in the user documentation and internal comments to the code, *|
|
||||
|* the above Disclaimer and U.S. Government End Users Notice. *|
|
||||
|* *|
|
||||
|* *|
|
||||
\***************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <nvml.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
nvmlReturn_t result;
|
||||
unsigned int device_count, i;
|
||||
|
||||
// First initialize NVML library
|
||||
result = nvmlInit();
|
||||
if (NVML_SUCCESS != result)
|
||||
{
|
||||
printf("Failed to initialize NVML: %s\n", nvmlErrorString(result));
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = nvmlDeviceGetCount(&device_count);
|
||||
if (NVML_SUCCESS != result)
|
||||
{
|
||||
printf("Failed to query device count: %s\n", nvmlErrorString(result));
|
||||
goto Error;
|
||||
}
|
||||
|
||||
printf("Found %u device%s\n", device_count, device_count != 1 ? "s" : "");
|
||||
printf("Listing devices:\n");
|
||||
|
||||
for (i = 0; i < device_count; i++)
|
||||
{
|
||||
nvmlDevice_t device;
|
||||
char name[NVML_DEVICE_NAME_BUFFER_SIZE];
|
||||
nvmlPciInfo_t pci;
|
||||
|
||||
// Query for device handle to perform operations on a device
|
||||
// You can also query device handle by other features like:
|
||||
// nvmlDeviceGetHandleBySerial
|
||||
// nvmlDeviceGetHandleByPciBusId
|
||||
result = nvmlDeviceGetHandleByIndex(i, &device);
|
||||
if (NVML_SUCCESS != result)
|
||||
{
|
||||
printf("Failed to get handle for device %u: %s\n", i, nvmlErrorString(result));
|
||||
goto Error;
|
||||
}
|
||||
|
||||
result = nvmlDeviceGetName(device, name, NVML_DEVICE_NAME_BUFFER_SIZE);
|
||||
if (NVML_SUCCESS != result)
|
||||
{
|
||||
printf("Failed to get name of device %u: %s\n", i, nvmlErrorString(result));
|
||||
goto Error;
|
||||
}
|
||||
|
||||
// pci.busId is very useful to know which device physically you're talking to
|
||||
// Using PCI identifier you can also match nvmlDevice handle to CUDA device.
|
||||
result = nvmlDeviceGetPciInfo(device, &pci);
|
||||
if (NVML_SUCCESS != result)
|
||||
{
|
||||
printf("Failed to get pci info for device %u: %s\n", i, nvmlErrorString(result));
|
||||
goto Error;
|
||||
}
|
||||
|
||||
printf("%u. %s [%s]\n", i, name, pci.busId);
|
||||
|
||||
// This is an example to get the supported vGPUs type names
|
||||
unsigned int vgpuCount = 0;
|
||||
nvmlVgpuTypeId_t *vgpuTypeIds = NULL;
|
||||
unsigned int j;
|
||||
|
||||
result = nvmlDeviceGetSupportedVgpus(device, &vgpuCount, NULL);
|
||||
if (NVML_ERROR_INSUFFICIENT_SIZE != result)
|
||||
goto Error;
|
||||
|
||||
if (vgpuCount != 0)
|
||||
{
|
||||
vgpuTypeIds = malloc(sizeof(nvmlVgpuTypeId_t) * vgpuCount);
|
||||
if (!vgpuTypeIds)
|
||||
{
|
||||
printf("Memory allocation of %d bytes failed \n", (int)(sizeof(*vgpuTypeIds)*vgpuCount));
|
||||
goto Error;
|
||||
}
|
||||
|
||||
result = nvmlDeviceGetSupportedVgpus(device, &vgpuCount, vgpuTypeIds);
|
||||
if (NVML_SUCCESS != result)
|
||||
{
|
||||
printf("Failed to get the supported vGPUs with status %d \n", (int)result);
|
||||
goto Error;
|
||||
}
|
||||
|
||||
printf(" Displaying vGPU type names: \n");
|
||||
for (j = 0; j < vgpuCount; j++)
|
||||
{
|
||||
char vgpuTypeName[NVML_DEVICE_NAME_BUFFER_SIZE];
|
||||
unsigned int bufferSize = NVML_DEVICE_NAME_BUFFER_SIZE;
|
||||
|
||||
if (NVML_SUCCESS == (result = nvmlVgpuTypeGetName(vgpuTypeIds[j], vgpuTypeName, &bufferSize)))
|
||||
{
|
||||
printf(" %s\n",vgpuTypeName);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Failed to query the vGPU type name with status %d \n", (int)result);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (vgpuTypeIds)
|
||||
free(vgpuTypeIds);
|
||||
}
|
||||
|
||||
result = nvmlShutdown();
|
||||
if (NVML_SUCCESS != result)
|
||||
printf("Failed to shutdown NVML: %s\n", nvmlErrorString(result));
|
||||
|
||||
printf("All done.\n");
|
||||
return 0;
|
||||
|
||||
Error:
|
||||
result = nvmlShutdown();
|
||||
if (NVML_SUCCESS != result)
|
||||
printf("Failed to shutdown NVML: %s\n", nvmlErrorString(result));
|
||||
|
||||
return 1;
|
||||
}
|
||||
13607
var/pkgs/cuda/13.0/targets/x86_64-linux/include/nvml.h
Normal file
13607
var/pkgs/cuda/13.0/targets/x86_64-linux/include/nvml.h
Normal file
File diff suppressed because it is too large
Load Diff
BIN
var/pkgs/cuda/13.0/targets/x86_64-linux/lib/stubs/libnvidia-ml.a
Normal file
BIN
var/pkgs/cuda/13.0/targets/x86_64-linux/lib/stubs/libnvidia-ml.a
Normal file
Binary file not shown.
BIN
var/pkgs/ipxe/bootx64.efi
Normal file
BIN
var/pkgs/ipxe/bootx64.efi
Normal file
Binary file not shown.
BIN
var/pkgs/ipxe/ipxe.efi
Normal file
BIN
var/pkgs/ipxe/ipxe.efi
Normal file
Binary file not shown.
BIN
var/pkgs/ipxe/undionly.kpxe
Normal file
BIN
var/pkgs/ipxe/undionly.kpxe
Normal file
Binary file not shown.
751
var/pkgs/scripts/init.sh
Normal file
751
var/pkgs/scripts/init.sh
Normal file
@@ -0,0 +1,751 @@
|
||||
#!/bin/bash
|
||||
# ============================================================================
|
||||
# Sun HPC 系统初始化脚本
|
||||
# 功能:系统安装完成后自动配置 HPC 计算节点环境
|
||||
# 版本:1.0
|
||||
# ============================================================================
|
||||
|
||||
set -e
|
||||
|
||||
# ============================================================================
|
||||
# 配置变量(根据实际环境修改)
|
||||
# ============================================================================
|
||||
|
||||
# 日志文件
|
||||
LOG_FILE="/var/log/sunhpc-init.log"
|
||||
|
||||
FRONTEND_IP='172.16.9.254'
|
||||
|
||||
# HTTP 服务器地址
|
||||
HTTP_SERVER="http://${FRONTEND_IP}"
|
||||
|
||||
# YUM 仓库配置
|
||||
YUM_REPO_NAME="sunhpc-local"
|
||||
YUM_REPO_BASEURL="${HTTP_SERVER}/rockylinux/9.7"
|
||||
YUM_REPO_GPGCHECK=0
|
||||
|
||||
# 主机名映射文件(在 HTTP 服务器上)
|
||||
HOSTNAME_MAP_URL="${HTTP_SERVER}/ks/hostname-map.txt"
|
||||
|
||||
# MOTD 文件 URL
|
||||
MOTD_URL="${HTTP_SERVER}/ks/motd"
|
||||
|
||||
# NTP 服务器
|
||||
NTP_SERVER="ntp.aliyun.com"
|
||||
|
||||
# DNS 服务器
|
||||
DNS_SERVERS="114.114.114.114 223.5.5.5"
|
||||
|
||||
# ============================================================================
|
||||
# 颜色输出函数
|
||||
# ============================================================================
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE
|
||||
}
|
||||
|
||||
log_step() {
|
||||
echo -e "${BLUE}[STEP]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 基础环境准备
|
||||
# ============================================================================
|
||||
|
||||
init_log() {
|
||||
# 创建日志文件
|
||||
touch $LOG_FILE
|
||||
chmod 644 $LOG_FILE
|
||||
log_info "=========================================="
|
||||
log_info "Sun HPC Node Initialization Started"
|
||||
log_info "=========================================="
|
||||
}
|
||||
|
||||
check_network() {
|
||||
log_step "Checking network connectivity..."
|
||||
|
||||
# 测试网络连接
|
||||
if ping -c 1 -W 3 $FRONTEND_IP &>/dev/null; then
|
||||
log_info "Network connectivity: OK"
|
||||
return 0
|
||||
else
|
||||
log_warn "Cannot reach HTTP server, will retry later"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 1. 创建 .sunhpc-release 文件
|
||||
# ============================================================================
|
||||
|
||||
create_release_file() {
|
||||
log_step "Creating .sunhpc-release file..."
|
||||
|
||||
cat > /.sunhpc-release << EOF
|
||||
Sun HPC Platform Release 1.0
|
||||
Build Date: $(date '+%Y-%m-%d %H:%M:%S')
|
||||
Hostname: $(hostname)
|
||||
Kernel: $(uname -r)
|
||||
Architecture: $(uname -m)
|
||||
EOF
|
||||
|
||||
chmod 644 /.sunhpc-release
|
||||
log_info "Created /.sunhpc-release file"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 2. 配置主机名和 /etc/hosts
|
||||
# ============================================================================
|
||||
|
||||
configure_hostname() {
|
||||
log_step "Configuring hostname and /etc/hosts..."
|
||||
|
||||
local mac=$(ip link show | grep -oP 'ether \K[0-9a-f:]+' | head -1 | tr '[:upper:]' '[:lower:]')
|
||||
local hostname=""
|
||||
|
||||
# 从 HTTP 服务器获取主机名映射
|
||||
if check_network; then
|
||||
# 下载主机名映射文件
|
||||
local map_file="/tmp/hostname-map.txt"
|
||||
curl -s -o "$map_file" "$HOSTNAME_MAP_URL" 2>/dev/null
|
||||
|
||||
if [[ -f "$map_file" ]]; then
|
||||
# 根据 MAC 地址查找主机名
|
||||
hostname=$(grep -i "$mac" "$map_file" | awk '{print $2}' | head -1)
|
||||
|
||||
# 如果没有找到,根据 IP 最后一段生成
|
||||
if [[ -z "$hostname" ]]; then
|
||||
local ip_addr=$(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1' | head -1)
|
||||
local ip_last=$(echo $ip_addr | awk -F'.' '{print $4}')
|
||||
hostname="cn$(printf "%03d" $ip_last)"
|
||||
log_warn "No hostname mapping for MAC $mac, using generated: $hostname"
|
||||
fi
|
||||
else
|
||||
log_warn "Cannot download hostname map, using default"
|
||||
local ip_addr=$(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1' | head -1)
|
||||
local ip_last=$(echo $ip_addr | awk -F'.' '{print $4}')
|
||||
hostname="cn$(printf "%03d" $ip_last)"
|
||||
fi
|
||||
else
|
||||
# 网络不通时使用默认主机名
|
||||
hostname="node-$(hostname -s)"
|
||||
fi
|
||||
|
||||
# 设置主机名
|
||||
hostnamectl set-hostname "$hostname"
|
||||
log_info "Hostname set to: $hostname"
|
||||
|
||||
# 备份原始 hosts 文件
|
||||
cp /etc/hosts /etc/hosts.bak.$(date +%Y%m%d)
|
||||
|
||||
# 构建新的 hosts 文件
|
||||
cat > /etc/hosts << EOF
|
||||
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
|
||||
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
|
||||
|
||||
# Sun HPC Node Configuration
|
||||
$ip_addr $hostname
|
||||
|
||||
# Management Node
|
||||
$FRONTEND_IP cluster
|
||||
|
||||
# Optional: Add other compute nodes here
|
||||
EOF
|
||||
|
||||
# 尝试下载完整的集群 hosts 文件
|
||||
if check_network; then
|
||||
local cluster_hosts="${HTTP_SERVER}/ks/cluster-hosts.txt"
|
||||
if wget --spider -q "$cluster_hosts" 2>/dev/null; then
|
||||
wget -q -O /tmp/cluster-hosts.txt "$cluster_hosts"
|
||||
cat /tmp/cluster-hosts.txt >> /etc/hosts
|
||||
log_info "Downloaded cluster hosts configuration"
|
||||
else
|
||||
log_warn "$cluster_hosts not found on server."
|
||||
fi
|
||||
fi
|
||||
|
||||
log_info "Updated /etc/hosts"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 3. 配置 MOTD (Message of The Day)
|
||||
# ============================================================================
|
||||
|
||||
configure_motd() {
|
||||
log_step "Configuring MOTD..."
|
||||
|
||||
# 备份原始 MOTD
|
||||
if [[ -f /etc/motd ]]; then
|
||||
cp /etc/motd /etc/motd.bak.$(date +%Y%m%d)
|
||||
fi
|
||||
|
||||
# 尝试从服务器下载 MOTD
|
||||
if check_network; then
|
||||
if wget --spider -q "$MOTD_URL" 2>/dev/null; then
|
||||
wget -q -O /etc/motd "$MOTD_URL"
|
||||
log_info "Downloaded MOTD from server"
|
||||
else
|
||||
log_warn "Cannot download MOTD, creating default"
|
||||
create_default_motd
|
||||
fi
|
||||
else
|
||||
create_default_motd
|
||||
fi
|
||||
|
||||
chmod 644 /etc/motd
|
||||
}
|
||||
|
||||
create_default_motd() {
|
||||
cat > /etc/motd << EOF
|
||||
===========================================================
|
||||
Sun HPC Platform - Compute Node
|
||||
===========================================================
|
||||
Welcome to Sun High Performance Computing Cluster
|
||||
|
||||
System Information:
|
||||
--------------------
|
||||
Hostname....: $(hostname)
|
||||
IP Address..: $(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1' | head -1)
|
||||
OS Version..: $(cat /etc/redhat-release 2>/dev/null || echo "Rocky Linux")
|
||||
Kernel......: $(uname -r)
|
||||
Architecture: $(uname -m)
|
||||
CPU Cores...: $(nproc)
|
||||
Memory......: $(free -h | awk '/^Mem:/{print $2}')
|
||||
|
||||
Important URLs:
|
||||
--------------------
|
||||
• Documentation : http://172.16.9.254/docs
|
||||
• Job Submission : http://172.16.9.254/slurm
|
||||
• Monitoring: http : http://172.16.9.254/monitor
|
||||
|
||||
Slurm Commands:
|
||||
--------------------
|
||||
sinfo - View partition information
|
||||
squeue - View job queue
|
||||
srun - Run interactive job
|
||||
sbatch - Submit batch job
|
||||
scancel - Cancel job
|
||||
|
||||
===========================================================
|
||||
* Unauthorized access is prohibited
|
||||
* All activities are logged and monitored
|
||||
* For support: hpc@sun.com or ext. 12345
|
||||
===========================================================
|
||||
EOF
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 4. 配置 YUM 本地仓库
|
||||
# ============================================================================
|
||||
|
||||
configure_yum_repo() {
|
||||
log_step "Configuring YUM repository..."
|
||||
|
||||
local repo_file="/etc/yum.repos.d/${YUM_REPO_NAME}.repo"
|
||||
|
||||
# 备份现有 repo 文件
|
||||
if [[ -f "$repo_file" ]]; then
|
||||
cp "$repo_file" "${repo_file}.bak.$(date +%Y%m%d)"
|
||||
fi
|
||||
|
||||
# 创建仓库配置文件
|
||||
cat > "$repo_file" << EOF
|
||||
[${YUM_REPO_NAME}]
|
||||
name=Sun HPC Local Repository
|
||||
baseurl=${YUM_REPO_BASEURL}
|
||||
enabled=1
|
||||
gpgcheck=${YUM_REPO_GPGCHECK}
|
||||
priority=1
|
||||
EOF
|
||||
|
||||
# 如果是 Rocky 8/9,可能需要配置 appstream
|
||||
if [[ -d "/etc/yum.repos.d" ]]; then
|
||||
local appstream_repo="/etc/yum.repos.d/${YUM_REPO_NAME}-appstream.repo"
|
||||
cat > "$appstream_repo" << EOF
|
||||
[${YUM_REPO_NAME}-appstream]
|
||||
name=Sun HPC Local AppStream Repository
|
||||
baseurl=${YUM_REPO_BASEURL}-appstream
|
||||
enabled=1
|
||||
gpgcheck=${YUM_REPO_GPGCHECK}
|
||||
priority=1
|
||||
EOF
|
||||
fi
|
||||
|
||||
# 清理 YUM 缓存并测试
|
||||
yum clean all &>/dev/null
|
||||
yum makecache &>/dev/null
|
||||
|
||||
if [[ $? -eq 0 ]]; then
|
||||
log_info "YUM repository configured successfully"
|
||||
else
|
||||
log_warn "YUM repository configured but cache generation failed (network may be down)"
|
||||
fi
|
||||
|
||||
# 显示启用的仓库
|
||||
log_info "Enabled repositories:"
|
||||
yum repolist 2>/dev/null | grep -E "^${YUM_REPO_NAME}" | tee -a $LOG_FILE
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 5. 配置 DNS 解析
|
||||
# ============================================================================
|
||||
|
||||
configure_dns() {
|
||||
log_step "Configuring DNS resolution..."
|
||||
|
||||
# 备份 resolv.conf
|
||||
cp /etc/resolv.conf /etc/resolv.conf.bak.$(date +%Y%m%d) 2>/dev/null || true
|
||||
|
||||
# 配置 DNS
|
||||
cat > /etc/resolv.conf << EOF
|
||||
# Sun HPC DNS Configuration
|
||||
nameserver ${DNS_SERVERS%% *}
|
||||
$(for dns in ${DNS_SERVERS}; do echo "nameserver $dns"; done | tail -n +2)
|
||||
|
||||
# Local domain
|
||||
search sunhpc.local local
|
||||
EOF
|
||||
|
||||
# 防止 NetworkManager 覆盖 resolv.conf
|
||||
if [[ -f /etc/NetworkManager/NetworkManager.conf ]]; then
|
||||
if ! grep -q "dns=none" /etc/NetworkManager/NetworkManager.conf; then
|
||||
sed -i '/^\[main\]/a dns=none' /etc/NetworkManager/NetworkManager.conf
|
||||
systemctl restart NetworkManager 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
log_info "DNS configured: ${DNS_SERVERS}"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 6. 配置 NTP 时间同步
|
||||
# ============================================================================
|
||||
|
||||
configure_ntp() {
|
||||
log_step "Configuring NTP time synchronization..."
|
||||
|
||||
# 使用 chrony (Rocky 8/9 默认)
|
||||
if command -v chronyd &>/dev/null; then
|
||||
# 备份配置
|
||||
cp /etc/chrony.conf /etc/chrony.conf.bak.$(date +%Y%m%d)
|
||||
|
||||
# 配置 chrony
|
||||
cat > /etc/chrony.conf << EOF
|
||||
# Sun HPC NTP Configuration
|
||||
server ${NTP_SERVER} iburst
|
||||
pool 2.rocky.pool.ntp.org iburst
|
||||
|
||||
# Record the rate at which the system clock gains/losses time.
|
||||
driftfile /var/lib/chrony/drift
|
||||
|
||||
# Allow the system clock to be stepped in the first three updates
|
||||
makestep 1.0 3
|
||||
|
||||
# Enable kernel synchronization of the real-time clock (RTC)
|
||||
rtcsync
|
||||
|
||||
# Specify file containing keys for NTP authentication
|
||||
keyfile /etc/chrony.keys
|
||||
|
||||
# Specify directory for log files
|
||||
logdir /var/log/chrony
|
||||
EOF
|
||||
|
||||
# 重启 chrony
|
||||
systemctl restart chronyd &>/dev/null
|
||||
systemctl enable chronyd &>/dev/null
|
||||
|
||||
log_info "Chrony NTP configured with server: ${NTP_SERVER}"
|
||||
else
|
||||
# 使用 ntpd (旧系统)
|
||||
if command -v ntpd &>/dev/null; then
|
||||
cat > /etc/ntp.conf << EOF
|
||||
server ${NTP_SERVER} iburst
|
||||
restrict default nomodify notrap nopeer noquery
|
||||
restrict 127.0.0.1
|
||||
restrict ::1
|
||||
driftfile /var/lib/ntp/drift
|
||||
EOF
|
||||
systemctl restart ntpd &>/dev/null
|
||||
systemctl enable ntpd &>/dev/null
|
||||
log_info "NTP configured with server: ${NTP_SERVER}"
|
||||
else
|
||||
log_warn "No NTP service found (chronyd or ntpd)"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 7. 配置 SSH 服务
|
||||
# ============================================================================
|
||||
|
||||
configure_ssh() {
|
||||
log_step "Configuring SSH service..."
|
||||
|
||||
# 备份配置
|
||||
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d)
|
||||
|
||||
# 优化 SSH 配置
|
||||
sed -i 's/#PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
|
||||
sed -i 's/#PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config
|
||||
sed -i 's/#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
|
||||
sed -i 's/#UseDNS.*/UseDNS no/' /etc/ssh/sshd_config
|
||||
sed -i 's/#GSSAPIAuthentication.*/GSSAPIAuthentication no/' /etc/ssh/sshd_config
|
||||
|
||||
# 重启 SSH 服务
|
||||
systemctl restart sshd &>/dev/null
|
||||
|
||||
log_info "SSH service configured"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 8. 配置防火墙
|
||||
# ============================================================================
|
||||
|
||||
configure_firewall() {
|
||||
log_step "Configuring firewall..."
|
||||
|
||||
# 检查 firewalld 是否运行
|
||||
if systemctl is-active firewalld &>/dev/null; then
|
||||
# 开放常用端口
|
||||
firewall-cmd --permanent --add-service=ssh &>/dev/null
|
||||
firewall-cmd --permanent --add-service=dhcp &>/dev/null
|
||||
firewall-cmd --permanent --add-port=873/tcp &>/dev/null # rsync
|
||||
firewall-cmd --permanent --add-port=111/udp &>/dev/null # rpcbind
|
||||
|
||||
# 重新加载
|
||||
firewall-cmd --reload &>/dev/null
|
||||
|
||||
log_info "Firewall configured"
|
||||
else
|
||||
log_warn "Firewalld not running, skipping configuration"
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 9. 安装常用软件包
|
||||
# ============================================================================
|
||||
|
||||
install_packages() {
|
||||
log_step "Installing common packages..."
|
||||
|
||||
local packages=(
|
||||
wget curl vim nano
|
||||
htop iotop iftop
|
||||
net-tools bind-utils
|
||||
telnet nc tcpdump
|
||||
rsync tree lsof
|
||||
gcc make autoconf automake
|
||||
openssl-devel zlib-devel
|
||||
nfs-utils cifs-utils
|
||||
ntpdate
|
||||
)
|
||||
|
||||
if check_network; then
|
||||
for pkg in "${packages[@]}"; do
|
||||
if rpm -q "$pkg" &>/dev/null; then
|
||||
log_info "Package already installed: $pkg"
|
||||
else
|
||||
log_info "Installing package: $pkg"
|
||||
yum install -y "$pkg" &>> $LOG_FILE || log_warn "Failed to install: $pkg"
|
||||
fi
|
||||
done
|
||||
else
|
||||
log_warn "Network unavailable, skipping package installation"
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 11. 配置用户环境
|
||||
# ============================================================================
|
||||
|
||||
configure_user_env() {
|
||||
log_step "Configuring user environment..."
|
||||
|
||||
# 创建共享目录
|
||||
mkdir -p /share/{apps,home}
|
||||
mkdir -p /state/partition1/{tmp,work}
|
||||
|
||||
# 设置权限
|
||||
chmod 755 /share
|
||||
chmod 1777 /state/partition1/tmp
|
||||
|
||||
# 配置全局环境变量
|
||||
cat > /etc/profile.d/sunhpc.sh << 'EOF'
|
||||
# Sun HPC Environment Variables
|
||||
export SHARE_HOME=/share
|
||||
export STATE_HOME=/state/partition1
|
||||
EOF
|
||||
|
||||
chmod 644 /etc/profile.d/sunhpc.sh
|
||||
log_info "User environment configured"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 12. 配置系统优化参数
|
||||
# ============================================================================
|
||||
|
||||
configure_sysctl() {
|
||||
log_step "Configuring system optimization..."
|
||||
|
||||
cat > /etc/sysctl.d/99-sunhpc.conf << EOF
|
||||
# Sun HPC System Optimization
|
||||
|
||||
# Network optimization
|
||||
net.core.rmem_max = 134217728
|
||||
net.core.wmem_max = 134217728
|
||||
net.ipv4.tcp_rmem = 4096 87380 134217728
|
||||
net.ipv4.tcp_wmem = 4096 65536 134217728
|
||||
net.core.netdev_max_backlog = 5000
|
||||
net.ipv4.tcp_max_syn_backlog = 8192
|
||||
net.ipv4.tcp_sack = 1
|
||||
net.ipv4.tcp_timestamps = 1
|
||||
|
||||
# Memory optimization
|
||||
vm.swappiness = 10
|
||||
vm.dirty_ratio = 30
|
||||
vm.dirty_background_ratio = 5
|
||||
vm.vfs_cache_pressure = 50
|
||||
|
||||
# File system
|
||||
fs.file-max = 1048576
|
||||
fs.inotify.max_user_watches = 1048576
|
||||
|
||||
# Process scheduler
|
||||
kernel.sched_autogroup_enabled = 0
|
||||
kernel.sched_migration_cost_ns = 5000000
|
||||
EOF
|
||||
|
||||
sysctl -p /etc/sysctl.d/99-sunhpc.conf &>/dev/null
|
||||
log_info "System optimization configured"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 13. 配置系统限制
|
||||
# ============================================================================
|
||||
|
||||
configure_limits() {
|
||||
log_step "Configuring system limits..."
|
||||
|
||||
cat > /etc/security/limits.d/99-sunhpc.conf << EOF
|
||||
# Sun HPC System Limits
|
||||
* soft nofile 1048576
|
||||
* hard nofile 1048576
|
||||
* soft nproc 131072
|
||||
* hard nproc 131072
|
||||
* soft memlock unlimited
|
||||
* hard memlock unlimited
|
||||
root soft nofile 1048576
|
||||
root hard nofile 1048576
|
||||
EOF
|
||||
|
||||
log_info "System limits configured"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 14. 配置定时任务
|
||||
# ============================================================================
|
||||
|
||||
configure_crontab() {
|
||||
log_step "Configuring cron jobs..."
|
||||
|
||||
cat > /etc/cron.d/sunhpc << EOF
|
||||
# Sun HPC Cron Jobs
|
||||
|
||||
# Sync time every hour
|
||||
0 * * * * root /usr/sbin/chronyc -a makestep &>/dev/null
|
||||
|
||||
# Clean old logs daily
|
||||
0 2 * * * root find /var/log -name "*.log" -mtime +30 -delete 2>/dev/null
|
||||
|
||||
# Report node status every 5 minutes
|
||||
*/5 * * * * root /usr/local/bin/node-status-report &>/dev/null
|
||||
EOF
|
||||
|
||||
chmod 644 /etc/cron.d/sunhpc
|
||||
log_info "Cron jobs configured"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 15. 创建节点状态上报脚本
|
||||
# ============================================================================
|
||||
|
||||
create_report_script() {
|
||||
log_step "Creating node status report script..."
|
||||
|
||||
cat > /usr/local/bin/node-status-report << 'EOF'
|
||||
#!/bin/bash
|
||||
# Node status report script for Sun HPC
|
||||
|
||||
HTTP_SERVER="http://172.16.9.254"
|
||||
NODE_NAME=$(hostname)
|
||||
IP_ADDR=$(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1' | head -1)
|
||||
LOAD_AVG=$(uptime | awk -F'load average:' '{print $2}' | cut -d, -f1)
|
||||
MEM_TOTAL=$(free -g | awk '/^Mem:/{print $2}')
|
||||
MEM_USED=$(free -g | awk '/^Mem:/{print $3}')
|
||||
DISK_USED=$(df -h / | awk 'NR==2{print $5}' | sed 's/%//')
|
||||
SLURM_STATUS=$(systemctl is-active slurm-slurmd 2>/dev/null || echo "unknown")
|
||||
|
||||
# Build status JSON
|
||||
STATUS_JSON="{\"node\":\"$NODE_NAME\",\"ip\":\"$IP_ADDR\",\"load\":$LOAD_AVG,\"mem_total\":$MEM_TOTAL,\"mem_used\":$MEM_USED,\"disk_used\":$DISK_USED,\"slurm\":\"$SLURM_STATUS\",\"timestamp\":\"$(date -Iseconds)\"}"
|
||||
|
||||
# Send to management node
|
||||
curl -s -X POST -H "Content-Type: application/json" -d "$STATUS_JSON" ${HTTP_SERVER}/api/node-status &>/dev/null
|
||||
EOF
|
||||
|
||||
chmod +x /usr/local/bin/node-status-report
|
||||
log_info "Node status report script created"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 16. 配置日志轮转
|
||||
# ============================================================================
|
||||
|
||||
configure_logrotate() {
|
||||
log_step "Configuring log rotation..."
|
||||
|
||||
cat > /etc/logrotate.d/sunhpc << EOF
|
||||
/var/log/sunhpc-init.log {
|
||||
daily
|
||||
rotate 30
|
||||
compress
|
||||
delaycompress
|
||||
missingok
|
||||
notifempty
|
||||
create 644 root root
|
||||
}
|
||||
EOF
|
||||
|
||||
log_info "Log rotation configured"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 17. 清理临时文件
|
||||
# ============================================================================
|
||||
|
||||
cleanup() {
|
||||
log_step "Cleaning up temporary files..."
|
||||
|
||||
# 删除临时文件
|
||||
rm -f /tmp/hostname-map.txt 2>/dev/null
|
||||
rm -f /tmp/cluster-hosts.txt 2>/dev/null
|
||||
|
||||
# 清除 YUM 缓存
|
||||
yum clean all &>/dev/null
|
||||
|
||||
log_info "Cleanup completed"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 18. 生成初始化完成报告
|
||||
# ============================================================================
|
||||
|
||||
generate_report() {
|
||||
log_step "Generating initialization report..."
|
||||
|
||||
cat > /root/init-report.txt << EOF
|
||||
===========================================
|
||||
Sun HPC Node Initialization Report
|
||||
===========================================
|
||||
Init Time: $(date '+%Y-%m-%d %H:%M:%S')
|
||||
Hostname: $(hostname)
|
||||
IP Address: $(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1' | head -1)
|
||||
MAC Address: $(ip link show | grep -oP 'ether \K[0-9a-f:]+' | head -1)
|
||||
|
||||
Services Status:
|
||||
- NetworkManager: $(systemctl is-active NetworkManager)
|
||||
- chronyd: $(systemctl is-active chronyd 2>/dev/null || echo "stopped")
|
||||
- sshd: $(systemctl is-active sshd)
|
||||
- slurm-slurmd: $(systemctl is-active slurm-slurmd 2>/dev/null || echo "stopped")
|
||||
- firewalld: $(systemctl is-active firewalld)
|
||||
|
||||
YUM Repositories:
|
||||
$(yum repolist)
|
||||
|
||||
Files Created:
|
||||
- /.sunhpc-release
|
||||
- /etc/hosts (updated)
|
||||
- /etc/motd (updated)
|
||||
- /etc/yum.repos.d/sunhpc-local.repo
|
||||
- /etc/chrony.conf (updated)
|
||||
- /etc/security/limits.d/99-sunhpc.conf
|
||||
- /etc/sysctl.d/99-sunhpc.conf
|
||||
|
||||
===========================================
|
||||
EOF
|
||||
|
||||
cat /root/init-report.txt >> $LOG_FILE
|
||||
log_info "Initialization report saved to /root/init-report.txt"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 主函数
|
||||
# ============================================================================
|
||||
|
||||
main() {
|
||||
log_info "Starting Sun HPC node initialization..."
|
||||
|
||||
# 执行所有初始化步骤
|
||||
init_log
|
||||
check_network
|
||||
create_release_file
|
||||
configure_hostname
|
||||
configure_motd
|
||||
configure_yum_repo
|
||||
configure_dns
|
||||
configure_ntp
|
||||
configure_ssh
|
||||
configure_firewall
|
||||
install_packages
|
||||
configure_slurm
|
||||
configure_user_env
|
||||
configure_sysctl
|
||||
configure_limits
|
||||
configure_crontab
|
||||
create_report_script
|
||||
configure_logrotate
|
||||
cleanup
|
||||
generate_report
|
||||
|
||||
log_info "=========================================="
|
||||
log_info "Sun HPC node initialization completed!"
|
||||
log_info "=========================================="
|
||||
|
||||
# 显示关键信息
|
||||
echo ""
|
||||
echo -e "${GREEN}=== Initialization Complete ===${NC}"
|
||||
echo -e "Hostname: $(hostname)"
|
||||
echo -e "Release file: $(cat /.sunhpc-release | head -1)"
|
||||
echo -e "Log file: $LOG_FILE"
|
||||
echo -e "Report: /root/init-report.txt"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 脚本入口
|
||||
# ============================================================================
|
||||
|
||||
# 检查是否需要重启
|
||||
if [[ "$1" == "--reboot" ]]; then
|
||||
main
|
||||
log_info "Rebooting in 5 seconds..."
|
||||
sleep 5
|
||||
reboot
|
||||
else
|
||||
main
|
||||
log_info "Initialization completed. You may reboot if needed."
|
||||
fi
|
||||
21
var/pkgs/scripts/ipxe.sh
Normal file
21
var/pkgs/scripts/ipxe.sh
Normal file
@@ -0,0 +1,21 @@
|
||||
#!ipxe
|
||||
|
||||
:main_menu
|
||||
menu iPXE boot menu
|
||||
|
||||
item rockylinux Install Rockylinux 9.7
|
||||
item local Boot from Local Disk
|
||||
|
||||
choose --default rockylinux --timeout 5000 selected || goto local
|
||||
|
||||
:rockylinux
|
||||
echo Booting Rockylinux from networking
|
||||
kernel http://172.16.9.254/linux/rockylinux/9.7/images/pxeboot/vmlinuz \
|
||||
net.ifnames=0 biosdevname=0 inst.sshd \
|
||||
inst.repo=http://172.16.9.254/linux/rockylinux/9.7 \
|
||||
inst.ks=http://172.16.9.254/linux/ks/rhel.ks
|
||||
initrd http://172.16.9.254/linux/rockylinux/9.7/images/pxeboot/initrd.img
|
||||
boot
|
||||
|
||||
:local
|
||||
exit
|
||||
77
var/pkgs/scripts/rhel.ks
Normal file
77
var/pkgs/scripts/rhel.ks
Normal file
@@ -0,0 +1,77 @@
|
||||
graphical
|
||||
timezone Asia/Shanghai --utc
|
||||
keyboard --xlayouts="us"
|
||||
lang en_US.UTF-8
|
||||
selinux --disabled
|
||||
|
||||
url --url='http://172.16.9.254/linux/rockylinux/9.7'
|
||||
|
||||
network --bootproto=dhcp --device=link --ipv6=auto --activate
|
||||
|
||||
# Partition clearing information
|
||||
# zerombr
|
||||
# clearpart --all --initlabel
|
||||
# ignoredisk --only-use=sda
|
||||
# part /boot --fstype="xfs" --ondisk=sda --size=1024
|
||||
# part swap --fstype="swap" --ondisk=sda --size=4096
|
||||
# part / --fstype="xfs" --ondisk=sda --size=97278
|
||||
# part /home --fstype="xfs" --ondisk=sda --size=20480
|
||||
|
||||
# autopart --type=lvm
|
||||
# autopart --type=plain
|
||||
# autopart --nohome
|
||||
# autopart --noswap
|
||||
|
||||
|
||||
%include /tmp/diskinfo
|
||||
|
||||
%packages
|
||||
@^minimal-environment
|
||||
@development
|
||||
@standard
|
||||
vim
|
||||
wget
|
||||
curl
|
||||
autofs
|
||||
nfs-utils
|
||||
nfs4-acl-tools
|
||||
sssd-nfs-idmap
|
||||
%end
|
||||
|
||||
rootpw --plaintext "admin_b101"
|
||||
user --name=dell --plaintext --password="admin_b101" --gecos="dell"
|
||||
reboot
|
||||
|
||||
%pre --interpreter=/bin/bash
|
||||
if [ -d /sys/firmware/efi ]; then
|
||||
cat > /tmp/diskinfo <<EOF
|
||||
clearpart --all --initlabel
|
||||
part /boot/efi --fstype=efi --size=600 --fsoptions="umask=0077,shortname=uefi"
|
||||
part /boot --fstype=xfs --size=1024
|
||||
part pv.01 --size=1 --grow
|
||||
volgroup vg_sys pv.01
|
||||
logvol / --fstype=xfs --name=root --vgname=vg_sys --size=51200
|
||||
logvol swap --fstype=swap --name=swap --vgname=vg_sys --size=4096
|
||||
logvol /data --fstype=xfs --name=data --vgname=vg_sys --size=1 --grow
|
||||
EOF
|
||||
else
|
||||
cat > /tmp/diskinfo <<EOF
|
||||
clearpart --all --initlabel
|
||||
part /boot --fstype=xfs --size=1024 --asprimary
|
||||
part pv.01 --size=1 --grow
|
||||
volgroup vg_sys pv.01
|
||||
logvol / --fstype=xfs --name=root --vgname=vg_sys --size=51200
|
||||
logvol swap --fstype=swap --name=swap --vgname=vg_sys --size=4096
|
||||
logvol /data --fstype=xfs --name=data --vgname=vg_sys --size=1 --grow
|
||||
EOF
|
||||
fi
|
||||
%end
|
||||
|
||||
%post
|
||||
curl -s -o /tmp/init.sh http://172.16.9.254/linux/ks/init.sh
|
||||
chmod +x /tmp/init.sh
|
||||
/tmp/init.sh
|
||||
%end
|
||||
|
||||
%addon com_redhat_kdump --disable
|
||||
%end
|
||||
Reference in New Issue
Block a user