Added Makefile-type instalation of with pip3 and systemd daemon

This commit is contained in:
Domen Tabernik 2020-07-27 14:56:37 +00:00
parent 3c8b435e32
commit dd8789ab53
7 changed files with 91 additions and 49 deletions

27
Makefile Normal file
View File

@ -0,0 +1,27 @@
all: superfans-gpu-controller superfans-gpu-controller.service
.PHONY: all superfans-gpu-controller-daemon install uninstall clean
service_dir=/etc/systemd/system
conf_dir=/etc
awk_script='BEGIN {FS="="; OFS="="}{if ($$1=="ExecStart") {$$2=exec_path} if (substr($$1,1,1) != "\#") {print $$0}}'
superfans-gpu-controller: superfans_gpu_controller.py setup.py
pip3 install .
superfans-gpu-controller.service: superfans_gpu_controller.py
# awk is needed to replace the absolute path of mydaemon executable in the .service file
awk -v exec_path='$(shell which superfans-gpu-controller) $(conf_dir)/superfans-gpu-controller.json' $(awk_script) superfans-gpu-controller.service.template > superfans-gpu-controller.service
install: $(service_dir) $(conf_dir) superfans-gpu-controller.service
cp superfans-gpu-controller.json $(conf_dir)
cp superfans-gpu-controller.service $(service_dir)
-systemctl enable superfans-gpu-controller.service
-systemctl enable superfans-gpu-controller
uninstall:
-systemctl stop superfans-gpu-controller
-rm -r $(service_dir)/superfans-gpu-controller.service
-rm -r $(conf_dir)/superfans-gpu-controller.json
clean:
-rm superfans-gpu-controller.service

View File

@ -1,30 +0,0 @@
#!/bin/sh
echo "Created '/etc/systemd/system/superfans-gpu-controller.service' service file"
echo "[Unit]
Description=GPU-based controller of SUPERMICRO server FANs
After=syslog.target nvidia-persistenced.service
[Service]
Type=simple
User=root
Group=root
WorkingDirectory=`pwd`
Environment=PYTHONUNBUFFERED=true
ExecStart=/usr/bin/python -u `pwd`/superfans_gpu_controller.py
StandardOutput=syslog
StandardError=syslog
[Install]
WantedBy=multi-user.target" > /etc/systemd/system/superfans-gpu-controller.service
echo "\n"
echo "Registering superfans-gpu-controller.service"
systemctl enable superfans-gpu-controller.service
systemctl daemon-reload
echo "Enabled start at system startup"
systemctl enable superfans-gpu-controller
echo "Starting the service"
systemctl start superfans-gpu-controller

11
setup.py Normal file
View File

@ -0,0 +1,11 @@
from setuptools import setup
setup(name='superfans-gpu-controller',
version='0.1',
description='Supermicro FAN controller based on NVIDIA GPU temperature',
py_modules=['superfans_gpu_controller','superfans' ],
entry_points={
'console_scripts': [
'superfans-gpu-controller = superfans_gpu_controller:main',
],
},
)

View File

@ -0,0 +1,8 @@
{
"fan_settings" : {"0": 20,
"60": 25,
"70": 30,
"80": 35,
"87": 40,
"90": 43}
}

View File

@ -0,0 +1,15 @@
[Unit]
Description=GPU-based controller of SUPERMICRO server FANs
After=syslog.target nvidia-persistenced.service
[Service]
Type=simple
User=root
Group=root
Environment="PYTHONUNBUFFERED=true"
ExecStart=/placeholder/path/to/superfans-gpu-controller "/etc/superfans-gpu-controller.json"
StandardOutput=syslog
StandardError=syslog
[Install]
WantedBy=multi-user.target

View File

@ -184,10 +184,10 @@ def ipmi_raw_cmd(raw_cmd, hostname = 'localhost', username=None, password=None,
try: try:
s = subprocess.check_output(cmd + " 2>&1", shell=True) s = subprocess.check_output(cmd + " 2>&1", shell=True)
except subprocess.CalledProcessError, ex: except subprocess.CalledProcessError as ex:
print("Error: Problem running ipmitool") print("Error: Problem running ipmitool")
print("Command: %s" % cmd) print("Command: %s" % cmd)
print("Return code: %d" % ex) print("Return code: %s" % ex)
return False return False
out = s.strip() out = s.strip()
@ -212,10 +212,10 @@ def ipmi_fan_status(hostname = 'localhost', username=None, password=None, use_en
cmd = 'ipmitool -I lanplus -U %s %s -H %s sensor | grep FAN' % (shlex.quote(username), cmd_pass, hostname) cmd = 'ipmitool -I lanplus -U %s %s -H %s sensor | grep FAN' % (shlex.quote(username), cmd_pass, hostname)
try: try:
s = subprocess.check_output(cmd + " 2>&1", shell=True) s = subprocess.check_output(cmd + " 2>&1", shell=True)
except subprocess.CalledProcessError, ex: except subprocess.CalledProcessError as ex:
print("Error: Problem running ipmitool") print("Error: Problem running ipmitool")
print("Command: %s" % cmd) print("Command: %s" % cmd)
print("Return code: %d" % ex) print("Return code: %s" % ex)
return False return False
fan_status_return = {} fan_status_return = {}

View File

@ -3,7 +3,7 @@
# author: Domen Tabernik # author: Domen Tabernik
# 2019 # 2019
import time, superfans, subprocess, signal, sys import time, superfans, subprocess, signal, sys, json
class GracefulKiller: class GracefulKiller:
kill_now = False kill_now = False
@ -24,6 +24,7 @@ def retrieve_nvidia_gpu_temperature():
s = subprocess.check_output(cmd + " 2>&1", shell=True) s = subprocess.check_output(cmd + " 2>&1", shell=True)
if len(s) <= 0: if len(s) <= 0:
return False return False
s = s.decode('ascii')
out = [int(x.strip()) for x in s.split("\n") if len(x.strip()) > 0] out = [int(x.strip()) for x in s.split("\n") if len(x.strip()) > 0]
if out: if out:
@ -45,6 +46,9 @@ def superfans_gpu_controller(fan_settings, FAN_INCREASED_MIN_TIME=120, sleep_sec
""" """
superfan_config = dict(hostname= 'localhost') superfan_config = dict(hostname= 'localhost')
# convert fan_settings keys from string to int
fan_settings = { int(k): fan_settings[k] for k in sorted(fan_settings.keys()) }
# save default present before changing anything # save default present before changing anything
default_preset = superfans.get_preset(superfan_config) default_preset = superfans.get_preset(superfan_config)
print('Started fan control using GPU temperature.') print('Started fan control using GPU temperature.')
@ -113,11 +117,11 @@ def superfans_gpu_controller(fan_settings, FAN_INCREASED_MIN_TIME=120, sleep_sec
# Allow for 1% difference in target # Allow for 1% difference in target
update_sys1_fan = any([d > fan_target_eps for d in diff_sys1_fan]) update_sys1_fan = any([d > fan_target_eps for d in diff_sys1_fan])
update_sys2_fan = any([d > fan_target_eps for d in diff_sys2_fan]) update_sys2_fan = any([d > fan_target_eps for d in diff_sys2_fan])
if update_sys1_fan: #if update_sys1_fan:
superfans.set_fan(superfan_config, target_fan, superfans.FAN_ZONE_SYS1) # superfans.set_fan(superfan_config, target_fan, superfans.FAN_ZONE_SYS1)
if update_sys2_fan: #if update_sys2_fan:
superfans.set_fan(superfan_config, target_fan, superfans.FAN_ZONE_SYS2) # superfans.set_fan(superfan_config, target_fan, superfans.FAN_ZONE_SYS2)
if update_sys1_fan or update_sys2_fan: if update_sys1_fan or update_sys2_fan:
print('\tCurrent GPU measurements (in C): %s' % ','.join(map(str,GPU_temp))) print('\tCurrent GPU measurements (in C): %s' % ','.join(map(str,GPU_temp)))
@ -134,13 +138,20 @@ def superfans_gpu_controller(fan_settings, FAN_INCREASED_MIN_TIME=120, sleep_sec
superfans.set_preset(superfan_config, default_preset) superfans.set_preset(superfan_config, default_preset)
print('Reverted back to system default.') print('Reverted back to system default.')
if __name__ == "__main__": def main():
# fan settings = {[in deg C]: [% fan], ...} if len(sys.argv) != 2:
fan_settings = {0: 20, print('Invalid number of arguments: missing configuration file!!')
60: 25, print('')
70: 30, print(' Usage: %s [PATH_TO_JSON_CONFIG]' % sys.argv[0])
80: 35, print('')
87: 40, print(' Configuration file in JSON format should include "fan_settings" = {[in deg C]: [% fan], ...} ')
90: 43} print
exit(0)
superfans_gpu_controller(fan_settings) with open(sys.argv[1]) as cfg_file:
cfg = json.load(cfg_file)
superfans_gpu_controller(cfg['fan_settings'])
if __name__ == "__main__":
main()