Here is my apache logs : <div>------------------------------------------------------------------------------------------------</div>
<div><div>==> /var/log/httpd/error_log <==</div><div>[Wed Apr 21 20:02:51 2010] [warn] mod_python (pid=1529, interpreter='<a href="http://rpcserver.domain.org">rpcserver.domain.org</a>'): Module directory listed in "sys.path". This may cause problems. Please check code. File being imported is "/usr/lib/python2.6/site-packages/webservices/account.py".</div>
<div>[Wed Apr 21 20:02:51 2010] [notice] mod_python (pid=1529, interpreter='<a href="http://rpcserver.domain.org">rpcserver.domain.org</a>'): Importing module '/usr/lib/python2.6/site-packages/webservices/account.py'</div>
<div>/usr/lib/python2.6/site-packages/mod_python/importer.py:32: DeprecationWarning: the md5 module is deprecated; use hashlib instead</div><div> import md5</div><div>ipa: ERROR: Could not create log_dir '/root/.ipa/log'</div>
<div>ipa: ERROR: could not load plugin module '/usr/lib/python2.6/site-packages/ipalib/plugins/migration.py'</div><div>Traceback (most recent call last):</div><div> File "/usr/lib/python2.6/site-packages/ipalib/plugable.py", line 533, in import_plugins</div>
<div> __import__(fullname)</div><div> File "/usr/lib/python2.6/site-packages/ipalib/plugins/migration.py", line 33, in <module></div><div> from ipaserver.plugins.ldap2 import ldap2</div><div> File "/usr/lib/python2.6/site-packages/ipaserver/__init__.py", line 33, in <module></div>
<div> api.bootstrap(context='server', debug=True, log=None)</div><div> File "/usr/lib/python2.6/site-packages/ipalib/plugable.py", line 380, in bootstrap</div><div> self.__doing('bootstrap')</div>
<div> File "/usr/lib/python2.6/site-packages/ipalib/plugable.py", line 365, in __doing</div><div> '%s.%s() already called' % (self.__class__.__name__, name)</div><div>StandardError: API.bootstrap() already called</div>
<div><br></div><div><br></div><div>==> /var/log/httpd/access_log <==</div><div>172.30.0.135 - - [21/Apr/2010:20:02:51 +0200] "POST /xmlrpc HTTP/1.0" 200 348 "-" "<a href="http://xmlrpclib.py/1.0.1" target="_blank">xmlrpclib.py/1.0.1</a> (by <a href="http://www.pythonware.com" target="_blank">www.pythonware.com</a>)"</div>
<div><br></div></div><div>------------------------------------------------------------------------------------------------</div><div><div><br></div></div><div><br></div><div>And here my xmlrpchandler</div><div><div><div>
------------------------------------------------------------------------------------------------</div>
</div></div><div><div>import sys</div><div>import os</div><div>from mod_python import apache</div><div>import xmlrpclib</div><div>import types</div><div><br></div><div>import imp</div><div>import re</div><div><br></div><div>
<br></div><div># Functions we want callable via XML-RPC</div><div>__all__ = ['listMethods', 'methodSignature', 'methodHelp', 'multicall']</div><div><br></div><div># For method signatures</div>
<div>INT = 'int'</div><div>STRING = 'string'</div><div>BOOLEAN = 'boolean'</div><div>DOUBLE = 'double'</div><div>DATETIME = 'dateTime.iso8601'</div><div>BASE64 = 'base64'</div>
<div>ARRAY = 'array'</div><div>STRUCT = 'struct'</div><div><br></div><div># Saw this done in mod_python's apache.py. I just fixed it up a little...</div><div>_suffixes = map(lambda x: x[0].replace('.', '\\.'), imp.get_suffixes())</div>
<div>_exp = '(' + '|'.join(_suffixes) + ')$'</div><div>_suffix_re = re.compile(_exp)</div><div><br></div><div>_environ = {}</div><div><br></div><div><br></div><div><br></div><div><br></div><div>def listMethods(env=None):</div>
<div> """Enumerates all available XML-RPC methods."""</div><div> __xmlrpc_signature = '[[ARRAY]]'</div><div><br></div><div> method_list = []</div><div><br></div><div> # scan the directory which this module resides in</div>
<div> path = os.path.dirname(sys.modules[__name__].__file__)</div><div> try:</div><div> module_list = []</div><div> </div><div> files = os.listdir(path)</div><div> for f in files:</div><div>
# does it have a module suffix?</div><div> if not _suffix_re.search(f):</div><div> continue</div><div> # strip module suffix</div><div> module_name = _suffix_re.sub('', f)</div>
<div> # ensure it's not private or this module</div><div> if module_name[0] == '_' or module_name == __name__:</div><div> continue</div><div> if module_name not in module_list:</div>
<div> module_list.append(module_name)</div><div><br></div><div> for module_name in module_list:</div><div> try:</div><div> module = apache.import_module(module_name, path=[path])</div>
<div> except:</div><div> pass</div><div> else:</div><div> # scan module for non-private functions</div><div> func_list = getattr(module, '__all__', dir(module))</div>
<div> for func_name in func_list:</div><div> if func_name[0] != '_' and \</div><div> callable(getattr(module, func_name, None)):</div><div> method_list.append('%s.%s' % (module_name, func_name))</div>
<div> except:</div><div> pass</div><div> </div><div> # add system methods</div><div> method_list.extend(map(lambda x: 'system.%s' % x, __all__))</div><div><br></div><div> method_list.sort()</div>
<div> return method_list</div><div><br></div><div>def methodSignature(method, env=None):</div><div> """Returns an XML-RPC method's signature."""</div><div> __xmlrpc_signature = '[[ARRAY, STRING]]'</div>
<div> </div><div> func = _map_methodName(method)</div><div> if not func:</div><div> return xmlrpclib.Fault(1, '%s: not implemented' % method)</div><div><br></div><div> return _get_signature(func)</div>
<div><br></div><div>def methodHelp(method, env=None):</div><div> """Returns an XML-RPC method's help string."""</div><div> __xmlrpc_signature = '[[STRING, STRING]]'</div><div>
</div><div> func = _map_methodName(method)</div><div> if not func:</div><div> return xmlrpclib.Fault(1, '%s: not implemented' % method)</div><div><br></div><div> if func.__doc__:</div><div> help = _strip_docstring(func.__doc__)</div>
<div> else:</div><div> help = ''</div><div> </div><div> return help</div><div><br></div><div>def multicall(call_params, env=None):</div><div> """Executes multiple method calls with a single request."""</div>
<div> __xmlrpc_signature = '[[ARRAY, ARRAY]]'</div><div><br></div><div> result_list = []</div><div><br></div><div> for param in call_params:</div><div> if type(param) != dict:</div><div> result_list.append(_fault_struct(1, 'struct expected'))</div>
<div> continue</div><div><br></div><div> if not param.has_key('methodName') or \</div><div> not param.has_key('params'):</div><div> result_list.append(_fault_struct(1, 'methodName/params members ' \</div>
<div> 'missing'))</div><div> continue</div><div> </div><div> method, params = param['methodName'], param['params']</div><div><br>
</div><div> if method == 'system.multicall':</div><div> result_list.append(_fault_struct(1, 'system.multicall: ' \</div><div> 'recursion forbidden'))</div>
<div> continue</div><div> </div><div> try:</div><div> result = _dispatch(method, params)</div><div> if isinstance(result, xmlrpclib.Fault):</div><div> result = _fault_struct(result.faultCode, result.faultString)</div>
<div> else:</div><div> result = (result,)</div><div> except:</div><div> result_list.append(_fault_struct(2, '%s: %s: %s' %</div><div> (method, sys.exc_type,</div>
<div> sys.exc_value)))</div><div> else:</div><div> result_list.append(result)</div><div> </div><div> return result_list</div><div><br></div><div>def _expand_tabs(s, width=8):</div>
<div> """Expands tabs to spaces, assuming tabs are of the specified width."""</div><div> </div><div> o = ''</div><div> col = 0</div><div> for c in s:</div><div> if c == '\t':</div>
<div> next = width - (col % width)</div><div> o += ' '[:next]</div><div> col += next</div><div> else:</div><div> o += c</div><div> col += 1</div>
<div> return o</div><div><br></div><div>def _strip_docstring(s):</div><div> """Takes a docstring and removes any extraneous indentation."""</div><div> </div><div> # Break into lines and expand tabs.</div>
<div> s = s.split('\n')</div><div> s = map(_expand_tabs, s)</div><div><br></div><div> # Convert lines with only spaces to empty strings.</div><div> for i in range(len(s)):</div><div> if s[i] and not s[i].strip():</div>
<div> s[i] = ''</div><div><br></div><div> # Single line or empty docstring.</div><div> if len(s) == 1:</div><div> return s[0]</div><div><br></div><div> # Take care of the first line.</div>
<div> o = ''</div><div> o += s[0] + '\n'</div><div><br></div><div> # Go through each line. The first non-blank line determines the indent for</div><div> # the entire docstring. Unindent each line.</div>
<div> indent = 0</div><div> for line in s[1:]:</div><div> if line:</div><div> if not indent:</div><div> indent = len(line) - len(line.lstrip())</div><div> if line.startswith(' '*indent):</div>
<div> line = line[indent:]</div><div> else:</div><div> # Indent was short. Strip as much as we can anyway.</div><div> line = line.lstrip()</div><div> o += line + '\n'</div>
<div> else:</div><div> o += '\n'</div><div><br></div><div> # If docstring ends with two linefeeds, remove one of them.</div><div> if o[-2:] == '\n\n':</div><div> o = o[:-1]</div>
<div> </div><div> return o</div><div><br></div><div>def _get_func_const(func, name, default=None):</div><div> """Get the value of a constant variable defined in a function."""</div>
<div>
<br></div><div> func_code = getattr(func, 'func_code', None)</div><div> if func_code:</div><div> if name in func_code.co_names:</div><div> i = list(func_code.co_names).index(name) + 1</div>
<div> return func_code.co_consts[i]</div><div> return default</div><div><br></div><div>def _get_signature(func):</div><div> """Return the parameter signature of a function.</div><div><br></div>
<div> Will first check func.__xmlrpc_signature, expecting it to be a list</div><div> of signatures. Otherwise, it will check a constant variable called</div><div> __xmlrpc_signature defined within the function. The variable MUST</div>
<div> be a string and must evaluate to a list of signatures.</div><div><br></div><div> Returns an empty list if none neither are a valid signature list.</div><div> """</div><div> </div><div> if hasattr(func, '__xmlrpc_signature'):</div>
<div> sig = func.__xmlrpc_signature</div><div> else:</div><div> sig_str = _get_func_const(func, '__xmlrpc_signature')</div><div> sig = []</div><div> if sig_str:</div><div> try:</div>
<div> sig = eval(sig_str)</div><div> # need to validate the signature someday...</div><div> except:</div><div> pass</div><div> </div><div> return sig</div>
<div><br></div><div>_type_map = {</div><div> types.IntType: INT,</div><div> types.LongType: INT,</div><div> types.StringType: STRING,</div><div> types.FloatType: DOUBLE,</div><div> types.TupleType: ARRAY,</div>
<div> types.ListType: ARRAY,</div><div> types.DictType: STRUCT</div><div> }</div><div><br></div><div>def _xmlrpc_type(v):</div><div> """Returns an XML-RPC type for a given value."""</div>
<div><br></div><div> t = type(v)</div><div> if _type_map.has_key(t):</div><div> return _type_map[t]</div><div> if t is types.InstanceType:</div><div> if isinstance(v, xmlrpclib.DateTime):</div><div>
return DATETIME</div><div> elif isinstance(v, xmlrpclib.Binary):</div><div> return BASE64</div><div> elif isinstance(v, xmlrpclib.Boolean):</div><div> return BOOLEAN</div><div>
# Huh?!</div><div> return STRING</div><div><br></div><div>def _match_signature(params, sig_list):</div><div> """Matches an argument list with a signature list.</div><div><br></div><div> If signature list is empty, any sort of argument list is accepted.</div>
<div> """</div><div> </div><div> param_types = map(_xmlrpc_type, params)</div><div> empty_sig = 1</div><div> for sig in sig_list:</div><div> empty_sig = 0</div><div><br></div><div> # skip return type</div>
<div> sig = sig[1:]</div><div> </div><div> if len(param_types) == len(sig) and param_types == sig:</div><div> return 1</div><div> </div><div> return empty_sig</div><div><br></div>
<div>def _fault_struct(faultCode, faultString):</div><div> """Returns a Fault as a dictionary."""</div><div><br></div><div> return { 'faultCode': faultCode, 'faultString': faultString }</div>
<div><br></div><div>def _map_methodName(method):</div><div> """Maps a methodName in the form of module.function to a function."""</div><div><br></div><div> # parse methodName as module.function</div>
<div> method = method.split('.')</div><div> if len(method) != 2:</div><div> return None</div><div><br></div><div> module_name, func_name = method</div><div><br></div><div> if module_name == 'system':</div>
<div> # reserved functions are implemented in this module</div><div> module = sys.modules[__name__]</div><div> else:</div><div> # attempt to load module from the same directory as this module</div>
<div> path = os.path.dirname(sys.modules[__name__].__file__)</div><div><br></div><div> module = None</div><div> # ensure it is not private</div><div> if module_name[0] != '_' and module_name != __name__:</div>
<div> try:</div><div> module = apache.import_module(module_name, path=[path])</div><div> except:</div><div> pass</div><div><br></div><div> if module is None:</div>
<div> return None</div><div><br></div><div> # now see if module has callable function named func_name</div><div> if hasattr(module, '__all__') and func_name not in module.__all__:</div><div> return None</div>
<div> </div><div> if func_name[0] != '_' and hasattr(module, func_name):</div><div> func = getattr(module, func_name)</div><div><br></div><div> if callable(func):</div><div> return func</div>
<div><br></div><div> return None</div><div><br></div><div>def _dispatch(method, params):</div><div> """Calls an XML-RPC method."""</div><div> global _environ</div><div><br></div><div>
func = _map_methodName(method)</div><div> if func is None:</div><div> return xmlrpclib.Fault(1, '%s: not implemented' % method)</div><div><br></div><div> # check arguments</div><div> sig_list = _get_signature(func)</div>
<div> if not _match_signature(params, sig_list):</div><div> return xmlrpclib.Fault(1, '%s: bad arguments' % method )</div><div> </div><div> # call the function</div><div> result = apply(func, params, {'env':_environ})</div>
<div> </div><div> # if result is None, set it to False</div><div> if result is None:</div><div> result = xmlrpclib.False</div><div> </div><div> return result</div><div><br></div><div># These HTTP headers are required according to the XML-RPC spec</div>
<div>_required_headers = ['Host', 'User-Agent', 'Content-Type', 'Content-Length']</div><div><br></div><div>def handler(req):</div><div> """mod_python handler."""</div>
<div> global _environ</div><div> _environ = dict(apache.build_cgi_env(req))</div><div> # only accept POST requests</div><div> if req.method != 'POST':</div><div> # We set this even though it doesn't seem to do anything...</div>
<div> req.err_headers_out['Allow'] = 'POST'</div><div> return apache.HTTP_METHOD_NOT_ALLOWED</div><div><br></div><div> # check that all required headers are present</div><div> for h in _required_headers:</div>
<div> if not req.headers_in.has_key(h):</div><div> return apache.HTTP_BAD_REQUEST</div><div><br></div><div> if not req.headers_in['Content-Type'].startswith('text/xml'):</div><div> return apache.HTTP_UNSUPPORTED_MEDIA_TYPE</div>
<div><br></div><div> # The structure of the following was inspired by Brian Quinlan's</div><div> # SimpleXMLRPCServer.py (which was inspired by Fredrik Lundh's code).</div><div> try:</div><div> length = int(req.headers_in['Content-Length'])</div>
<div><br></div><div> # read and parse request</div><div> data = req.read(length)</div><div> params, method = xmlrpclib.loads(data)</div><div><br></div><div> try:</div><div> # dispatch the method</div>
<div> response = _dispatch(method, params)</div><div><br></div><div> # convert response to singleton, if necessary</div><div> if not isinstance(response, xmlrpclib.Fault):</div><div> response = (response,)</div>
<div> except:</div><div> # caught an exception, return it as our fault response</div><div> response = xmlrpclib.Fault(2, '%s: %s: %s' %</div><div> (method, sys.exc_type, sys.exc_value))</div>
<div><br></div><div> # convert response to xml</div><div> response = xmlrpclib.dumps(response, methodresponse=1)</div><div> except:</div><div> # eh?!</div><div> return apache.HTTP_BAD_REQUEST</div>
<div> else:</div><div> # send response</div><div> req.content_type = 'text/xml'</div><div> req.headers_out['Content-Length'] = str(len(response))</div><div> req.send_http_header()</div>
<div> req.write(response)</div><div> return apache.OK</div></div><div><div>------------------------------------------------------------------------------------------------</div></div><div><br></div><div><br>
</div><div>And here my code of client </div><div><div>------------------------------------------------------------------------------------------------</div></div><div>#!/usr/bin/python <div>
<br></div><div>import xmlrpclib as rpc</div><div>remote = rpc.ServerProxy('<a href="http://client2.gamma.agorabox.org/xmlrpc" target="_blank">http://<span class="Apple-style-span" style="color: rgb(0, 0, 0); -webkit-text-decorations-in-effect: none; ">rpcserver.domain.org</span>/xmlrpc</a>')</div>
<div>print "+++++++ remote.account.getUserInfos(u'admin')"</div>
<div>print remote.account.getUserInfos(u'admin')</div><div><div><div>------------------------------------------------------------------------------------------------</div></div></div><div><br></div><div><br></div>
<div><br></div><div>---</div>Meilleures salutations / Best Regards<br><br>Rachid ALAHYANE<br><br>
<br><br><div class="gmail_quote">2010/4/21 Rob Crittenden <span dir="ltr"><<a href="mailto:rcritten@redhat.com" target="_blank">rcritten@redhat.com</a>></span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div>ALAHYANE Rachid wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Ok so, my end goal is to use the ipa methods with xml-rpc as following,<br>
<br>
* ipaServer : my ipa server, used to authenticate users and serves response for xml-rpc calls from rpcServer<br>
* rpcServer : this host is my xml-rpc server, I installed freeipa libraires on it, and an apache server with mod_python and mod_auth_kerb. This hosts will be used as a client ipa, It is for these reasons that i used `account.py` from within apache.<br>
* myClient : this host is the one which will make the rpc calls to rpcServer.<br>
<br>
NB : 'account.py' is called by xmlrpchandler (it is my python handler) when getUserInfos is called by myclient .<br>
</blockquote>
<br></div>
Can you set LogLevel debug on the rpcServer web server and see if you get a backtrace (or look in /var/log/httpd/error_log, you may already have one).<br>
<br>
What is strange is that this code works fine standalone. Can you show us all the code in your xmlrpchandler?<br>
<br>
BTW, your English is fine :-)<br><font color="#888888">
<br>
rob</font><div><div></div><div><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
<br>
Example :<br>
myClient calls the remote.account.getUserInfos(u'admin'), rpcServer (in mode client) intercepts this call and forwards it to the ipaServer. This last one sends the response to rpcServer (via xml-rpc) and then rpcServer responds to myClient.<br>
<br>
<br>
this is my configurations :<br>
<br>
== On rpcServer ==<br>
--------- httpd conf ------------<br>
<Files "xmlrpc"><br>
## python conf # ....<br>
SetHandler python-program<br>
PythonHandler xmlrpchandler<br>
PythonDebug on<br>
</Files><br>
------------------------------------<br>
<br>
the handler xmlrpchandler calls the following method when the client requests for the remote method getUserInfos().<br>
<br>
--------- account.py ------------<br>
def getUserInfos(user_name, env=None):<br>
<br>
from ipalib import api<br>
<br>
api.bootstrap_with_global_options(context='webservices')<br>
api.finalize()<br>
# mode Server is False. I am not on the server ipa<br>
api.Backend.xmlclient.connect()<br>
return api.Command.user_show(user_name) ------------------------------------<br>
<br>
<br>
== On myClient ==<br>
When I call this method from my client, I get this exception : <br>
------------------------------------<br>
<Fault 2: "remote.account.getUserInfos: <type 'exceptions.StandardError'>: API.bootstrap() already called"><br>
------------------------------------<br>
<br>
<br>
I hope that is clearer now, despite my bad English ;)<br>
<br>
<br>
---<br>
Meilleures salutations / Best Regards<br>
<br>
Rachid ALAHYANE<br>
<br>
<br>
<br>
</blockquote>
<br>
</div></div></blockquote></div><br>
</div>