mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Further migration toward new xmlrcp code; fixed problem with unicode Fault.faultString; fixed problem where ServerProxy method was not called correctly
This commit is contained in:
committed by
Rob Crittenden
parent
9f48612a56
commit
24b6cb89d4
@@ -455,7 +455,7 @@ class NameSpace(ReadOnly):
|
|||||||
|
|
||||||
:param key: The name or index of a member, or a slice object.
|
:param key: The name or index of a member, or a slice object.
|
||||||
"""
|
"""
|
||||||
if type(key) is str:
|
if isinstance(key, basestring):
|
||||||
return self.__map[key]
|
return self.__map[key]
|
||||||
if type(key) in (int, slice):
|
if type(key) in (int, slice):
|
||||||
return self.__members[key]
|
return self.__members[key]
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import struct
|
|||||||
import frontend
|
import frontend
|
||||||
import backend
|
import backend
|
||||||
import errors
|
import errors
|
||||||
|
import errors2
|
||||||
import plugable
|
import plugable
|
||||||
import util
|
import util
|
||||||
from constants import CLI_TAB
|
from constants import CLI_TAB
|
||||||
@@ -534,9 +535,9 @@ class CLI(object):
|
|||||||
print ''
|
print ''
|
||||||
self.api.log.info('operation aborted')
|
self.api.log.info('operation aborted')
|
||||||
sys.exit()
|
sys.exit()
|
||||||
except errors.IPAError, e:
|
except errors2.PublicError, e:
|
||||||
self.api.log.error(unicode(e))
|
self.api.log.error(e.strerror)
|
||||||
sys.exit(e.faultCode)
|
sys.exit(e.errno)
|
||||||
|
|
||||||
def run_real(self):
|
def run_real(self):
|
||||||
"""
|
"""
|
||||||
@@ -620,6 +621,8 @@ class CLI(object):
|
|||||||
(c.name.replace('_', '-'), c) for c in self.api.Command()
|
(c.name.replace('_', '-'), c) for c in self.api.Command()
|
||||||
)
|
)
|
||||||
self.textui = self.api.Backend.textui
|
self.textui = self.api.Backend.textui
|
||||||
|
if self.api.env.in_server is False and 'xmlclient' in self.api.Backend:
|
||||||
|
self.api.Backend.xmlclient.connect()
|
||||||
|
|
||||||
def load_plugins(self):
|
def load_plugins(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -96,14 +96,14 @@ class Command(plugable.Plugin):
|
|||||||
If not in a server context, the call will be forwarded over
|
If not in a server context, the call will be forwarded over
|
||||||
XML-RPC and the executed an the nearest IPA server.
|
XML-RPC and the executed an the nearest IPA server.
|
||||||
"""
|
"""
|
||||||
self.debug(make_repr(self.name, *args, **options))
|
|
||||||
params = self.args_options_2_params(*args, **options)
|
params = self.args_options_2_params(*args, **options)
|
||||||
params = self.normalize(**params)
|
params = self.normalize(**params)
|
||||||
params = self.convert(**params)
|
params = self.convert(**params)
|
||||||
params.update(self.get_default(**params))
|
params.update(self.get_default(**params))
|
||||||
self.validate(**params)
|
self.validate(**params)
|
||||||
(args, options) = self.params_2_args_options(**params)
|
(args, options) = self.params_2_args_options(**params)
|
||||||
self.debug(make_repr(self.name, *args, **options))
|
# FIXME: don't log passords!
|
||||||
|
self.info(make_repr(self.name, *args, **options))
|
||||||
result = self.run(*args, **options)
|
result = self.run(*args, **options)
|
||||||
self.debug('%s result: %r', self.name, result)
|
self.debug('%s result: %r', self.name, result)
|
||||||
return result
|
return result
|
||||||
@@ -200,6 +200,11 @@ class Command(plugable.Plugin):
|
|||||||
(k, self.params[k].convert(v)) for (k, v) in kw.iteritems()
|
(k, self.params[k].convert(v)) for (k, v) in kw.iteritems()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def __convert_iter(self, kw):
|
||||||
|
for param in self.params():
|
||||||
|
if kw.get(param.name, None) is None:
|
||||||
|
continue
|
||||||
|
|
||||||
def get_default(self, **kw):
|
def get_default(self, **kw):
|
||||||
"""
|
"""
|
||||||
Return a dictionary of defaults for all missing required values.
|
Return a dictionary of defaults for all missing required values.
|
||||||
@@ -245,7 +250,7 @@ class Command(plugable.Plugin):
|
|||||||
elif param.required:
|
elif param.required:
|
||||||
raise errors.RequirementError(param.name)
|
raise errors.RequirementError(param.name)
|
||||||
|
|
||||||
def run(self, *args, **kw):
|
def run(self, *args, **options):
|
||||||
"""
|
"""
|
||||||
Dispatch to `Command.execute` or `Command.forward`.
|
Dispatch to `Command.execute` or `Command.forward`.
|
||||||
|
|
||||||
@@ -258,11 +263,8 @@ class Command(plugable.Plugin):
|
|||||||
performs is executed remotely.
|
performs is executed remotely.
|
||||||
"""
|
"""
|
||||||
if self.api.env.in_server:
|
if self.api.env.in_server:
|
||||||
target = self.execute
|
return self.execute(*args, **options)
|
||||||
else:
|
return self.forward(*args, **options)
|
||||||
target = self.forward
|
|
||||||
object.__setattr__(self, 'run', target)
|
|
||||||
return target(*args, **kw)
|
|
||||||
|
|
||||||
def execute(self, *args, **kw):
|
def execute(self, *args, **kw):
|
||||||
"""
|
"""
|
||||||
@@ -283,7 +285,7 @@ class Command(plugable.Plugin):
|
|||||||
"""
|
"""
|
||||||
Forward call over XML-RPC to this same command on server.
|
Forward call over XML-RPC to this same command on server.
|
||||||
"""
|
"""
|
||||||
return self.Backend.xmlrpc.forward_call(self.name, *args, **kw)
|
return self.Backend.xmlclient.forward(self.name, *args, **kw)
|
||||||
|
|
||||||
def finalize(self):
|
def finalize(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ Misc frontend plugins.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
from ipalib import api, LocalOrRemote
|
from ipalib import api, LocalOrRemote, Bytes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -135,8 +135,13 @@ def xml_dumps(params, methodname=None, methodresponse=False, encoding='UTF-8'):
|
|||||||
allow_none=True,
|
allow_none=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def decode_fault(e, encoding='UTF-8'):
|
||||||
|
assert isinstance(e, Fault)
|
||||||
|
if type(e.faultString) is str:
|
||||||
|
return Fault(e.faultCode, e.faultString.decode(encoding))
|
||||||
|
return e
|
||||||
|
|
||||||
def xml_loads(data):
|
def xml_loads(data, encoding='UTF-8'):
|
||||||
"""
|
"""
|
||||||
Decode the XML-RPC packet in ``data``, transparently unwrapping its params.
|
Decode the XML-RPC packet in ``data``, transparently unwrapping its params.
|
||||||
|
|
||||||
@@ -159,8 +164,11 @@ def xml_loads(data):
|
|||||||
|
|
||||||
:param data: The XML-RPC packet to decode.
|
:param data: The XML-RPC packet to decode.
|
||||||
"""
|
"""
|
||||||
(params, method) = loads(data)
|
try:
|
||||||
return (xml_unwrap(params), method)
|
(params, method) = loads(data)
|
||||||
|
return (xml_unwrap(params), method)
|
||||||
|
except Fault, e:
|
||||||
|
raise decode_fault(e)
|
||||||
|
|
||||||
|
|
||||||
class KerbTransport(SafeTransport):
|
class KerbTransport(SafeTransport):
|
||||||
@@ -211,8 +219,8 @@ class xmlclient(Backend):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
conn = ServerProxy(self.env.xmlrpc_uri,
|
conn = ServerProxy(self.env.xmlrpc_uri,
|
||||||
transport=KerbTransport(),
|
|
||||||
allow_none=True,
|
allow_none=True,
|
||||||
|
encoding='UTF-8',
|
||||||
)
|
)
|
||||||
setattr(context, self.connection_name, conn)
|
setattr(context, self.connection_name, conn)
|
||||||
|
|
||||||
@@ -243,9 +251,10 @@ class xmlclient(Backend):
|
|||||||
command = getattr(context.xmlconn, name)
|
command = getattr(context.xmlconn, name)
|
||||||
params = args + (kw,)
|
params = args + (kw,)
|
||||||
try:
|
try:
|
||||||
response = command(xml_wrap(params))
|
response = command(*xml_wrap(params))
|
||||||
return xml_unwrap(response)
|
return xml_unwrap(response)
|
||||||
except Fault, e:
|
except Fault, e:
|
||||||
|
e = decode_fault(e)
|
||||||
self.debug('Caught fault %d from server %s: %s', e.faultCode,
|
self.debug('Caught fault %d from server %s: %s', e.faultCode,
|
||||||
self.env.xmlrpc_uri, e.faultString)
|
self.env.xmlrpc_uri, e.faultString)
|
||||||
if e.faultCode in self.__errors:
|
if e.faultCode in self.__errors:
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ from xmlrpclib import Fault
|
|||||||
from ipalib import Backend
|
from ipalib import Backend
|
||||||
from ipalib.errors2 import PublicError, InternalError, CommandError
|
from ipalib.errors2 import PublicError, InternalError, CommandError
|
||||||
from ipalib.rpc import xml_dumps, xml_loads
|
from ipalib.rpc import xml_dumps, xml_loads
|
||||||
|
from ipalib.util import make_repr
|
||||||
|
|
||||||
|
|
||||||
def params_2_args_options(params):
|
def params_2_args_options(params):
|
||||||
@@ -47,21 +48,26 @@ class xmlserver(Backend):
|
|||||||
self.debug('Received RPC call to %r', method)
|
self.debug('Received RPC call to %r', method)
|
||||||
if method not in self.Command:
|
if method not in self.Command:
|
||||||
raise CommandError(name=method)
|
raise CommandError(name=method)
|
||||||
|
self.info('params = %r', params)
|
||||||
(args, options) = params_2_args_options(params)
|
(args, options) = params_2_args_options(params)
|
||||||
|
self.info('args = %r', args)
|
||||||
|
self.info('options = %r', options)
|
||||||
|
self.debug(make_repr(method, *args, **options))
|
||||||
result = self.Command[method](*args, **options)
|
result = self.Command[method](*args, **options)
|
||||||
return (result,) # Must wrap XML-RPC response in a tuple singleton
|
return (result,) # Must wrap XML-RPC response in a tuple singleton
|
||||||
|
|
||||||
def execute(self, data, ccache=None, client_version=None,
|
def execute(self, data):
|
||||||
client_ip=None, languages=None):
|
|
||||||
"""
|
"""
|
||||||
Execute the XML-RPC request in contained in ``data``.
|
Execute the XML-RPC request in contained in ``data``.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
(params, method) = xml_loads(data)
|
(params, method) = xml_loads(data)
|
||||||
response = self.dispatch(method, params)
|
response = self.dispatch(method, params)
|
||||||
|
print 'okay'
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
if not isinstance(e, PublicError):
|
if not isinstance(e, PublicError):
|
||||||
e = InternalError()
|
e = InternalError()
|
||||||
assert isinstance(e, PublicError)
|
assert isinstance(e, PublicError)
|
||||||
|
self.debug('Returning %r exception', e.__class__.__name__)
|
||||||
response = Fault(e.errno, e.strerror)
|
response = Fault(e.errno, e.strerror)
|
||||||
return dumps(response)
|
return xml_dumps(response, methodresponse=True)
|
||||||
|
|||||||
54
lite-xmlrpc2.py
Executable file
54
lite-xmlrpc2.py
Executable file
@@ -0,0 +1,54 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# Authors:
|
||||||
|
# Jason Gerard DeRose <jderose@redhat.com>
|
||||||
|
#
|
||||||
|
# Copyright (C) 2008 Red Hat
|
||||||
|
# see file 'COPYING' for use and warranty information
|
||||||
|
#
|
||||||
|
# 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; version 2 only
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
|
||||||
|
"""
|
||||||
|
In-tree XML-RPC server using SimpleXMLRPCServer.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
|
||||||
|
from ipalib import api
|
||||||
|
|
||||||
|
api.bootstrap_with_global_options(context='server')
|
||||||
|
api.finalize()
|
||||||
|
|
||||||
|
|
||||||
|
class Instance(object):
|
||||||
|
def _listMethods(self):
|
||||||
|
return list(api.Command)
|
||||||
|
|
||||||
|
|
||||||
|
class Server(SimpleXMLRPCServer):
|
||||||
|
def _marshaled_dispatch(self, data, dispatch_method=None):
|
||||||
|
return api.Backend.xmlserver.execute(data)
|
||||||
|
|
||||||
|
|
||||||
|
address = ('', api.env.lite_xmlrpc_port)
|
||||||
|
server = Server(address,
|
||||||
|
logRequests=False,
|
||||||
|
allow_none=True,
|
||||||
|
encoding='UTF-8',
|
||||||
|
)
|
||||||
|
server.register_introspection_functions()
|
||||||
|
server.register_instance(Instance())
|
||||||
|
try:
|
||||||
|
server.serve_forever()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
api.log.info('Server stopped')
|
||||||
@@ -378,7 +378,6 @@ class test_Command(ClassChecker):
|
|||||||
o.set_api(api)
|
o.set_api(api)
|
||||||
assert o.run.im_func is self.cls.run.im_func
|
assert o.run.im_func is self.cls.run.im_func
|
||||||
assert ('execute', args, kw) == o.run(*args, **kw)
|
assert ('execute', args, kw) == o.run(*args, **kw)
|
||||||
assert o.run.im_func is my_cmd.execute.im_func
|
|
||||||
|
|
||||||
# Test in non-server context
|
# Test in non-server context
|
||||||
(api, home) = create_test_api(in_server=False)
|
(api, home) = create_test_api(in_server=False)
|
||||||
@@ -387,7 +386,6 @@ class test_Command(ClassChecker):
|
|||||||
o.set_api(api)
|
o.set_api(api)
|
||||||
assert o.run.im_func is self.cls.run.im_func
|
assert o.run.im_func is self.cls.run.im_func
|
||||||
assert ('forward', args, kw) == o.run(*args, **kw)
|
assert ('forward', args, kw) == o.run(*args, **kw)
|
||||||
assert o.run.im_func is my_cmd.forward.im_func
|
|
||||||
|
|
||||||
|
|
||||||
class test_LocalOrRemote(ClassChecker):
|
class test_LocalOrRemote(ClassChecker):
|
||||||
|
|||||||
@@ -335,6 +335,7 @@ class test_Param(ClassChecker):
|
|||||||
o = Subclass('my_param')
|
o = Subclass('my_param')
|
||||||
for value in NULLS:
|
for value in NULLS:
|
||||||
assert o.convert(value) is None
|
assert o.convert(value) is None
|
||||||
|
assert o.convert(None) is None
|
||||||
for value in okay:
|
for value in okay:
|
||||||
assert o.convert(value) is value
|
assert o.convert(value) is value
|
||||||
|
|
||||||
@@ -821,6 +822,7 @@ class test_Str(ClassChecker):
|
|||||||
assert e.name == 'my_str'
|
assert e.name == 'my_str'
|
||||||
assert e.index == 18
|
assert e.index == 18
|
||||||
assert_equal(e.error, u'must be Unicode text')
|
assert_equal(e.error, u'must be Unicode text')
|
||||||
|
assert o.convert(None) is None
|
||||||
|
|
||||||
def test_rule_minlength(self):
|
def test_rule_minlength(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -171,11 +171,13 @@ def test_xml_loads():
|
|||||||
assert_equal(tup[0], params)
|
assert_equal(tup[0], params)
|
||||||
|
|
||||||
# Test un-serializing an RPC response containing a Fault:
|
# Test un-serializing an RPC response containing a Fault:
|
||||||
fault = Fault(69, unicode_str)
|
for error in (unicode_str, u'hello'):
|
||||||
data = dumps(fault, methodresponse=True, allow_none=True)
|
fault = Fault(69, error)
|
||||||
e = raises(Fault, f, data)
|
data = dumps(fault, methodresponse=True, allow_none=True, encoding='UTF-8')
|
||||||
assert e.faultCode == 69
|
e = raises(Fault, f, data)
|
||||||
assert_equal(e.faultString, unicode_str)
|
assert e.faultCode == 69
|
||||||
|
assert_equal(e.faultString, error)
|
||||||
|
assert type(e.faultString) is unicode
|
||||||
|
|
||||||
|
|
||||||
class test_xmlclient(PluginTester):
|
class test_xmlclient(PluginTester):
|
||||||
@@ -227,19 +229,19 @@ class test_xmlclient(PluginTester):
|
|||||||
context.xmlconn = DummyClass(
|
context.xmlconn = DummyClass(
|
||||||
(
|
(
|
||||||
'user_add',
|
'user_add',
|
||||||
(rpc.xml_wrap(params),),
|
rpc.xml_wrap(params),
|
||||||
{},
|
{},
|
||||||
rpc.xml_wrap(result),
|
rpc.xml_wrap(result),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
'user_add',
|
'user_add',
|
||||||
(rpc.xml_wrap(params),),
|
rpc.xml_wrap(params),
|
||||||
{},
|
{},
|
||||||
Fault(3007, u"'four' is required"), # RequirementError
|
Fault(3007, u"'four' is required"), # RequirementError
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
'user_add',
|
'user_add',
|
||||||
(rpc.xml_wrap(params),),
|
rpc.xml_wrap(params),
|
||||||
{},
|
{},
|
||||||
Fault(700, u'no such error'), # There is no error 700
|
Fault(700, u'no such error'), # There is no error 700
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user