From fdaefe7b62e9e61a4ad1d59baee37340d7d5c1ee Mon Sep 17 00:00:00 2001 From: Ross Smith Date: Wed, 22 May 2013 16:23:07 -0400 Subject: added feature to allow clients to declare their version to server --- setup.py | 3 +- src/lib/Component.py | 2 +- src/lib/__init__.py | 2 +- src/lib/version.py | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/sbin/bcfg2 | 19 +++++++++ 5 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 src/lib/version.py diff --git a/setup.py b/setup.py index 8fd385953..9dbd76a3c 100755 --- a/setup.py +++ b/setup.py @@ -8,6 +8,8 @@ import os import os.path import sys +execfile('src/lib/version.py') + # we only need m2crypto on < python2.6 need_m2crypto = False version = sys.version_info[:2] @@ -131,7 +133,6 @@ if need_m2crypto: setup(cmdclass=cmdclass, name="Bcfg2", - version="1.2.4", description="Bcfg2 Server", author="Narayan Desai", author_email="desai@mcs.anl.gov", diff --git a/src/lib/Component.py b/src/lib/Component.py index caea3eda9..d299fbfa9 100644 --- a/src/lib/Component.py +++ b/src/lib/Component.py @@ -215,7 +215,7 @@ class Component (object): method_func = self._resolve_exposed_method(method) except NoExposedMethod: self.logger.error("Unknown method %s" % (method)) - raise xmlrpclib.Fault(7, "Unknown method %s" % method) + raise xmlrpclib.Fault(xmlrpclib.METHOD_NOT_FOUND, "Unknown method %s" % method) except Exception: e = sys.exc_info()[1] if getattr(e, "log", True): diff --git a/src/lib/__init__.py b/src/lib/__init__.py index d36c0a00a..75027dfe3 100644 --- a/src/lib/__init__.py +++ b/src/lib/__init__.py @@ -1,4 +1,4 @@ """Base modules definition.""" __revision__ = '$Revision$' -__all__ = ['Server', 'Client', 'Component', 'Logger', 'Options', 'Proxy', 'Statistics'] +__all__ = ['Server', 'Client', 'Component', 'Logger', 'Options', 'Proxy', 'Statistics', 'version'] diff --git a/src/lib/version.py b/src/lib/version.py new file mode 100644 index 000000000..3f9501dda --- /dev/null +++ b/src/lib/version.py @@ -0,0 +1,115 @@ +import re + +__version__ = "1.2.4" + +class Bcfg2VersionInfo(tuple): + v_re = re.compile(r'(\d+)(\w+)(\d+)') + + def __new__(cls, vstr): + (major, minor, rest) = vstr.split(".") + match = cls.v_re.match(rest) + if match: + micro, releaselevel, serial = match.groups() + else: + micro = rest + releaselevel = 'final' + serial = 0 + return tuple.__new__(cls, [int(major), int(minor), int(micro), + releaselevel, int(serial)]) + + def __init__(self, vstr): + tuple.__init__(self) + self.major, self.minor, self.micro, self.releaselevel, self.serial = \ + tuple(self) + + def __repr__(self): + return "(major=%s, minor=%s, micro=%s, releaselevel=%s, serial=%s)" % \ + tuple(self) + + def _release_cmp(self, r1, r2): + if r1 == r2: + return 0 + elif r1 == "final": + return -1 + elif r2 == "final": + return 1 + elif r1 == "rc": + return -1 + elif r2 == "rc": + return 1 + # should never get to anything past this point + elif r1 == "pre": + return -1 + elif r2 == "pre": + return 1 + else: + # wtf? + return 0 + + def __gt__(self, version): + if version is None: + # older bcfg2 clients didn't report their version, so we + # handle this case specially and assume that any reported + # version is newer than any indeterminate version + return True + try: + for i in range(3): + if self[i] > version[i]: + return True + elif self[i] < version[i]: + return False + rel = self._release_cmp(self[3], version[3]) + if rel < 0: + return True + elif rel > 0: + return False + if self[4] > version[4]: + return True + else: + return False + except TypeError: + return self > Bcfg2VersionInfo(version) + + def __lt__(self, version): + if version is None: + # older bcfg2 clients didn't report their version, so we + # handle this case specially and assume that any reported + # version is newer than any indeterminate version + return False + try: + for i in range(3): + if self[i] < version[i]: + return True + elif self[i] > version[i]: + return False + rel = self._release_cmp(self[3], version[3]) + if rel > 0: + return True + elif rel < 0: + return False + if self[4] < version[4]: + return True + else: + return False + except TypeError: + return self < Bcfg2VersionInfo(version) + + def __eq__(self, version): + if version is None: + # older bcfg2 clients didn't report their version, so we + # handle this case specially and assume that any reported + # version is newer than any indeterminate version + return False + try: + rv = True + for i in range(len(self)): + rv &= self[i] == version[i] + return rv + except TypeError: + return self == Bcfg2VersionInfo(version) + + def __ge__(self, version): + return not self < version + + def __le__(self, version): + return not self > version diff --git a/src/sbin/bcfg2 b/src/sbin/bcfg2 index 1d1cc8424..e974f0ef9 100755 --- a/src/sbin/bcfg2 +++ b/src/sbin/bcfg2 @@ -18,6 +18,7 @@ import Bcfg2.Client.Frame import Bcfg2.Client.Tools # Compatibility imports from Bcfg2.Bcfg2Py3k import xmlrpclib +from Bcfg2.version import __version__ import Bcfg2.Proxy import Bcfg2.Logger @@ -195,6 +196,24 @@ class Client: self.logger.error(str(err)) raise SystemExit(1) + + try: + probe_data = proxy.DeclareVersion(__version__) + except xmlrpclib.Fault: + err = sys.exc_info()[1] + if (err.faultCode == xmlrpclib.METHOD_NOT_FOUND or + (err.faultCode == 7 and + err.faultString.startswith("Unknown method"))): + self.logger.debug("Server does not support declaring " + "client version") + else: + self.logger.error("Failed to declare version: %s" % err) + except (Bcfg2.Proxy.ProxyError, + Bcfg2.Proxy.CertificateError, + socket.gaierror, + socket.error): + err = sys.exc_info()[1] + self.logger.error("Failed to declare version: %s" % err) try: probe_data = proxy.GetProbes() except (Bcfg2.Proxy.ProxyError, -- cgit v1.2.3-1-g7c22