151 lines
5.2 KiB
Python
151 lines
5.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
# *****************************************************************************
|
|
# NICOS, the Networked Instrument Control System of the MLZ
|
|
# Copyright (c) 2009-2018 by the NICOS contributors (see AUTHORS)
|
|
#
|
|
# 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>
|
|
#
|
|
# *****************************************************************************
|
|
"""managing SECoP server and connections
|
|
|
|
SEC Node with added functionality for starting and stoping frappy servers
|
|
connected to a SEC node
|
|
"""
|
|
|
|
import os
|
|
from os.path import expanduser
|
|
|
|
from nicos import config, session
|
|
from nicos.core import Override, Param, Moveable, status
|
|
from nicos.devices.secop import SecNodeDevice
|
|
from nicos.utils.comparestrings import compare
|
|
from servicemanager import FrappyManager
|
|
|
|
|
|
def suggest(poi, allowed_keys):
|
|
comp = {}
|
|
for key in allowed_keys:
|
|
comp[key] = compare(poi, key)
|
|
comp = sorted(comp.items(), key=lambda t: t[1], reverse=True)
|
|
return [m[0] for m in comp[:3] if m[1] > 2]
|
|
|
|
|
|
class FrappyNode(SecNodeDevice, Moveable):
|
|
"""SEC node device
|
|
|
|
with ability to start / restart / stop the frappy server
|
|
"""
|
|
|
|
parameter_overrides = {
|
|
'target': Override(description='configuration for the frappy server or host:port',
|
|
type=str, default=''),
|
|
}
|
|
parameters = {
|
|
'service': Param('frappy service name (main, stick or addons)', type=str, default=''),
|
|
}
|
|
|
|
_service_manager = FrappyManager()
|
|
_cfgvalue = None
|
|
|
|
def doStart(self, value):
|
|
if value == 'None':
|
|
value = None
|
|
self.restart(value)
|
|
|
|
def doStop(self):
|
|
"""never busy"""
|
|
|
|
def doRead(self, maxage=0):
|
|
if self._cfgvalue is None and self._cache:
|
|
self._cfgvalue = self._cache.get(self, 'value')
|
|
return self._cfgvalue
|
|
|
|
@classmethod
|
|
def config_dirs(cls, ins, service):
|
|
sm = cls._service_manager
|
|
sm.get_info()
|
|
return sm.config_dirs(ins, service)
|
|
|
|
@classmethod
|
|
def available_cfg(cls, service):
|
|
ins = config.instrument
|
|
available_cfg = set()
|
|
for d in cls.config_dirs(ins, service):
|
|
try:
|
|
available_cfg |= set(c[:-4] for c in os.listdir(expanduser(d)) if c.endswith('.cfg'))
|
|
except FileNotFoundError: # ignore missing directories
|
|
pass
|
|
return available_cfg
|
|
|
|
def disable(self):
|
|
seaconn = session.devices.get('seaconn')
|
|
if seaconn and seaconn._attached_secnode:
|
|
seaconn.communicate('frappy_remove %s' % self.service)
|
|
self._set_status(*self._status)
|
|
|
|
def _set_status(self, code, text):
|
|
if self.uri == '':
|
|
code, text = status.DISABLED, 'disabled'
|
|
SecNodeDevice._set_status(self, code, text)
|
|
|
|
def restart(self, cfg=None):
|
|
"""restart frappy server
|
|
|
|
if value is not given: restart with the same config
|
|
else restart with given config
|
|
"""
|
|
was_cfg = self._cfgvalue and ':' not in self._cfgvalue
|
|
if cfg is None: # do restart anyway
|
|
cfg = self._cfgvalue
|
|
elif cfg == self._cfgvalue: # probably called from doStart
|
|
if cfg == '':
|
|
self.disable()
|
|
# do not restart in this case
|
|
return
|
|
is_cfg = cfg and ':' not in cfg
|
|
ins = config.instrument
|
|
info = self._service_manager.get_ins_info(ins)
|
|
if is_cfg:
|
|
available_cfg = self.available_cfg(self.service)
|
|
failed = False
|
|
for cfgitem in cfg.split(','):
|
|
if cfgitem not in available_cfg:
|
|
failed = True
|
|
suggestions = suggest(cfgitem, available_cfg)
|
|
if suggestions:
|
|
session.log.error('%s unknown, did you mean: %s' % (cfgitem, ', '.join(suggestions)))
|
|
if failed:
|
|
raise ValueError('use "frappy_list()" to get a list of valid frappy configurations')
|
|
uri = 'localhost:%d' % info[self.service]
|
|
else:
|
|
uri = cfg
|
|
if uri != self.uri:
|
|
self.uri = '' # disconnect
|
|
if was_cfg:
|
|
self._service_manager.do_stop(ins, self.service)
|
|
if uri:
|
|
if is_cfg:
|
|
self._service_manager.do_restart(ins, self.service, cfg, self.log)
|
|
self.uri = uri # connect
|
|
else:
|
|
self.disable()
|
|
self._cfgvalue = cfg
|
|
if self._cache:
|
|
self._cache.put(self, 'value', cfg)
|
|
self._setROParam('target', cfg)
|