source: fedd/fedd_proj.py @ bb3769a

axis_examplecompt_changesinfo-opsversion-1.30version-2.00version-3.01version-3.02
Last change on this file since bb3769a was bb3769a, checked in by Ted Faber <faber@…>, 16 years ago

parsing SOAP faults (finally)

  • Property mode set to 100644
File size: 22.3 KB
Line 
1#!/usr/local/bin/python
2
3import os,sys
4
5from BaseHTTPServer import BaseHTTPRequestHandler
6from ZSI import *
7from M2Crypto import SSL
8from M2Crypto.m2xmlrpclib import SSL_Transport
9from M2Crypto.SSL.SSLServer import SSLServer
10import M2Crypto.httpslib
11import xmlrpclib
12
13import re
14import random
15import string
16import subprocess
17import tempfile
18import copy
19
20from fedd_services import *
21from fedd_util import *
22
23if False:
24    _RequestAccessFault_typecode = Struct(pname=("http://www.isi.edu/faber/fedd.wsdl", 'RequestAccessFault'), ofwhat=[ns0.faultType_Def( pname=("http://www.isi.edu/faber/fedd.wsdl", "RequestAccessFaultBody"), aname="_RequestAccessFaultBody", minoccurs=0, maxoccurs=1, nillable=True, encoded=None, typed=True)], pyclass=None)
25    class RequestAccessFault:
26        typecode = _RequestAccessFault_typecode
27        __metaclass__ = pyclass_type
28        def __init__(self, code=0, str="str"):
29            self._RequestAccessFaultBody = None
30    RequestAccessFault.typecode.pyclass=RequestAccessFault
31
32class fedd_proj:
33    """
34    The implementation of access control based on mapping users to projects.
35
36    Users can be mapped to existing projects or have projects created
37    dynamically.  This implements both direct requests and proxies.
38    """
39    # Attributes that can be parsed from the configuration file
40    bool_attrs = ("dynamic_projects", "project_priority")
41    emulab_attrs = ("boss", "ops", "domain", "fileserver", "eventserver")
42    id_attrs = ("testbed", "cert_file", "trusted_certs", "proxy",
43            "proxy_trusted_certs", "cert_pwd")
44
45    # Used by the SOAP caller
46    soap_namespace = 'http://www.isi.edu/faber/fedd.wsdl'
47    soap_methods = { 'RequestAccess': 'soap_RequestAccess' }
48    xmlrpc_methods = { 'RequestAccess': 'xmlrpc_RequestAccess' }
49
50    class access_project:
51        """
52        A project description used to grant access to this testbed.
53
54        The description includes a name and a list of node types to which the
55        project will be granted access.
56        """
57        def __init__(self, name, nt):
58            self.name = name
59            self.node_types = list(nt)
60
61        def __repr__(self):
62            if len(self.node_types) > 0:
63                return "access_proj('%s', ['%s'])" % \
64                        (self.name, str("','").join(self.node_types))
65            else:
66                return "access_proj('%s', [])" % self.name
67
68    # These are used to make the error reporting independent of the transport.
69    # The XMLRPC and SOAP dispatchers will convert them to transport-specific
70    # errors
71    class server_error(RuntimeError): pass
72    class client_error(RuntimeError): pass
73    # Error parsing config
74    class parse_error(RuntimeError): pass
75
76
77    def __init__(self, config=None):
78        """
79        Initializer.  Parses a configuration if one is given.
80        """
81
82        # Create instance attributes from the static lists
83        for a in fedd_proj.bool_attrs:
84            setattr(self, a, False)
85
86        for a in fedd_proj.emulab_attrs + fedd_proj.id_attrs:
87            setattr(self, a, None)
88
89        # Other attributes
90        self.attrs = {}
91        self.access = {}
92        self.fedid_category = {}
93        self.fedid_default = "user"
94        self.restricted = []
95        self.wap = '/usr/testbed/sbin/wap'
96        self.newproj = '/usr/testbed/sbin/newproj'
97        self.mkproj = '/usr/testbed/sbin/mkproj'
98        self.grantnodetype = '/usr/testbed/sbin/grantnodetype'
99
100        # Read the configuration
101        if config != None: 
102            self.read_config(config)
103
104    def dump_state(self):
105        """
106        Dump the state read from a configuration file.  Mostly for debugging.
107        """
108        for a in fedd_proj.bool_attrs:
109            print "%s: %s" % (a, getattr(self, a ))
110        for a in fedd_proj.emulab_attrs + fedd_proj.id_attrs:
111            print "%s: %s" % (a, getattr(self, a))
112        for k, v in self.attrs.iteritems():
113            print "%s %s" % (k, v)
114        print "Access DB:"
115        for k, v in self.access.iteritems():
116            print "%s %s" % (k, v)
117        print "Trust DB:"
118        for k, v in self.fedid_category.iteritems():
119            print "%s %s" % (k, v)
120        print "Restricted: %s" % str(',').join(sorted(self.restricted))
121
122    def get_id(self, id):
123        """
124        Utility to get an object from the polymorphic IDType.
125       
126        Only fedids and usernames are currently understood.  If neither is
127        present None is returned.  If both are present (which is a bug) the
128        fedid is returned.
129        """
130        if id == None: 
131            return None
132        elif getattr(id, "get_element_fedid", None) != None:
133            return fedid(id.get_element_fedid())
134        elif getattr(id, "get_element_username", None) != None:
135            return id.get_element_username()
136        else:
137            return None
138
139    def get_users(self, obj):
140        """
141        Return a list of the IDs of the users in dict
142        """
143        if obj.has_key('user'):
144            return [ unpack_id(u['userID']) \
145                    for u in obj['user'] if u.has_key('userID') ]
146        else:
147            return None
148
149    def random_string(self, s, n=3):
150        """Append n random ASCII characters to s and return the string"""
151        rv = s
152        for i in range(0,n):
153            rv += random.choice(string.ascii_letters)
154        return rv
155
156    def write_attr_xml(self, file, root, lines):
157        """
158        Write an emulab config file for a dynamic project.
159
160        Format is <root><attribute name=lines[0]>lines[1]</attribute></root>
161        """
162        # Convert a pair to an attribute line
163        out_attr = lambda a,v : \
164                '<attribute name="%s"><value>%s</value></attribute>' % (a, v)
165
166        f = os.fdopen(file, "w")
167        f.write("<%s>\n" % root)
168        f.write("\n".join([out_attr(*l) for l in lines]))
169        f.write("</%s>\n" % root)
170        f.close()
171
172
173    def dynamic_project(self, found, ssh):
174        """Create a dynamic project with ssh access"""
175        user_fields = [
176                ("name", "Federation User %s" % found[1]),
177                ("email", "%s-fed@isi.deterlab.net" % found[1]),
178                ("password", self.random_string("", 8)),
179                ("login", found[1]),
180                ("address", "4676 Admiralty"),
181                ("city", "Marina del Rey"),
182                ("state", "CA"),
183                ("zip", "90292"),
184                ("country", "USA"),
185                ("phone", "310-448-9190"),
186                ("title", "None"),
187                ("affiliation", "USC/ISI")
188        ]
189
190        proj_fields = [
191                ("name", found[0].name),
192                ("short description", "dynamic federated project"),
193                ("URL", "http://www.isi.edu/~faber"),
194                ("funders", "USC/USU"),
195                ("long description", "Federation access control"),
196                ("public", "1"),
197                ("num_pcs", "100"),
198                ("linkedtous", "1")
199        ]
200
201        # tempfiles for the parameter files
202        uf, userfile = tempfile.mkstemp(prefix="usr", suffix=".xml",
203                dir="/tmp")
204        pf, projfile = tempfile.mkstemp(prefix="proj", suffix=".xml",
205                dir="/tmp")
206
207        # A few more dynamic fields
208        for s in ssh:
209            user_fields.append(("pubkey", s))
210        proj_fields.append(("newuser_xml", userfile))
211
212        # Write out the files
213        self.write_attr_xml(uf, "user", user_fields)
214        self.write_attr_xml(pf, "project", proj_fields)
215
216        # Generate the commands (only grantnodetype's are dynamic)
217        cmds = [
218                (self.wap, self.newproj, projfile),
219                (self.wap, self.mkproj, found[0].name)
220                ]
221        for nt in found[0].node_types:
222            cmds.append((self.wap, self.grantnodetype, '-p', found[0].name, nt))
223
224        # Create the projects
225        rc = 0
226        for cmd in cmds:
227            if self.dynamic_projects:
228                try:
229                    rc = subprocess.call(cmd)
230                except OSerror, e:
231                    raise fedd_proj.server_error(
232                            "Dynamic project subprocess creation error "+ \
233                                    "[%s] (%s)" %  (cmd[1], e.strerror))
234            else:
235                print >>sys.stdout, str(" ").join(cmd)
236
237            if rc != 0: 
238                raise fedd_proj.server_error(
239                        "Dynamic project subprocess error " +\
240                                "[%s] (%d)" % (cmd[1], rc))
241        # Clean up tempfiles
242        os.unlink(userfile)
243        os.unlink(projfile)
244
245   
246    def strip_unicode(self, obj):
247        """Loosly de-unicode an object"""
248        if isinstance(obj, dict):
249            for k in obj.keys():
250                obj[k] = self.strip_unicode(obj[k])
251            return obj
252        elif isinstance(obj, basestring):
253            return str(obj)
254        elif getattr(obj, "__iter__", None):
255            return [ self.strip_unicode(x) for x in obj]
256        else:
257            return obj
258
259    def proxy_xmlrpc_request(self, dt, req):
260        """Send an XMLRPC proxy request.  Called if the SOAP RPC fails"""
261        tc = self.proxy_trusted_certs or self.trusted_certs
262
263        # No retry loop here.  Proxy servers must correctly authenticate
264        # themselves without help
265        try:
266            ctx = fedd_ssl_context(self.cert_file, tc, password=self.cert_pwd)
267        except SSL.SSLError:
268            raise fedd_proj.server_error("Server certificates misconfigured")
269
270        # Of all the dumbass things.  The XMLRPC library in use here won't
271        # properly encode unicode strings, so we make a copy of req with the
272        # unicode objects converted.  We also convert the destination testbed
273        # to a basic string if it isn't one already.
274        if isinstance(dt, str): url = dt
275        else: url = str(dt)
276
277        r = copy.deepcopy(req)
278        self.strip_unicode(r)
279       
280        transport = SSL_Transport(ctx)
281        port = xmlrpclib.ServerProxy(url, transport=transport)
282
283        # Reconstruct the full request message
284        try:
285            resp = port.RequestAccess(
286                    { "RequestAccessRequestBody": r})
287            resp, method = xmlrpclib.loads(resp)
288        except xmlrpclib.Error, e:
289            raise fedd_proj.server_error("Remote XMLRPC Fault: %s" % e)
290       
291        if resp[0].has_key('RequestAccessResponseBody'):
292            return resp[0]['RequestAccessResponseBody']
293        else:
294            raise fedd_proj.server_error("Bad proxy response")
295
296    def proxy_request(self, dt, req):
297        """
298        Send req on to the real destination in dt and return the response
299
300        Req is just the requestType object.  This function re-wraps it.  It
301        also rethrows any faults.
302        """
303        tc = self.proxy_trusted_certs or self.trusted_certs
304
305        # No retry loop here.  Proxy servers must correctly authenticate
306        # themselves without help
307        try:
308            ctx = fedd_ssl_context(self.cert_file, tc, password=self.cert_pwd)
309        except SSL.SSLError:
310            raise fedd_proj.server_error("Server certificates misconfigured")
311
312        loc = feddServiceLocator();
313        port = loc.getfeddPortType(dt,
314                transport=M2Crypto.httpslib.HTTPSConnection, 
315                transdict={ 'ssl_context' : ctx })
316
317        # Reconstruct the full request message
318        msg = RequestAccessRequestMessage()
319        msg.set_element_RequestAccessRequestBody(
320                pack_soap(msg, "RequestAccessRequestBody", req))
321        try:
322            resp = port.RequestAccess(msg)
323        except ZSI.ParseException, e:
324            raise fedd_proj.server_error("Bad format message (XMLRPC??): %s" %
325                    str(e))
326        except ZSI.FaultException, e:
327            raise e.fault
328
329        r = unpack_soap(resp)
330
331        if r.has_key('RequestAccessResponseBody'):
332            return r['RequestAccessResponseBody']
333        else:
334            raise fedd_proj.server_error("Bad proxy response")
335
336    def permute_wildcards(self, a, p):
337        """Return a copy of a with various fields wildcarded.
338
339        The bits of p control the wildcards.  A set bit is a wildcard
340        replacement with the lowest bit being user then project then testbed.
341        """
342        if p & 1: user = ["<any>"]
343        else: user = a[2]
344        if p & 2: proj = "<any>"
345        else: proj = a[1]
346        if p & 4: tb = "<any>"
347        else: tb = a[0]
348
349        return (tb, proj, user)
350
351    def find_access(self, search):
352        """
353        Search the access DB for a match on this tuple.  Return the matching
354        access tuple and the user that matched.
355       
356        NB, if the initial tuple fails to match we start inserting wildcards in
357        an order determined by self.project_priority.  Try the list of users in
358        order (when wildcarded, there's only one user in the list).
359        """
360        if self.project_priority: perm = (0, 1, 2, 3, 4, 5, 6, 7)
361        else: perm = (0, 2, 1, 3, 4, 6, 5, 7)
362
363        for p in perm: 
364            s = self.permute_wildcards(search, p)
365            # s[2] is None on an anonymous, unwildcarded request
366            if s[2] != None:
367                for u in s[2]:
368                    if self.access.has_key((s[0], s[1], u)):
369                        return (self.access[(s[0], s[1], u)], u)
370            else:
371                if self.access.has_key(s):
372                    return (self.access[s], None)
373        return None
374
375    def lookup_access(self, req, fid):
376        """
377        Determine the allowed access for this request.  Return the access and
378        which fields are dynamic.
379
380        The fedid is needed to construct the request
381        """
382        tb = None
383        project = None
384        user = None
385
386        principal_type = self.fedid_category.get(fid, self.fedid_default)
387
388        if principal_type == "testbed": tb = fid
389
390        if req.has_key('project'):
391            p = req['project']
392            if p.has_key('name'):
393                project = unpack_id(p['name'])
394            user = self.get_users(p)
395        else:
396            user = self.get_users(req)
397
398        # Now filter by prinicpal type
399        if principal_type == "user":
400            if user != None:
401                fedids = [ u for u in user if isinstance(u, type(fid))]
402                if len(fedids) > 1:
403                    raise fedd_proj.client_error(
404                            "User asserting multiple fedids")
405                elif len(fedids) == 1 and fedids[0] != fid:
406                    raise fedd_proj.client_error(
407                            "User asserting different fedid")
408            project = None
409            tb = None
410        elif principal_type == "project":
411            if isinstance(project, type(fid)) and fid != project:
412                raise fedd_proj.client_error(
413                        "Project asserting different fedid")
414            tb = None
415
416        # Ready to look up access
417        print "Lookup %s %s %s: " % (tb, project, user)
418        found, user_match = self.find_access((tb, project, user))
419        print "Found: ", found
420       
421        if found == None: raise fedd_proj.server_error("Access denied")
422
423        # resolve <dynamic> and <same> in found
424        dyn_proj = False
425        dyn_user = False
426
427        if found[0].name == "<same>":
428            if project != None:
429                found[0].name = project
430            else : 
431                raise fedd_proj.server_error(
432                        "Project matched <same> when no project given")
433        elif found[0].name == "<dynamic>":
434            found[0].name = self.random_string("project", 3)
435            dyn_proj = True
436
437        if found[1] == "<same>":
438            if user_match == "<any>":
439                if user != None: found = (found[0], user[0])
440                else: raise fedd_proj.server_error(
441                        "Matched <same> on anonymous request")
442            else:
443                found = (found[0], user_match)
444        elif found[1] == "<dynamic>":
445            found = (found[0], self.random_string("user", 4))
446            dyn_user = True
447       
448        return found, (dyn_user, dyn_proj)
449
450    def build_response(self, alloc_id, ap, ssh):
451        """
452        Create the SOAP response.
453
454        Build the dictionary description of the response and use
455        fedd_utils.pack_soap to create the soap message.  NB that alloc_id is
456        a fedd_services_types.IDType_Holder pulled from the incoming message
457        """
458        # Because alloc_id is already a fedd_services_types.IDType_Holder,
459        # there's no need to repack it
460        msg = { 
461                'allocID': alloc_id,
462                'emulab': { 
463                    'domain': self.domain,
464                    'boss': self.boss,
465                    'ops': self.ops,
466                    'fileServer': self.fileserver,
467                    'eventServer': self.eventserver,
468                    'project': {
469                        'name': pack_id(ap[0].name),
470                        'user': [ {
471                            'userID': pack_id(ap[1]),
472                            'access' : [ { 'sshPubkey': x } for x in ssh ],
473                            }
474                        ]
475                    }
476                },
477            }
478        if len(self.attrs) > 0:
479            msg['emulab']['fedAttr'] = \
480                [ { 'attribute': x, 'value' : y } \
481                        for x,y in self.attrs.iteritems()]
482        return msg
483
484    def RequestAccess(self, req, fid):
485
486        if req.has_key('RequestAccessRequestBody'):
487            req = req['RequestAccessRequestBody']
488        else:
489            raise fedd_proj.client_error("No request!?")
490
491        if req.has_key('destinationTestbed'):
492            dt = unpack_id(req['destinationTestbed'])
493       
494        if dt == None or dt == self.testbed:
495            # Request for this fedd
496            found, dyn = self.lookup_access(req, fid)
497
498            # Check for access to restricted nodes
499            if req.has_key('resources') and req['resources'].has_key('node'):
500                resources = req['resources']
501                inaccessible = [ t for n in resources['node'] \
502                                if n.has_key('hardware') != None \
503                                    for t in n['hardware'] \
504                                        if t in self.restricted and \
505                                                t not in found[0].node_types]
506                if len(inaccessible) > 0:
507                    raise fedd_proj.server_error(
508                            "Access denied (nodetypes %s)" % \
509                            str(', ').join(inaccessible))
510
511            ssh = [ x['sshPubkey'] \
512                    for x in req['access'] if x.has_key('sshPubkey')]
513
514            if len(ssh) > 0: 
515                if dyn[1]: self.dynamic_project(found, ssh)
516                else: pass    # SSH key additions
517            else:
518                raise fedd_proj.client_error("SSH access parameters required")
519
520            resp = self.build_response(req['allocID'], found, ssh)
521            return resp
522        else:
523            p_fault = None      # Any SOAP failure (sent unless XMLRPC works)
524            try:
525                # Proxy the request using SOAP
526                return self.proxy_request(dt, req)
527            except RuntimeError, f:
528                p_fault = f
529         
530           
531            # This runs if SOAP failed
532            try:
533                return self.proxy_xmlrpc_request(dt, req)
534                print "here"
535            except RuntimeError:
536                # Both failed, return the SOAP error.  If somehow that
537                # exception is gone, return the XMLRPC one
538                if p_fault != None: raise p_fault
539                else: raise
540
541    def soap_RequestAccess(self, ps, fid):
542        req = ps.Parse(RequestAccessRequestMessage.typecode)
543
544        msg = self.RequestAccess(unpack_soap(req), fedid)
545       
546        resp = RequestAccessResponseMessage()
547        resp.set_element_RequestAccessResponseBody(
548                pack_soap(resp, "RequestAccessResponseBody", msg))
549
550        return resp
551
552    def xmlrpc_RequestAccess(self, params, fid):
553        msg = self.RequestAccess(params[0], fedid)
554
555        if msg != None:
556            return xmlrpclib.dumps(({ "RequestAccessResponseBody": msg },))
557        else:
558            raise server_error("No response generated?!");
559
560    def read_trust(self, trust):
561        """
562        Read a trust file that splits fedids into testbeds, users or projects
563
564        Format is:
565
566        [type]
567        fedid
568        fedid
569        default: type
570        """
571        lineno = 0;
572        cat = None
573        cat_re = re.compile("\[(user|testbed|project)\]$", re.IGNORECASE)
574        fedid_re = re.compile("[" + string.hexdigits + "]+$")
575        default_re = re.compile("default:\s*(user|testbed|project)$", 
576                re.IGNORECASE)
577
578        f = open(trust, "r")
579        for line in f:
580            lineno += 1
581            line = line.strip()
582            if len(line) == 0 or line.startswith("#"):
583                continue
584            # Category line
585            m = cat_re.match(line)
586            if m != None:
587                cat = m.group(1).lower()
588                continue
589            # Fedid line
590            m = fedid_re.match(line)
591            if m != None:
592                if cat != None:
593                    self.fedid_category[fedid(hexstr=m.string)] = cat
594                else:
595                    raise fedd_proj.parse_error(\
596                            "Bad fedid in trust file (%s) line: %d" % \
597                            (trust, lineno))
598                continue
599            # default line
600            m = default_re.match(line)
601            if m != None:
602                self.fedid_default = m.group(1).lower()
603                continue
604            # Nothing matched - bad line, raise exception
605            f.close()
606            raise fedd_proj.parse_error(\
607                    "Unparsable line in trustfile %s line %d" % (trust, lineno))
608        f.close()
609
610    def read_config(self, config):
611        """
612        Read a configuration file and set internal parameters.
613
614        The format is more complex than one might hope.  The basic format is
615        attribute value pairs separated by colons(:) on a signle line.  The
616        attributes in bool_attrs, emulab_attrs and id_attrs can all be set
617        directly using the name: value syntax.  E.g.
618        boss: hostname
619        sets self.boss to hostname.  In addition, there are access lines of the
620        form (tb, proj, user) -> (aproj, auser) that map the first tuple of
621        names to the second for access purposes.  Names in the key (left side)
622        can include "<NONE> or <ANY>" to act as wildcards or to require the
623        fields to be empty.  Similarly aproj or auser can be <SAME> or
624        <DYNAMIC> indicating that either the matching key is to be used or a
625        dynamic user or project will be created.  These names can also be
626        federated IDs (fedid's) if prefixed with fedid:.  Finally, the aproj
627        can be followed with a colon-separated list of node types to which that
628        project has access (or will have access if dynamic).
629        Testbed attributes outside the forms above can be given using the
630        format attribute: name value: value.  The name is a single word and the
631        value continues to the end of the line.  Empty lines and lines startin
632        with a # are ignored.
633
634        Parsing errors result in a parse_error exception being raised.
635        """
636        lineno=0
637        name_expr = "["+string.ascii_letters + string.digits + "\.\-_]+"
638        fedid_expr = "fedid:[" + string.hexdigits + "]+"
639        key_name = "(<ANY>|<NONE>|"+fedid_expr + "|"+ name_expr + ")"
640        access_proj = "(<DYNAMIC>(?::" + name_expr +")*|"+ \
641                "<SAME>" + "(?::" + name_expr + ")*|" + \
642                fedid_expr + "(?::" + name_expr + ")*|" + \
643                name_expr + "(?::" + name_expr + ")*)"
644        access_name = "(<DYNAMIC>|<SAME>|" + fedid_expr + "|"+ name_expr + ")"
645
646        bool_re = re.compile('(' + '|'.join(fedd_proj.bool_attrs) + 
647                '):\s+(true|false)', re.IGNORECASE)
648        string_re = re.compile( "(" + \
649                '|'.join(fedd_proj.emulab_attrs + fedd_proj.id_attrs) + \
650                '):\s*(.*)', re.IGNORECASE)
651        attr_re = re.compile('attribute:\s*([\._\-a-z0-9]+)\s+value:\s*(.*)',
652                re.IGNORECASE)
653        access_re = re.compile('\('+key_name+'\s*,\s*'+key_name+'\s*,\s*'+
654                key_name+'\s*\)\s*->\s*\('+access_proj + '\s*,\s*' + 
655                access_name + '\s*\)', re.IGNORECASE)
656        trustfile_re = re.compile("trustfile:\s*(.*)", re.IGNORECASE)
657        restricted_re = re.compile("restricted:\s*(.*)", re.IGNORECASE)
658
659        def parse_name(n):
660            if n.startswith('fedid:'): return fedid(n[len('fedid:'):])
661            else: return n
662
663        f = open(config, "r");
664        for line in f:
665            lineno += 1
666            line = line.strip();
667            if len(line) == 0 or line.startswith('#'):
668                continue
669
670            # Boolean attribute line
671            m = bool_re.match(line);
672            if m != None:
673                attr, val = m.group(1,2)
674                setattr(self, attr.lower(), bool(val.lower() == "true"))
675                continue
676
677            # String attribute line
678            m = string_re.match(line)
679            if m != None:
680                attr, val = m.group(1,2)
681                setattr(self, attr.lower(), val)
682                continue
683
684            # Extended (attribute: x value: y) attribute line
685            m = attr_re.match(line)
686            if m != None:
687                attr, val = m.group(1,2)
688                self.attrs[attr] = val
689                continue
690
691            # Access line (t, p, u) -> (ap, au) line
692            m = access_re.match(line)
693            if m != None:
694                access_key = tuple([ parse_name(x) for x in m.group(1,2,3)])
695                aps = m.group(4).split(":");
696                if aps[0] == 'fedid:':
697                    del aps[0]
698                    aps[0] = fedid(hexstr=aps[0])
699
700                au = m.group(5)
701                if au.startswith("fedid:"):
702                    au = fedid(hexstr=aus[len("fedid:"):])
703
704                access_val = (fedd_proj.access_project(aps[0], aps[1:]), au)
705
706                self.access[access_key] = access_val
707                continue
708
709            # Trustfile inclusion
710            m = trustfile_re.match(line)
711            if m != None:
712                self.read_trust(m.group(1))
713                continue
714            # Restricted node types
715
716            m = restricted_re.match(line)
717            if m != None:
718                self.restricted.append(m.group(1))
719                continue
720
721            # Nothing matched to here: unknown line - raise exception
722            f.close()
723            raise fedd_proj.parse_error("Unknown statement at line %d of %s" % \
724                    (lineno, config))
725        f.close()
726
727    def soap_dispatch(self, method, req, fid):
728        if fedd_proj.soap_methods.has_key(method):
729            try:
730                return getattr(self, fedd_proj.soap_methods[method])(req, fid)
731            except fedd_proj.server_error, e:
732                de = ns0.faultType_Def((ns0.faultType_Def.schema,"RequestAccessFaultBody")).pyclass()
733                de._code=100
734                de._desc="temp"
735                f = Fault(Fault.Server, "Server Test", detail=de)
736                raise f
737            except fedd_proj.client_error, e:
738                raise Fault(Fault.Client, str(e))
739        else:
740            raise Fault(Fault.Client, "Unknown method: %s" % method)
741
742    def xmlrpc_dispatch(self, method, req, fid):
743        if fedd_proj.xmlrpc_methods.has_key(method):
744            try:
745                return getattr(self, fedd_proj.xmlrpc_methods[method])(req, fid)
746            except fedd_proj.server_error, e:
747                raise xmlrpclib.Fault("server", str(e))
748            except fedd_proj.client_error, e:
749                raise xmlrpclib.Fault("client", str(e))
750        else:
751            raise xmlrpclib.Fault(100, "Unknown method: %s" % method)
752
753def new_feddservice(configfile):
754    return fedd_proj(configfile)
Note: See TracBrowser for help on using the repository browser.