예제 #1
0
 def xmlrpc___setitem__(self, *a, **k):
     return sanitize(self.xmlrpc_set)(*a, **k)
예제 #2
0
 def xmlrpc_getFlags(self, *a, **k):
     return sanitize(self.getFlags)(*a, **k)
예제 #3
0
 def xmlrpc_getAttributes(self, *a, **k):
     return sanitize(self.desc.getAttributes)(*a, **k)
예제 #4
0
 def xmlrpc_h_get_time(self, *a, **k):
     return sanitize(self.desc.h_get_time)(*a, **k)
예제 #5
0
 def xmlrpc_getkid(self, *a, **k):
     return sanitize(self.desc.getkid)(*a, **k)
예제 #6
0
class ConfigurationInterface(xmlrpc.XMLRPC, object):
    """Public interface to Conf objects (XMLRPC and get/set mechanics)"""
    conf_class = 'Conf'
    """Conf class towards which this class acts as a ConfigurationInterface."""
    main_confdir = params.confdir
    """Base server configuration directory"""
    conf_def = [
        {
            "handle": 'mro',
            "name": 'Class hierarchy',
            "type": 'List',
            "attr": ['ReadOnly', 'Hidden']
        },
        {
            "handle": 'log',
            "name": 'Log',
            "type": 'Log',
            "attr": ['History']
        },
    ]
    """Default configuration list"""

    server = None
    allow_none = True
    _Method__name = 'undefined'

    def __init__(self, desc):
        """Create an interface for configuration object `desc`. """

        xmlrpc.XMLRPC.__init__(self, allowNone=True)
        object.__init__(self)
        self.separator = '/'
        self.devices = []
        self.controls = {}
        self.desc = desc
        self.log = logger.SubLogger(self)

    def keys(self, *a, **k):
        return self.desc.keys(*a, **k)

    def get_preset(self, *a, **k):
        return self.desc.get_preset(*a, **k)

    def sete(self, *a, **k):
        return self.desc.sete(*a, **k)

    def hasattr(self, *a, **k):
        return self.desc.hasattr(*a, **k)

    def getattr(self, *a, **k):
        return self.desc.getattr(*a, **k)

    def setattr(self, *a, **k):
        return self.desc.setattr(*a, **k)

    def getkid(self, *a, **k):
        return self.desc.getkid(*a, **k)

    def gettype(self, *a, **k):
        return self.desc.gettype(*a, **k)

    def has_key(self, *a, **k):
        return self.desc.has_key(*a, **k)

    def listPresets(self, *a, **k):
        return self.desc.listPresets(*a, **k)

    def updateCurrent(self, *a, **k):
        return self.desc.updateCurrent(*a, **k)

    def update(self, *a, **k):
        return self.desc.update(*a, **k)

    def fp(self, *a, **k):
        return self.desc.fp(*a, **k)

    def iolist(self, *a, **k):
        return self.desc.iolist(*a, **k)

    def get_from_preset(self, *a, **k):
        return self.desc.get_from_preset(*a, **k)

    def compare_presets(self, *a, **k):
        return self.desc.compare_presets(*a, **k)

    def set_to_preset(self, *a, **k):
        return self.desc.set_to_preset(*a, **k)

    def xmlrpc_has_key(self, *a, **k):
        return self.desc.has_key(*a, **k)

    def xmlrpc_keys(self, *a, **k):
        return self.desc.keys(*a, **k)

    def xmlrpc_hasattr(self, *a, **k):
        return self.hasattr(*a, **k)

    def xmlrpc_getattr(self, *a, **k):
        return self.getattr(*a, **k)

    def xmlrpc_setattr(self, *a, **k):
        return self.setattr(*a, **k)

    def xmlrpc_getkid(self, *a, **k):
        return sanitize(self.desc.getkid)(*a, **k)

    def xmlrpc_applyDesc(self, *a, **k):
        return self.applyDesc(*a, **k)

    def xmlrpc_listPresets(self, *a, **k):
        return self.desc.listPresets(*a, **k)

    def save(self, *a, **k):
        return self.desc.save(*a, **k)

    def xmlrpc_save(self, *a, **k):
        return self.desc.save(*a, **k)

    def remove(self, *a, **k):
        return self.desc.remove(*a, **k)

    def xmlrpc_remove(self, *a, **k):
        return self.desc.remove  # config. file(*a, **k)

    def rename(self, *a, **k):
        return self.desc.rename(*a, **k)

    def xmlrpc_rename(self, *a, **k):
        return self.desc.rename(*a, **k)

    def delete(self, *a, **k):
        return self.desc.delete(*a, **k)

    def xmlrpc_delete(self, *a, **k):
        return self.desc.delete  # key(*a, **k)

    def xmlrpc_h_get(self, *a, **k):
        return sanitize(self.desc.h_get)(*a, **k)

    def xmlrpc_h_get_time(self, *a, **k):
        return sanitize(self.desc.h_get_time)(*a, **k)

    def xmlrpc_getAttributes(self, *a, **k):
        return sanitize(self.desc.getAttributes)(*a, **k)

    def xmlrpc_iolist(self, *a, **k):
        return self.iolist(*a, **k)

    def xmlrpc_get_from_preset(self, *a, **k):
        return self.get_from_preset(*a, **k)

    def xmlrpc_compare_presets(self, *a, **k):
        return self.compare_presets(*a, **k)

    def xmlrpc_set_to_preset(self, *a, **k):
        return self.set_to_preset(*a, **k)

    def h_get(self, *a, **k):
        return self.desc.h_get(*a, **k)

    def h_get_history(self, *a, **k):
        return self.desc.h_get_history(*a, **k)

    def h_get_time(self, *a, **k):
        return self.desc.h_get_time(*a, **k)

    def h_clear(self, *a, **k):
        return self.desc.h_clear(*a, **k)

    def h_time_at(self, *a, **k):
        return self.desc.h_time_at(*a, **k)

    def xmlrpc_h_time_at(self, *a, **k):
        return self.h_time_at(*a, **k)

    def xmlrpc___getitem__(self, *a, **k):
        return sanitize(self.xmlrpc_get)(*a, **k)

    def xmlrpc___setitem__(self, *a, **k):
        return sanitize(self.xmlrpc_set)(*a, **k)

    def xmlrpc_setFlags(self, *a, **k):
        return sanitize(self.setFlags)(*a, **k)

    def xmlrpc_getFlags(self, *a, **k):
        return sanitize(self.getFlags)(*a, **k)

    def xmlrpc___contains__(self, *a, **k):
        return self.desc.has_key(*a, **k)

    def xmlrpc___hash__(self, *a, **k):
        return self.__hash__(*a, **k)

    def xmlrpc___eq__(self, *a, **k):
        return self.__eq__(*a, **k)

    def xmlrpc___repr__(self, *a, **k):
        return self.desc.__repr__(*a, **k)

    def xmlrpc___str__(self, *a, **k):
        return self.__str__(*a, **k)

    # Must explicitly define these functions.
    # Cannot assign them to self during __init__
    def __getitem__(self, *args, **kwargs):
        return self.get(*args, **kwargs)

    def __setitem__(self, *args, **kwargs):
        return self.set(*args, **kwargs)

    def __contains__(self, *args, **kwargs):
        return self.desc.has_key(*args, **kwargs)

    def getcontrols(self):
        """Returns currently defined controls"""
        return self.controls.keys()

    xmlrpc_getcontrols = getcontrols

    def close(self):
        if self.desc is False:
            return False
        print 'ConfigurationInterface.close', type(self), id(self)
        self.desc.close()
        self.desc = False
        return True

    @property
    def class_name(self):
        return self.__class__.__name__

    def classname(self):
        return self.class_name

    xmlrpc_classname = classname

    def mro(self):
        mro = inspect.getmro(self.__class__)
        r = []
        for cl in mro:
            r.append(cl.__name__)
        return r[:-3]

    xmlrpc_mro = mro

    def describe(self, *a, **kw):
        self['mro'] = self.mro()
        return self.desc.describe(*a, **kw)

    def get_mro(self):
        return self.mro()

    def iteritems(self):
        pass

    def iterkeys(self):
        pass

    def __iter__(self):
        pass

    def __hash__(self):
        """L'hash viene calcolato sulla base dell'oggetto self.log onde evitare ricorsioni infinite."""
        return hash(self.log)

    def __eq__(self, other):
        if not getattr(other, '_Method__name', False):
            return False
        if self._Method__name != other._Method__name:
            return False
        return True

    def __str__(self):
        if self.desc is False:
            return 'Closed {}: {}, {}, {}'.format(self.__class__.__name__,
                                                  repr(self), type(self),
                                                  id(self))
        r = self.__class__.__name__ + ' for ' + self.desc.__str__()
        r += '\nconf_dir: %s \nconf_obj: %s' % (self.conf_dir, self.conf_obj)
        return r

    def xmlrpc_describe(self, readLevel=0):
        """Sanitize description dictionary and filter depending on user's readLevel."""
        r = self.desc.describe()
        for key, val in r.items():
            if val['readLevel'] > readLevel:
                del r[key]
                continue
            val['current'] = xmlrpcSanitize(val['current'],
                                            attr=val['attr'],
                                            otype=val['type'])
            #           if 'Binary' in val['attr'] or val['type']=='Profile':
            #               val['current']=xmlrpc.Binary(dumps(val['current']))
            r[key] = val
        l = [v.keys() for v in r.values()]
        print set([type(item) for sublist in l for item in sublist])
        return r

    _rmodel = False

    def rmodel(self):
        """Dictionary model recursively listing all subdevices' paths.
        {'self':name,
         'sub1':{'self':name,
                 'sub1sub1':{'self':name,...},
         'sub2':{'self':name}
          ...}
        """
        if self._rmodel is not False:
            return self._rmodel
        out = {'self': self['name']}
        for name, path in self.list():
            d = self.getSubHandler(path)
            if d is self:
                print 'Skipping myself', name
                continue
            if d is None:
                print 'skipping NONE', name, path
                continue
            out[path] = d.rmodel()
        return out

    xmlrpc_rmodel = rmodel

    @classmethod
    def _pget(cls, key, self):
        """Helper function for getting a class-defined property"""
        # print 'PGET', type(self), key # this works!
        return self.get(key)

    @classmethod
    def _pset(cls, key, self, val):
        """Helper function for setting a class-defined property"""
        # FIXME: pset does not work!
        # print 'PSET', type(self), key, val
        return self.set(key, val)

    @classmethod
    def setProperties(cls, *keys):
        """Contructs class properties corresponding to Conf options."""
        for key in keys:
            if hasattr(cls, key):
                v = getattr(cls, key)
                print 'Property {} is overwriting previous attribute {}'.format(
                    key, repr(v))
                del v
            pget = functools.partial(cls._pget, key)
            pset = functools.partial(cls._pset, key)
            p = property(pget, pset)
            setattr(cls, key, p)

    def set_preset(self, *args, **kwargs):
        """Calls applyDesc after setting the preset"""
        r = self.desc.set_preset(*args, **kwargs)
        if r:
            self.applyDesc()
        return r

    def applyDesc(self, *a, **k):
        """To be reimplemented."""
        return True

    def validate_preset_name(self, name):
        lst = self.listPresets()
        ret = select_preset_for_name(name, self.listPresets())
        self.log.debug('validate_preset_name', name, ret, lst)
        return ret

    def setAttributes(self, name, attrlist, writeLevel=5):
        return self.desc.setAttributes(name, attrlist)

    xmlrpc_setAttributes = setAttributes

    def add_attr(self, opt, attr_name, writeLevel=5):
        return self.desc.add_attr(opt, attr_name)

    xmlrpc_add_attr = add_attr

    def del_attr(self, opt, attr_name, writeLevel=5):
        return self.desc.del_attr(opt, attr_name)

    xmplrpc_del_attr = del_attr

    def getFlags(self, opt):
        """Returns option flags for `opt`"""
        if self.controls.has_key(opt):
            out = {}
            pre = self.desc.getFlags(opt)
            for key, val in pre.iteritems():
                r = self.controls[opt].getFlag(key)
                print 'control getflag', key, r
                if r:
                    out[key] = val
                else:
                    out[key] = pre[key]
            self.desc.setFlags(opt, out)
        return self.desc.getFlags(opt)

    def file_list(self, opt, ext=''):
        """Update a FileList options attribute"""
        odir = self.desc.getConf_dir() + opt + '/'
        r = listDirExt(odir, ext, create=True)
        self.setattr(opt, 'options', r)
        return r

    def get(self, name, *opt):
        """Get routing.
        First searches for a get_`name` method to call,
        then for a special control, finally directly retrieve the value from memory"""
        # Check get_name existance
        if not self.desc.has_key(name):
            if len(opt) > 0:
                return opt[0]
            self.log.warning('No property: ', name)
            raise NoProperty('NoProperty: ' + name)
        # Call getter functions
        func = getattr(self, 'get_' + name, False)
        val = None
        if func:
            val = func()
            self.desc.set(name, val)
        # Call special controls
        elif self.controls.has_key(name):
            val = self.controls[name].get()
            #           print 'Getting control',name,val
            self.desc.set(name, val)
        # Get a SubDict
        if isinstance(val, dict):
            return SubDict(val, self, name)
        # If intercepted by any special function, return here
        # They should take care about managing special types (Dict, FileList,
        # RoleIO)
        if val is not None:
            return val
        prop = self.desc.gete(name)
        val = prop['current']
        typ = prop.get('type', '')
        # Manage Dict-type options
        if isinstance(prop, bool) or isinstance(prop, str):
            self.log.error('Wrong type for handle', name, type(prop),
                           repr(prop))
        if typ == 'Meta':
            val = SubDict(val, self, name)
        # Update file listings on get()
        elif typ == 'FileList':
            self.file_list(name)
        # Resolve RoleIO
        elif typ == 'RoleIO':
            val = self.get_role_io(name, val)
        return val

    def get_role_io(self, name, val=None):
        """Retrieve `name` RoleIO option from the referred option value"""
        obj = self.roledev.get(name, False)
        # Try to remap
        if not obj:
            obj = self.map_role_dev(name)
        if obj:
            obj, pre, io = obj
            if io and obj:
                val = obj[io.handle]
                self.desc.set(name, val)
        else:
            val = self.desc.get(name)
        return val

    def gete(self, opt, *a, **k):
        r = self.desc.gete(opt, *a, **k)
        # Refresh file listing
        if r.get('type', '') == 'FileList':
            self.file_list(opt)
            r = self.desc.gete(opt, *a, **k)
        return r

    @property
    def root_obj(self):
        """Dummy root obj"""
        return self

    def xmlrpc_get(self, name, readLevel=0):
        """Client frontend for the `get()` method.
        Security check with `readLevel`.
        Only read values from memory if no acquisition isRunning.
        Pickle or otherwise xmlrpc-sanitize values for network transmission"""
        r = self.desc.getattr(name, 'readLevel')
        if readLevel < r:
            self.log.critical('Not authorized get', name)
            raise ReadNotAuthorized('Option: %s Required: %i Level: %i' %
                                    (name, r, readLevel))
        p = self.desc.gete(name)
        if 'Hot' in p['attr']:
            if self.root_obj.get('isRunning'):
                r = self.desc.get(name)
            else:
                r = self.get(name)
        else:
            r = self.get(name)
        if p['type'] in ['Binary', 'Profile', 'Image']:
            return xmlrpc.Binary(dumps(r))
        if p['type'] == 'Meta':
            return r.copy()
        return csutil.xmlrpcSanitize(r)

    def multiget(self, opts, readLevel=0):
        """Performs get operation on a list of options, returning a {opt:val} mapping"""
        r = {}
        for opt in opts:
            r[opt] = self.xmlrpc_get(opt, readLevel=readLevel)
        return r

    xmlrpc_multiget = sanitize(multiget)

    @sanitize
    def xmlrpc_geth(self, name, readLevel=0):
        dn = self.desc.gete(name)
        rl = dn['readLevel']
        if rl > readLevel:
            self.log.critical('Not authorized geth', name)
            raise ReadNotAuthorized('Option: %s, Required: %i, Level: %i' %
                                    (name, rl, readLevel))
        attr = dn.get('attr', [])
        if 'History' in attr and getattr(self.desc, 'history', False):
            return self.desc.h_get_history(name)
        return 'No history for property: ' + name

    @sanitize
    def xmlrpc_set(self, name, val, kwopt={'writeLevel': 5}):
        writeLevel = kwopt['writeLevel']
        w = self.desc.getattr(name, 'writeLevel')
        if writeLevel < w:
            self.log.critical('Not authorized set', name)
            raise WriteNotAuthorized('Option: %s, Required: %i, Level: %i' %
                                     (name, w, writeLevel))
        return self.set(name, val, kwopt=kwopt)

    def setFlags(self, opt, flags):
        """Set flags for option `opt`"""
        if self.controls.has_key(opt):
            out = {}
            pre = self.desc.getFlags(opt)
            for key, val in flags.iteritems():
                r = self.controls[opt].setFlag(key, val)
                if r:
                    out[key] = val
                else:
                    out[key] = pre[key]
            flags = out
        return self.desc.setFlags(opt, flags)

    def map_role_dev(self, new=None):
        return True

    # FIXME: SET SHOULD RETURN NVAL, not (name,nval)!!!
    # Change client-side where needed
    def set(self, name, val, t=-1, kwopt={}):
        """Set routing.
        First searches for a set_`name` method to call.
        Then searches for a control `name`.
        Finally directly set the value on memory (self.desc).
        Returns the actual value set."""
        if not self.desc:
            print 'No desc interface object', self, self.desc
            return None
        if self.desc.getEmpty() and not self.desc.has_key(name):
            self.desc.set(name, val, t)
            return name, val
        dn = self.desc.gete(name)
        oval = self.desc.get(name)
        typ = dn['type']
        # Dict-like management
        if typ == 'Meta':
            # Obtain a pure-dict object which must be picklable
            val = val.copy()
        # Role management
        elif typ == 'Role':
            if isinstance(val, str):
                val = val.split(',')
                if len(val) == 1:
                    val.append('default')
            if not (isinstance(val, list) or isinstance(val, tuple)):
                # Convert object to role list: [fullpath,preset]
                val = [val['fullpath'], val['preset']]
        # Resolve RoleIO
        # FIXME: security breach: could write to a protected opt as access
        # levels are not checked here
        elif typ == 'RoleIO':
            obj = self.roledev.get(name, False)
            # Try to remap
            if not obj:
                obj = self.map_role_dev(name)
            if obj:
                obj, pre, io = obj
                if io:
                    obj[io.handle] = val
        ### HOOKS ###
        # Setter hook
        # Search for a setter function and call it
        func = getattr(self, 'set_' + name, False)
        if func and type(func) != types.MethodType:
            func = False
        # Controls hook
        # Search if a control object has been defined in the self.controls
        # dict.
        if (not func) and self.controls.has_key(name):
            func = self.controls[name].set
        # If a valid function was found, fill implicit arguments if present
        if func:
            r = fill_implicit_args(func, (val, ), kwopt)
            if not r:
                raise FunctionRoutingError()
            # Pass also filled kwargs to func
            val = func(val, **r[-1])
        ############
        if val == None:
            self.log.debug('Failed setting', name)
            return name, oval
        # SET IN MEMORY
        self.desc.set(name, val, t)
        # At the end, intercept Role mapping requests
        if typ == 'Role':
            r = self.map_role_dev(name, val)
            # Restoring old value
            if r is False:
                self.desc.set(name, oval)
        return name, val

    @sanitize
    def xmlrpc_gete(self, name, readLevel=0):
        r = self.desc.gete(name).entry.copy()
        if readLevel < r['readLevel']:
            self.log.critical('Not authorized gete', name)
            raise ReadNotAuthorized('Option: %s Required: %i Level: %i' %
                                    (name, r['readLevel'], readLevel))
        r['current'] = self.xmlrpc_get(name, readLevel=readLevel)
        return r

    def xmlrpc_sete(self, name, opt, writeLevel=0):
        if writeLevel < 4:
            self.log.critical('Not authorized sete', name)
            raise WriteNotAuthorized('Option: %s Required: %i Level: %i' %
                                     (name, 4, writeLevel))
        return self.sete(name, opt)

    def setConf_dir(self, cd):
        """Set the folder where the configuration should be saved."""
        self.desc.setConf_dir(cd)

    def getConf_dir(self):
        """Return the folder where the configuration should be saved."""
        return self.desc.getConf_dir()

    conf_dir = property(getConf_dir, setConf_dir)

    def setConf_obj(self, obj):
        """Set the output full path for current configuration."""
        self.desc.setConf_obj(obj)

    def getConf_obj(self):
        """Return the output full path for current configuration."""
        return self.desc.getConf_obj()

    conf_obj = property(getConf_obj, setConf_obj)

    @sanitize
    def echo(self, s='none', readLevel=0, writeLevel=0, userName=''):
        """Login demo function."""
        l = ['guest', 'analyst', 'user', 'tech', 'maint', 'admin']
        r = 'Welcome {}. \nYour role is: read={},{} / write={},{}.\nHere is your echo: {}'.format(
            userName, readLevel, l[readLevel], writeLevel, l[writeLevel], s)
        return r

    xmlrpc_echo = echo

    def check_read(self, opt, readLevel=0):
        """Check if option `opt` can be red by current user"""
        return self.getattr(opt, 'readLevel') <= readLevel

    xmlrpc_check_read = check_read

    def check_write(self, opt, writeLevel=0):
        """Check if option `opt` can be written by current user"""
        return self.getattr(opt, 'writeLevel') <= writeLevel

    xmlrpc_check_write = check_write
예제 #7
0
class BaseServer(device.Device):
    """Basic server object functions. Useful for testing purposes"""
    allowNone = True
    naturalName = 'server'
    restart = False
    scanningPorts = 0
    _Method__name = 'MAINSERVER'
    name = 'server'
    conf_def = deepcopy(device.Device.conf_def)
    conf_def += server_conf.conf

    def __str__(self):
        return 'BASESERVER ' + repr(self)

    def __init__(self,
                 manager=share.manager,
                 confdir=params.confdir,
                 datadir=params.datadir):
        self.manager = manager
        self._server = self
        self._root = self
        device.Device.__init__(self, parent=None, node='MAINSERVER')
        self.separator = '/'

        self.storage, self.beholder, self.balance, self.smaug, self.morla = [
            False
        ] * 5
        self.hsm, self.horizontal, self.vertical, self.flex, self.post, self.drop, self.kiln = [
            False
        ] * 7
        self.instruments = []
        self.deviceservers = []
        self.main_confdir = confdir
        self.main_datadir = datadir

    def pause_check(self):
        self.shutting_down = True

    def get_instruments(self):
        """Returns the list of available Instrument names"""
        lst = [(obj['comment'] or obj['name'], obj.naturalName)
               for obj in self.instruments]
        self.desc.set('instruments', lst)
        return lst

    def get_deviceservers(self):
        """Returns the list of available DeviceServer names"""
        lst = [obj['name'] for obj in self.deviceservers]
        self.desc.set('deviceservers', lst)
        return lst

    @property
    def runningInstrument(self):
        ins = self['runningInstrument']
        if ins in ['', 'None', None, False]:
            return False
        obj = self.child(ins)
        if obj is None:
            return False
        return obj

    @property
    def lastInstrument(self):
        """Configured instrument, ready for test start"""
        ins = self['lastInstrument']
        if ins in ['', 'None', None, False]:
            return False
        obj = self.child(ins)
        if obj is None:
            return False
        return obj

    def get_initTest(self):
        """Retrieve initialization status from active instrument"""
        obj = self.runningInstrument
        if obj is False:
            return False
        return obj['initTest']

    def get_closingTest(self):
        """Retrieve closing status from active instrument"""
        obj = self.runningInstrument
        if obj is False:
            return False
        return obj['closingTest']

    def get_progress(self):
        """Remove finished Progress before returning the list of active tasks."""
        p = list(set(self.desc.get('progress')))
        # Clean finished progresses
        for e0 in p[:]:
            e = e0.split('/')
            # Option name
            opt = e.pop(-1)
            # Retrive the pointed object
            obj = self.child(e)
            if not obj:
                self.log.error('Operation object no longer exists!', e0)
                p.remove(e0)
            # Operation ended
            if not obj[opt]:
                self.log.debug('Operation ended', e0)
                p.remove(e0)
        # List contains still running options
        return p

    def set_progress(self, kid):
        """Append kid to the list instead of substituting"""
        p = self.desc.get('progress')
        p.append(kid)
        return p

    def check(self):
        """Check for delayed start"""
        ins = self.lastInstrument  # there must be a defined running instrument
        test_in_progress = ins and (ins['running'] + ins['initTest'] +
                                    ins['closingTest'] + ins['initializing'])

        delay = self['delay']
        delayT = self['delayT']
        T = self.kiln['T']
        last_client_access_time = self['lastClientAccessTime']
        auto_shutdown_interval = self['autoShutdownInterval']

        client_inactive = (self.time() - last_client_access_time > auto_shutdown_interval) \
                        and auto_shutdown_interval >= 300 \
                        and last_client_access_time > 0 \
                        and not test_in_progress \
                        and not self['delayStart'] \
                        and not self.time_delta

        if client_inactive:
            self.log.debug('Client inactive: halting server.')
            self.support.get_halt()

        if not ins:
            self['delayStart'] = False
        elif self['delayStart'] and delay > 0:
            d = delay - self.time()
            if -120 < d < 0 or (T < delayT and delayT > 0):
                if test_in_progress == 0:
                    self.log.info('Delayed start:', self['lastInstrument'],
                                  self['delay'], self['delayT'])
                    ins.start_acquisition(userName=ins.measure['operator'])
                    self['delay'] = 0
                    self['delayT'] = -1
                    self['delayStart'] = False
                    return True
                else:
                    self.log.warning(
                        'Delayed start cannot be applied: {}, {}, {}, {}'.
                        format(ins['running'], ins['initTest'],
                               ins['closingTest'], ins['initializing']))
            elif d > 0:
                self.log.debug(
                    'Waiting for delayed start of {}. Remaining {}min. Target T: {}, current: {}'
                    .format(self['lastInstrument'], int(d / 60), delayT, T))
            else:
                self.log.error('Delayed start timed out.', d)
                self['delay'] = 0
                self['delayStart'] = False

        return device.Device.check(self)

    def set_delayStart(self, val, userName='******'):
        """Forbit if no instrument is configured or set operator name."""
        if not val:
            return False
        ins = self.lastInstrument
        if not ins:
            self.log.error(
                'Cannot set delayed start if no instrument is configured.')
            return False
        if ins is False:
            self.log.error('Unknown instrument for delayed start: {}'.format(
                repr(ins)))
            return False
        if self['isRunning'] + ins['running'] + ins['initTest'] + ins[
                'closingTest'] + ins['initializing'] != 0:
            self.log.error(
                'Cannot set delayed start. Instrument is already running/closing.'
            )
            return False
        if self['delay'] < self.time() + 10:
            self.log.error(
                'Delayed start require `delay` option to be set in the future.'
            )
            return False
        self.log.debug('set_delayStart', val, userName)
        ins.measure['operator'] = userName
        return True

    def stop_acquisition(self, save=True, writeLevel=1):
        ins = self['runningInstrument']
        obj = getattr(self, ins, False)
        if obj is False:
            if ins != '':
                self.log.error(
                    'Cannot stop acquisition for running instrument:', ins)
            return False
        if not obj['analysis']:
            self.log.warning('Acquisition is not running for instrument', ins)
            return False
        return obj.stop_acquisition(save=True, writeLevel=1)

    xmlrpc_stop_acquisition = stop_acquisition

    def time(self):
        """Returns the server's time"""
        return csutil.time()

    xmlrpc_time = time

    def mapdate(self, kid_times, readLevel=0):
        """Receives a list of KID names and times to check for updates.
        Replies with two lists. The first (idx) is the list of updated positional indexes referring to
        the relative position of the option in kid_times.
        The second (rep) contains new current values.
        Is time is positive, the value is red from memory (.desc.get()).
        If negative, reading is forced through a standard get() call."""
        idx = []
        rep = []

        for i, (k, t0) in enumerate(kid_times):
            obj, n = self.read_kid(k)
            if not obj:
                continue
            rl = obj.getattr(n, 'readLevel')
            if rl > readLevel:
                self.log.error('Permission denied for option:', n, rl,
                               readLevel)
                continue
            # Detect forced updates
            if t0 < 0:
                rep.append(obj.get(n))
                idx.append(i)
                continue
            nt = obj.h_time_at(n)
            if nt > t0:
                # Retrieve the memory value,
                # in order not to trigger on-get updates
                rep.append(obj.desc.get(n))
                idx.append(i)
        return [idx, rep]

    xmlrpc_mapdate = csutil.sanitize(mapdate)

    def shutdown(self, *a, **k):
        try:
            self.close()
            share.stop()
        except:
            print_exc()
        from twisted.internet import reactor
        reactor.stop()

    def get_eq_mac(self):
        all_mac = go("ifconfig | grep 'HW' | awk '{ print $5}'")
        return all_mac