servicemanager/nicos.py
Markus Zolliker eee6c22b87 add sea config information to sea list
+ fixed servman import (must be __init__)
2020-11-03 12:06:29 +01:00

259 lines
9.4 KiB
Python

# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Module authors:
# Markus Zolliker <markus.zolliker@psi.ch>
#
# *****************************************************************************
import os
import sys
import shutil
from glob import glob
from os.path import join, abspath, dirname, expanduser, exists, islink
from configparser import ConfigParser
from __init__ import ServiceManager
ENV_KEYS = {
'NICOS_CACHE_PORT',
'NICOS_DAEMON_PORT',
'FRAPPY_MAIN_PORT',
'FRAPPY_STICK_PORT',
'FRAPPY_ADDONS_PORT',
'SEA_PORT',
}
def copy_all(srcdir, dstdir):
"""copy all files from srcdir to dstdir"""
files = glob(join(srcdir, '*'))
for src in files:
shutil.copy2(src, dstdir)
return files
class NicosManager(ServiceManager):
group = 'nicos'
services = ('cache', 'daemon', 'poller')
def do_create(self, ins, nr=None, *args):
"""TODO: redo"""
self.get_info()
if ins == 'all' or ins == 'check':
inslist = list(self.info)
else:
inslist = [ins]
for ins_i in inslist:
env = self.env[ins_i]
base = join(env['NICOS_ROOT'], env['NICOS_PACKAGE'], ins)
nicos_conf = join(base, 'nicos.conf')
content = {
'nicos': {
'setup_subdirs': '%s, common, frappy' % ins,
'logging_path': '%s/%s' % (env['NICOS_LOG'], ins),
'pid_path': '%s/%s' % (env['NICOS_LOG'], ins),
},
'environment': {
key: env[key] for key in env if key in ENV_KEYS
}
}
try:
cp = ConfigParser()
cp.optionsxform = str
cp.read(nicos_conf)
if set(cp.sections) != set(content):
oldcontent = None
else:
oldcontent = {key: cp[key] for key in content}
except FileNotFoundError:
oldcontent = None
if content != oldcontent:
cp = ConfigParser()
cp.optionsxform = str
for key, sdict in content.items():
cp[key] = sdict
cp.write(nicos_conf + 'x')
# pdir = self.start_dir
# if ins is None or ins == 'common':
# raise ValueError("nothing to do")
# insdict = {info['cache']['port'] % 100: ins_i for ins_i, info in self.info.items()}
# nrdict = {v: k for k, v in insdict.items()}
# if nr is not None:
# nr = int(nr)
# if ins == 'all':
# if nr is not None:
# raise ValueError("'nicos create all' has no <nr> argument")
# action = 'update'
# else:
# if nr is None:
# nr = nrdict.get(ins)
# if nr is None:
# raise ValueError('%s not known, <nr> has to specified' % ins)
# if insdict.get(nr, ins) != ins:
# raise ValueError('%d conflicts with %s' % (nr, insdict[nr]))
# action = 'create' if ins in insdict.values() else 'update'
# insdict = {nr: ins}
# for nr, ins in insdict.items():
# print('%s %3d %s %s' % (action, nr, ins, pdir))
# os.makedirs(join(pdir, ins), exist_ok=True)
# with open(join(pdir, ins, 'nicos.conf'), 'w') as f:
# f.write(NICOS_CONF % dict(insnr='%02d' % nr, ins=ins, sea=8630 + nr,
# logroot=os.environ.get('NICOS_LOG')))
# shutil.copyfile(join(pdir, 'common', 'guiconfig.py'), join(pdir, ins, 'guiconfig.py'))
@staticmethod
def extra_info(ins):
try:
datadir = join(os.environ.get('NICOS_DATA', '.'), ins)
datadir = join(datadir, os.readlink(join(datadir, 'current')))
except FileNotFoundError:
return None
return 'nicos data: %s' % datadir
@staticmethod
def linked_dir(current_wd):
link = join(current_wd, 'data')
if islink(link):
return join(link, os.readlink(link))
if exists(link):
raise ValueError('%s is not a symlink' % link)
return None
@staticmethod
def handle_linked(target, wd=None):
if not target:
print('no links from %s' % os.getcwd())
return
targetdir = abspath(join(target, '..'))
analist_file = join(targetdir, 'data_links.txt')
linked_from = []
if exists(analist_file):
with open(analist_file) as f:
for line in f:
line = line.strip()
if line and line != wd:
if islink(join(line, 'data')):
linked_from.append(line)
if wd:
linked_from.append(wd)
linked_from = '\n'.join(linked_from)
if wd:
with open(analist_file, 'w') as f:
f.write('%s\n' % linked_from)
print('links to %s from:\n%s' % (target, linked_from))
@staticmethod
def make_symlink(ins):
data = join(os.environ['NICOS_DATA'], ins)
target = join(data, os.readlink(join(data, 'current')), 'data')
link = join(os.getcwd(), 'data')
if islink(link):
os.remove(link)
elif exists(link):
raise ValueError('%s is not a symlink' % link)
os.symlink(target, link, True)
NicosManager.handle_linked(target, os.getcwd())
@staticmethod
def copy_linked(datadir=None):
src = NicosManager.linked_dir(os.getcwd())
if src:
if not datadir:
if src.rsplit('/', 1)[-1] != 'data':
raise ValueError('%s is already a copy' % src)
datadir = dirname(src)
else:
if not datadir:
raise ValueError('missing data dir')
src = join(datadir, 'data')
dst = join(os.getcwd(), '%s_%s_data' % tuple(datadir.rsplit('/', 2)[-2:]))
os.makedirs(dst, exist_ok=True)
n = len(copy_all(src, dst))
print('copy %d files to %s' % (n, dst))
# copy scripts
src = join(datadir, 'scripts')
dst = join(dst, 'scripts')
os.makedirs(dst, exist_ok=True)
n = len(copy_all(src, dst))
print('copy %d files to %s' % (n, dst))
@staticmethod
def do_link(ins, *args):
"""make/show symlink to nicos data in current wd"""
if ins is None:
NicosManager.handle_linked(NicosManager.linked_dir(os.getcwd()))
else:
NicosManager.make_symlink(ins)
sys.exit(0)
@staticmethod
def do_copy(ins, year_prop, *args):
"""copy nicos data to current wd"""
if ins is None:
NicosManager.copy_linked()
else:
data = join(os.environ['NICOS_DATA'], ins)
if year_prop:
year, sep, proposal = year_prop.rpartition('/')
if year:
src = join(data, year, proposal)
else:
# get proposal from most recent year
src = next(reversed(sorted(glob(join(data, '*', proposal)))))
else:
src = join(data, os.readlink(join(data, 'current')))
NicosManager.copy_linked(src)
def prepare_start(self, ins):
start_dir, env = super().prepare_start(ins)
instr = '%s.%s' % (env['NICOS_PACKAGE'], ins)
env['INSTRUMENT'] = instr
start_dir = env.get('NICOS_START', start_dir)
return start_dir, env
def prepare_client(self, ins):
self.check_running(ins, 'daemon')
env = self.prepare_start(ins)[1]
os.environ.update(env)
os.chdir(join(os.environ['NICOS_ROOT'], env['NICOS_PACKAGE']))
sys.path.insert(0, os.environ['NICOS_ROOT'])
def run_client(self, ins, main, app, **kwargs):
serverhost = os.environ.get('NICOS_SERVER_HOST', 'localhost')
sys.argv[:] = [app, 'guest:guest@%s:%d' % (serverhost, self.info[ins]['daemon'])]
sys.exit(main(sys.argv, **kwargs))
def do_cli(self, ins):
self.prepare_client(ins)
from nicos.clients.cli import main
os.environ['NICOS_HISTORY_FILE'] = expanduser('~/.nicoshistory_%s' % ins)
self.run_client(ins, main, 'nicos-client',
userpath=expanduser('~/.config/nicos_client_%s' % ins))
def do_gui(self, ins):
self.prepare_client(ins)
print(os.getcwd())
from nicos.clients.gui.main import main
userpath = expanduser('~/.config/nicos_%s' % ins)
print('starting nicos gui %s' % ins, userpath)
self.run_client(ins, main, 'nicos-gui', userpath=userpath)