--- a/cwctl.py Tue Apr 10 17:07:03 2012 +0200
+++ b/cwctl.py Tue Apr 10 17:09:04 2012 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -38,6 +38,8 @@
from os.path import exists, join, isfile, isdir, dirname, abspath
+from urlparse import urlparse
+
from logilab.common.clcommands import CommandLine
from logilab.common.shellutils import ASK
@@ -867,31 +869,45 @@
'group': 'local'
}),
- ('pyro',
- {'short': 'P', 'action' : 'store_true',
- 'help': 'connect to a running instance through Pyro.',
- 'group': 'remote',
- }),
- ('pyro-ns-host',
- {'short': 'H', 'type' : 'string', 'metavar': '<host[:port]>',
- 'help': 'Pyro name server host. If not set, will be detected by '
- 'using a broadcast query.',
+ ('repo-uri',
+ {'short': 'H', 'type' : 'string', 'metavar': '<protocol>://<[host][:port]>',
+ 'help': 'URI of the CubicWeb repository to connect to. URI can be \
+pyro://[host:port] the Pyro name server host; if the pyro nameserver is not set, \
+it will be detected by using a broadcast query, a ZMQ URL or \
+inmemory:// (default) use an in-memory repository.',
'group': 'remote'
}),
)
def run(self, args):
appid = args.pop(0)
- if self.config.pyro:
+ if self.config.repo_uri:
+ uri = urlparse(self.config.repo_uri)
+ if uri.scheme == 'pyro':
+ cnxtype = uri.scheme
+ hostport = uri.netloc
+ elif uri.scheme == 'inmemory':
+ cnxtype = ''
+ hostport = ''
+ else:
+ cnxtype = 'zmq'
+ hostport = self.config.repo_uri
+ else:
+ cnxtype = ''
+
+ if cnxtype:
from cubicweb import AuthenticationError
- from cubicweb.dbapi import connect
+ from cubicweb.dbapi import connect, ConnectionProperties
from cubicweb.server.utils import manager_userpasswd
from cubicweb.server.migractions import ServerMigrationHelper
+ cnxprops = ConnectionProperties(cnxtype=cnxtype)
+
while True:
try:
login, pwd = manager_userpasswd(msg=None)
cnx = connect(appid, login=login, password=pwd,
- host=self.config.pyro_ns_host, mulcnx=False)
+ host=hostport, mulcnx=False,
+ cnxprops=cnxprops)
except AuthenticationError, ex:
print ex
except (KeyboardInterrupt, EOFError):
@@ -927,7 +943,7 @@
else:
mih.interactive_shell()
finally:
- if not self.config.pyro:
+ if not cnxtype: # shutdown in-memory repo
mih.shutdown()
else:
cnx.close()
--- a/dbapi.py Tue Apr 10 17:07:03 2012 +0200
+++ b/dbapi.py Tue Apr 10 17:09:04 2012 +0200
@@ -93,7 +93,7 @@
Only 'in-memory' and 'pyro' are supported for now. Either vreg or config
argument should be given
"""
- assert method in ('pyro', 'inmemory')
+ assert method in ('pyro', 'inmemory', 'zmq')
assert vreg or config
if vreg and not config:
config = vreg.config
@@ -102,7 +102,9 @@
from cubicweb.server.repository import Repository
from cubicweb.server.utils import TasksManager
return Repository(config, TasksManager(), vreg=vreg)
-
+ elif method == 'zmq':
+ from cubicweb.zmqclient import ZMQRepositoryClient
+ return ZMQRepositoryClient(config, vreg=vreg)
else: # method == 'pyro'
# resolve the Pyro object
from logilab.common.pyro_ext import ns_get_proxy, get_proxy
@@ -147,8 +149,8 @@
the user login to use to authenticate.
:host:
- the pyro nameserver host. Will be detected using broadcast query if
- unspecified.
+ - pyro: nameserver host. Will be detected using broadcast query if unspecified
+ - zmq: repository host socket address
:group:
the instance's pyro nameserver group. You don't have to specify it unless
@@ -185,6 +187,8 @@
config.global_set_option('pyro-ns-host', host)
if group:
config.global_set_option('pyro-ns-group', group)
+ elif method == 'zmq':
+ config = cwconfig.CubicWebNoAppConfiguration()
else:
assert database
config = cwconfig.instance_configuration(database)
--- a/misc/migration/3.15.0_common.py Tue Apr 10 17:07:03 2012 +0200
+++ b/misc/migration/3.15.0_common.py Tue Apr 10 17:09:04 2012 +0200
@@ -1,2 +1,5 @@
undo_actions = config.cfgfile_parser.get('MAIN', 'undo-support', False)
config.global_set_option('undo-enabled', bool(undo_actions))
+pyro_actions = config.cfgfile_parser.get('REMOTE', 'pyro', False)
+if pyro_actions:
+ config.global_set_option('repo-uri', 'pyro://')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/zmqclient.py Tue Apr 10 17:09:04 2012 +0200
@@ -0,0 +1,61 @@
+# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+"""Source to query another RQL repository using pyro"""
+
+__docformat__ = "restructuredtext en"
+_ = unicode
+
+from functools import partial
+import zmq
+
+
+# XXX hack to overpass old zmq limitation that force to have
+# only one context per python process
+try:
+ from cubicweb.server.cwzmq import ctx
+except ImportError:
+ ctx = zmq.Context()
+
+class ZMQRepositoryClient(object):
+ """
+ This class delegate the overall repository stuff to a remote source.
+
+ So calling a method of this repository will results on calling the
+ corresponding method of the remote source repository.
+
+ Any raised exception on the remote source is propagated locally.
+
+ ZMQ is used as the transport layer and cPickle is used to serialize data.
+ """
+
+ def __init__(self, config, vreg=None):
+ self.config = config
+ self.vreg = vreg
+ self.socket = ctx.socket(zmq.REQ)
+ self.host = config.get('base-url')
+ self.socket.connect(self.host)
+
+ def __zmqcall__(self, name, *args, **kwargs):
+ self.socket.send_pyobj([name, args, kwargs])
+ result = self.socket.recv_pyobj()
+ if isinstance(result, BaseException):
+ raise result
+ return result
+
+ def __getattr__(self, name):
+ return partial(self.__zmqcall__, name)