From 252df8e0c14722ce5cca8e02d72b9b62f5ff70dd Mon Sep 17 00:00:00 2001 From: cfalcon Date: Mon, 1 Jul 2019 14:22:58 +0200 Subject: [PATCH 1/3] Add test for TANGO_HOST multi db server --- lib/taurus/core/tango/test/test_tangovalidator.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/taurus/core/tango/test/test_tangovalidator.py b/lib/taurus/core/tango/test/test_tangovalidator.py index 5eb677c96..3afe16a1e 100644 --- a/lib/taurus/core/tango/test/test_tangovalidator.py +++ b/lib/taurus/core/tango/test/test_tangovalidator.py @@ -48,8 +48,13 @@ # Tests for Tango Authority name validation #========================================================================= @valid(name='tango://foo:10000') +@valid(name='tango://foo:10000,foo:20000') +@valid(name='tango://.dynamic_auth.') @invalid(name='tango:foo') +@invalid(name='tango:foo,') @invalid(name='tango:foo:10000') +@invalid(name='tango://foo:10000,') +@invalid(name='tango://foo:10000,bar') @invalid(name='tango://foo:10000/') @invalid(name='tango://foo:10000/?') @invalid(name='tango://foo:bar') From a1e97cb3d03cd3f7c29c08094d66f1c90b2e57f4 Mon Sep 17 00:00:00 2001 From: cfalcon Date: Mon, 1 Jul 2019 14:23:16 +0200 Subject: [PATCH 2/3] Support TANGO_HOST multi db server TangoValidators do not support URIs with multiples db. A Tango system can be configured with two running Tango databases. The TANGO_HOST environment variable for that cases is set to host:port1,host:port2... Support Tango multi db URIs using a reserved work `.dynamic_auth.` to indicate taurus that the authority is to be resolved dynamically by PyTango. Fix #929 --- lib/taurus/core/tango/tangodatabase.py | 21 ++++++++++--- lib/taurus/core/tango/tangodevice.py | 8 ++++- lib/taurus/core/tango/tangofactory.py | 3 +- lib/taurus/core/tango/tangovalidator.py | 39 +++++++++++++++---------- 4 files changed, 49 insertions(+), 22 deletions(-) diff --git a/lib/taurus/core/tango/tangodatabase.py b/lib/taurus/core/tango/tangodatabase.py index cb138566e..c1b18414b 100644 --- a/lib/taurus/core/tango/tangodatabase.py +++ b/lib/taurus/core/tango/tangodatabase.py @@ -43,6 +43,7 @@ from taurus.core.taurusauthority import TaurusAuthority from taurus.core.util.containers import CaselessDict from taurus.core.util.log import taurus4_deprecation +from taurus.core.tango.tangovalidator import TangoAuthorityNameValidator __all__ = ["TangoInfo", "TangoAttrInfo", "TangoDevInfo", "TangoServInfo", @@ -673,19 +674,31 @@ def __init__(self, host=None, port=None, parent=None): if host is None or port is None: try: _hp = TangoAuthority.get_default_tango_host() - host, port = _hp.rsplit(':', 1) + v = TangoAuthorityNameValidator() + g = v.getUriGroups('tango://{}'.format(_hp)) + host = g.get('host', None) + port = g.get('port', None) + if host is None: + complete_name = "tango://.dynamic_auth." + else: + host, port = _hp.rsplit(':', 1) except Exception: from taurus import warning warning("Error getting default Tango host") # Set host to fqdn - host = socket.getfqdn(host) + if host is not None: + host = socket.getfqdn(host) + db = Database(host, port) + complete_name = "tango://%s:%s" % (host, port) + else: + db = Database() - self.dbObj = Database(host, port) + self.dbObj = db self._dbProxy = None self._dbCache = None - complete_name = "tango://%s:%s" % (host, port) + self.call__init__(TaurusAuthority, complete_name, parent) try: diff --git a/lib/taurus/core/tango/tangodevice.py b/lib/taurus/core/tango/tangodevice.py index 60e979c85..774fa319c 100644 --- a/lib/taurus/core/tango/tangodevice.py +++ b/lib/taurus/core/tango/tangodevice.py @@ -34,6 +34,7 @@ from taurus.core.taurusbasetypes import (TaurusDevState, TaurusLockInfo, LockStatus, TaurusEventType) from taurus.core.util.log import taurus4_deprecation +from taurus.core.tango.tangovalidator import TangoDeviceNameValidator __all__ = ["TangoDevice"] @@ -206,7 +207,12 @@ def getDisplayValue(self, cache=True): def _createHWObject(self): try: - return DeviceProxy(self.getFullName()) + v = TangoDeviceNameValidator() + g = v.getUriGroups(self.getFullName()) + if g['authority'] != '//.dynamic_auth.': + return DeviceProxy(self.getFullName()) + else: + return DeviceProxy(self.getSimpleName()) except DevFailed as e: self.warning('Could not create HW object: %s' % (e.args[0].desc)) self.traceback() diff --git a/lib/taurus/core/tango/tangofactory.py b/lib/taurus/core/tango/tangofactory.py index 755e915ab..c9cc500cd 100644 --- a/lib/taurus/core/tango/tangofactory.py +++ b/lib/taurus/core/tango/tangofactory.py @@ -276,7 +276,8 @@ def getAuthority(self, name=None): if name is None: if self.dft_db is None: try: - if self._default_tango_host is None: + if (self._default_tango_host is None + or self._default_tango_host == '.dynamic_auth.'): self.dft_db = _Authority() else: name = self._default_tango_host diff --git a/lib/taurus/core/tango/tangovalidator.py b/lib/taurus/core/tango/tangovalidator.py index 81d2eaece..b07f6b591 100644 --- a/lib/taurus/core/tango/tangovalidator.py +++ b/lib/taurus/core/tango/tangovalidator.py @@ -52,7 +52,10 @@ class TangoAuthorityNameValidator(TaurusAuthorityNameValidator): ''' scheme = 'tango' - authority = '//(?P([\w\-_]+\.)*[\w\-_]+):(?P\d{1,5})' + authority = '//((?P([\w\-_]+\.)*[\w\-_]+):(?P\d{1,5})' \ + '|.dynamic_auth.' \ + '|([\w\-_]+\.)*[\w\-_]+:\d{1,5}' \ + '(,([\w\-_]+\.)*[\w\-_]+:\d{1,5})+)' path = '(?!)' query = '(?!)' fragment = '(?!)' @@ -62,10 +65,10 @@ def getUriGroups(self, name, strict=None): name using fully qualified domain name for the host. ''' ret = TaurusAuthorityNameValidator.getUriGroups(self, name, strict) - if ret is not None: - fqdn = socket.getfqdn(ret["host"]) - ret["host"] = fqdn - ret["authority"] = "//{host}:{port}".format(**ret) + if ret is not None and ret.get("host", None) is not None: + fqdn = socket.getfqdn(ret["host"]) + ret["host"] = fqdn + ret["authority"] = "//{host}:{port}".format(**ret) return ret @@ -97,9 +100,9 @@ def getUriGroups(self, name, strict=None): ''' ret = TaurusDeviceNameValidator.getUriGroups(self, name, strict) if ret is not None and ret.get("host", None) is not None: - fqdn = socket.getfqdn(ret["host"]) - ret["host"] = fqdn - ret["authority"] = "//{host}:{port}".format(**ret) + fqdn = socket.getfqdn(ret["host"]) + ret["host"] = fqdn + ret["authority"] = "//{host}:{port}".format(**ret) return ret def getNames(self, fullname, factory=None, queryAuth=True): @@ -120,10 +123,10 @@ def getNames(self, fullname, factory=None, queryAuth=True): if default_authority is None: import PyTango - host, port = PyTango.ApiUtil.get_env_var('TANGO_HOST').split(":") - # Get the fully qualified domain name - host = socket.getfqdn(host) - default_authority = "//{0}:{1}".format(host, port) + tango_host = PyTango.ApiUtil.get_env_var('TANGO_HOST') + v = TangoAuthorityNameValidator() + g = v.getUriGroups('tango://{}'.format(tango_host)) + default_authority = g.get('authority') authority = groups.get('authority') if authority is None: @@ -221,10 +224,14 @@ def getUriGroups(self, name, strict=None): name using fully qualified domain name for the host. ''' ret = TaurusAttributeNameValidator.getUriGroups(self, name, strict) - if ret is not None and ret.get("host", None) is not None: - fqdn = socket.getfqdn(ret["host"]) - ret["host"] = fqdn - ret["authority"] = "//{host}:{port}".format(**ret) + if ret is not None: + if ret.get("host", None) is not None: + fqdn = socket.getfqdn(ret["host"]) + ret["host"] = fqdn + auth = "//{host}:{port}".format(**ret) + else: + auth = "//.dynamic_auth." + ret["authority"] = auth return ret def getNames(self, fullname, factory=None, queryAuth=True, fragment=False): From eb46bbbe14a495795009c6e6d48aef987f3adcb8 Mon Sep 17 00:00:00 2001 From: cfalcon Date: Mon, 1 Jul 2019 16:33:54 +0200 Subject: [PATCH 3/3] Fix overindented and avoid implicit concatenation --- lib/taurus/core/tango/tangovalidator.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/taurus/core/tango/tangovalidator.py b/lib/taurus/core/tango/tangovalidator.py index b07f6b591..79fea6d5e 100644 --- a/lib/taurus/core/tango/tangovalidator.py +++ b/lib/taurus/core/tango/tangovalidator.py @@ -52,10 +52,10 @@ class TangoAuthorityNameValidator(TaurusAuthorityNameValidator): ''' scheme = 'tango' - authority = '//((?P([\w\-_]+\.)*[\w\-_]+):(?P\d{1,5})' \ - '|.dynamic_auth.' \ - '|([\w\-_]+\.)*[\w\-_]+:\d{1,5}' \ - '(,([\w\-_]+\.)*[\w\-_]+:\d{1,5})+)' + authority = ('//((?P([\w\-_]+\.)*[\w\-_]+):(?P\d{1,5})' + + '|.dynamic_auth.' + + '|([\w\-_]+\.)*[\w\-_]+:\d{1,5}' + + '(,([\w\-_]+\.)*[\w\-_]+:\d{1,5})+)') path = '(?!)' query = '(?!)' fragment = '(?!)' @@ -66,9 +66,9 @@ def getUriGroups(self, name, strict=None): ''' ret = TaurusAuthorityNameValidator.getUriGroups(self, name, strict) if ret is not None and ret.get("host", None) is not None: - fqdn = socket.getfqdn(ret["host"]) - ret["host"] = fqdn - ret["authority"] = "//{host}:{port}".format(**ret) + fqdn = socket.getfqdn(ret["host"]) + ret["host"] = fqdn + ret["authority"] = "//{host}:{port}".format(**ret) return ret @@ -100,9 +100,9 @@ def getUriGroups(self, name, strict=None): ''' ret = TaurusDeviceNameValidator.getUriGroups(self, name, strict) if ret is not None and ret.get("host", None) is not None: - fqdn = socket.getfqdn(ret["host"]) - ret["host"] = fqdn - ret["authority"] = "//{host}:{port}".format(**ret) + fqdn = socket.getfqdn(ret["host"]) + ret["host"] = fqdn + ret["authority"] = "//{host}:{port}".format(**ret) return ret def getNames(self, fullname, factory=None, queryAuth=True):