1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00
VILLASnode/python/villas/node/node.py

143 lines
3.7 KiB
Python
Raw Permalink Normal View History

import json
2021-02-24 09:51:27 +01:00
import os
import tempfile
import subprocess
import logging
import signal
import requests
import datetime
LOGGER = logging.getLogger('villas.node')
2020-06-07 23:24:21 +02:00
class Node(object):
2020-08-17 17:12:54 +02:00
api_version = 'v2'
2020-10-15 10:21:22 +02:00
def __init__(self, api_url=None,
log_filename=None,
config_filename=None, config={},
2020-06-07 23:24:21 +02:00
executable='villas-node', **kwargs):
2020-10-15 10:21:22 +02:00
self.api_url = api_url
self.log_filename = log_filename
self.executable = executable
2021-02-24 09:51:27 +01:00
if config_filename and config:
raise RuntimeError('Can\'t provide config_filename and '
'config at the same time!')
if config_filename:
with open(self.config_filename) as f:
self.config = json.load(f)
else:
self.config = config
# Try to deduct api_url from config
if self.api_url is None:
port = config.get('http', {}).get('port')
if port is None:
port = 80 if os.getuid() == 0 else 8080
self.api_url = f'http://localhost:{port}'
def start(self):
2020-06-07 23:24:21 +02:00
self.config_file = tempfile.NamedTemporaryFile(mode='w+',
suffix='.json')
2021-02-24 09:51:27 +01:00
json.dump(self.config, self.config_file)
self.config_file.flush()
if self.log_filename is None:
now = datetime.datetime.now()
2020-06-07 23:24:21 +02:00
self.log_filename = now.strftime(
'villas-node_%Y-%m-%d_%H-%M-%S.log')
self.log = open(self.log_filename, 'w+')
2020-06-07 23:24:21 +02:00
LOGGER.info("Starting VILLASnode instance with config: %s",
self.config_file.name)
2020-06-07 23:24:21 +02:00
self.child = subprocess.Popen([self.executable, self.config_file.name],
stdout=self.log, stderr=self.log)
def pause(self):
2018-11-30 20:45:30 +01:00
LOGGER.info("Pausing VILLASnode instance")
self.child.send_signal(signal.SIGSTOP)
def resume(self):
2018-11-30 20:45:30 +01:00
LOGGER.info("Resuming VILLASnode instance")
self.child.send_signal(signal.SIGCONT)
def stop(self):
2018-11-30 20:45:30 +01:00
LOGGER.info("Stopping VILLASnode instance")
self.child.send_signal(signal.SIGTERM)
self.child.wait()
self.log.close()
def restart(self):
2018-11-30 20:45:30 +01:00
LOGGER.info("Restarting VILLASnode instance")
self.request('restart')
@property
def active_config(self):
2020-11-11 00:32:20 +01:00
return self.request('config')
@property
def nodes(self):
2020-08-17 17:12:54 +02:00
return self.request('nodes')
@property
def paths(self):
2020-08-17 17:12:54 +02:00
return self.request('paths')
2020-11-11 00:32:20 +01:00
@property
def status(self):
return self.request('status')
def load_config(self, i):
if type(i) is dict:
cfg = i
elif type(i) is str:
cfg = json.loads(i)
2020-11-11 09:10:33 +01:00
elif hasattr(i, 'read'): # file-like?
2020-11-11 00:32:20 +01:00
cfg = json.load(i)
else:
raise TypeError()
req = {
'config': cfg
}
2020-11-11 09:10:33 +01:00
2020-11-11 00:32:20 +01:00
self.request('restart', method='POST', json=req)
2020-11-11 00:32:20 +01:00
def request(self, action, method='GET', **args):
2020-11-11 09:10:33 +01:00
2020-11-11 00:32:20 +01:00
if 'timeout' not in args:
args['timeout'] = 1
2020-11-11 00:32:20 +01:00
r = requests.request(method,
2020-11-11 09:10:33 +01:00
f'{self.api_url}/api/{self.api_version}/{action}',
**args)
r.raise_for_status()
return r.json()
2020-10-15 10:21:22 +02:00
def get_local_version(self):
ver = subprocess.check_output([self.executable, '-V'])
return ver.decode('ascii').rstrip()
2020-06-07 23:12:19 +02:00
2020-10-15 10:21:22 +02:00
def get_version(self):
2020-11-11 00:32:20 +01:00
resp = self.request('status')
2020-11-11 00:32:20 +01:00
return resp['version']
def is_running(self):
if self.child is None:
return False
else:
return self.child.poll() is None