source: fedd/federation/allocate_project.py @ c3d5d53

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

Cleanup. Remove fixed stuff from allocation.

  • Property mode set to 100644
File size: 23.7 KB
Line 
1#!/usr/local/bin/python
2
3import os,sys
4import re
5import random
6import string
7import subprocess
8import threading
9import pickle
10import tempfile
11
12from util import *
13from fedid import fedid
14from remote_service import xmlrpc_handler, soap_handler, service_caller
15from service_error import service_error
16import logging
17
18
19# Configure loggers to dump to /dev/null which avoids errors if calling classes
20# don't configure them.
21class nullHandler(logging.Handler):
22    def emit(self, record): pass
23
24fl = logging.getLogger("fedd.allocate.local")
25fl.addHandler(nullHandler())
26fl = logging.getLogger("fedd.allocate.remote")
27fl.addHandler(nullHandler())
28
29
30class allocate_project_local:
31    """
32    Allocate projects on this machine in response to an access request.
33    """
34    dynamic_projects = 4
35    dynamic_keys= 2
36    confirm_keys = 1
37    none = 0
38
39    levels = {
40            'dynamic_projects': dynamic_projects,
41            'dynamic_keys': dynamic_keys,
42            'confirm_keys': confirm_keys,
43            'none': none,
44    }
45
46    def __init__(self, config, auth=None):
47        """
48        Initializer.  Parses a configuration if one is given.
49        """
50
51        self.debug = config.getboolean("allocate", "debug", False)
52        self.wap = config.get('allocate', 'wap', '/usr/testbed/sbin/wap')
53        self.newproj = config.get('allocate', 'newproj',
54                '/usr/testbed/sbin/newproj')
55        self.mkproj = config.get('allocate', 'mkproj', 
56                '/usr/testbed/sbin/mkproj')
57        self.rmproj = config.get('allocate', 'rmproj',
58                '/usr/testbed/sbin/rmproj')
59        self.rmuser = config.get('allocate', 'rmuser',
60                '/usr/testbed/sbin/rmuser')
61        self.newuser = config.get('allocate', 'newuser',
62                '/usr/testbed/sbin/newuser')
63        self.addpubkey = config.get('allocate', 'addpubkey', 
64                '/usr/testbed/sbin/addpubkey')
65        self.grantnodetype = config.get('allocate', 'grantnodetype', 
66                '/usr/testbed/sbin/grantnodetype')
67        self.confirmkey = config.get('allocate', 'confirmkey', 
68                '/usr/testbed/sbin/taddpubkey')
69        self.user_to_project=config.get("allocate", 'user_to_project',
70                '/usr/local/bin/user_to_project.py')
71        self.allocation_level = config.get("allocate", "allocation_level", 
72                "none")
73        self.log = logging.getLogger("fedd.allocate.local")
74        set_log_level(config, "allocate", self.log)
75
76        if auth:
77            self.auth = auth
78        else:
79            auth = authorizer()
80            log.warn("[allocate] No authorizer passed in, using local one")
81
82        try:
83            self.allocation_level = \
84                    self.levels[self.allocation_level.strip().lower()]
85        except KeyError:
86            self.log.error("Bad allocation_level %s.  Defaulting to none" % \
87                    self.allocation_error)
88            self.allocation_level = self.none
89
90        self.state = { 
91                'keys': set(), 
92                'types': set(),
93                'projects': set(),
94                'users': set(),
95                }
96        self.state_filename = config.get('allocate', 'allocation_state')
97        self.state_lock = threading.Lock()
98        self.read_state()
99
100        access_db = config.get("allocate", "accessdb")
101        if access_db:
102            try:
103                read_simple_accessdb(access_db, self.auth, 'allocate')
104            except IOError, e:
105                raise service_error(service_error.internal,
106                        "Error reading accessDB %s: %s" % (access_db, e))
107            except ValueError:
108                raise service_error(service_error.internal, "%s" % e)
109
110
111        # Internal services are SOAP only
112        self.soap_services = {\
113                "AllocateProject": soap_handler("AllocateProject", 
114                    self.dynamic_project),
115                "StaticProject": soap_handler("StaticProject", 
116                    self.static_project),
117                "ReleaseProject": soap_handler("ReleaseProject", 
118                    self.release_project),
119                }
120        self.xmlrpc_services = { }
121
122    def read_state(self):
123        """
124        Read a new copy of access state.  Old state is overwritten.
125
126        State format is a simple pickling of the state dictionary.
127        """
128        if self.state_filename:
129            try:
130                f = open(self.state_filename, "r")
131                self.state = pickle.load(f)
132                self.log.debug("[allocation]: Read state from %s" % \
133                        self.state_filename)
134            except IOError, e:
135                self.log.warning(("[allocation]: No saved state: " +\
136                        "Can't open %s: %s") % (self.state_filename, e))
137            except EOFError, e:
138                self.log.warning(("[allocation]: " +\
139                        "Empty or damaged state file: %s:") % \
140                        self.state_filename)
141            except pickle.UnpicklingError, e:
142                self.log.warning(("[allocation]: No saved state: " + \
143                        "Unpickling failed: %s") % e)
144            # These should all be in the picked representation, but make sure
145            if not self.state.has_key('keys'): self.state['keys'] = set()
146            if not self.state.has_key('types'): self.state['types'] = set()
147            if not self.state.has_key('projects'):
148                self.state['projects'] = set()
149            if not self.state.has_key('users'): self.state['users'] = set()
150
151    def write_state(self):
152        if self.state_filename:
153            try:
154                f = open(self.state_filename, 'w')
155                pickle.dump(self.state, f)
156            except IOError, e:
157                self.log.error("Can't write file %s: %s" % \
158                        (self.state_filename, e))
159            except pickle.PicklingError, e:
160                self.log.error("Pickling problem: %s" % e)
161            except TypeError, e:
162                self.log.error("Pickling problem (TypeError): %s" % e)
163
164
165    def random_string(self, s, n=3):
166        """Append n random ASCII characters to s and return the string"""
167        rv = s
168        for i in range(0,n):
169            rv += random.choice(string.ascii_letters)
170        return rv
171
172    def write_attr_xml(self, file, root, lines):
173        """
174        Write an emulab config file for a dynamic project.
175
176        Format is <root><attribute name=lines[0]>lines[1]</attribute></root>
177        """
178        # Convert a pair to an attribute line
179        out_attr = lambda a,v : \
180                '<attribute name="%s"><value>%s</value></attribute>' % (a, v)
181
182        f = os.fdopen(file, "w")
183        f.write("<%s>\n" % root)
184        f.write("\n".join([out_attr(*l) for l in lines]))
185        f.write("</%s>\n" % root)
186        f.close()
187
188    def run_cmd(self, cmd, log_prefix='allocate'):
189        """
190        Run the command passed in.  Cmd is a list containing the words of the
191        command.  Return the exit value from the subprocess - that is 0 on
192        success.  On an error running the command -  python or OS error, raise
193        a service exception.
194        """
195        self.log.debug("[%s]: %s" % (log_prefix, ' '.join(cmd)))
196        if not self.debug:
197            try:
198                return subprocess.call(cmd)
199            except OSError, e:
200                raise service_error(service_error.internal,
201                        "Static project subprocess creation error "+ \
202                                "[%s] (%s)" %  (cmd[0], e.strerror))
203        else:
204            return 0
205
206    def confirm_key(self, user, key):
207        """
208        Call run_cmd to comfirm the key.  Return a boolean rather
209        than the subprocess code.
210        """
211        return self.run_cmd((self.wap, self.confirmkey, '-C', 
212            '-u', user, '-k', key)) ==0
213
214    def add_key(self, user, key):
215        """
216        Call run_cmd to add the key.  Return a boolean rather
217        than the subprocess code.
218        """
219        return self.run_cmd((self.wap, self.addpubkey, '-u', user,
220            '-k', key)) == 0
221
222    def remove_key(self, user, key):
223        """
224        Call run_cmd to remove the key.  Return a boolean rather
225        than the subprocess code.
226        """
227        return self.run_cmd((self.wap, self.addpubkey, '-R', '-u', user, 
228            '-k', key)) == 0
229
230    def confirm_access(self, project, type):
231        """
232        Call run_cmd to comfirm the key.  Return a boolean rather
233        than the subprocess code.
234        """
235        return self.run_cmd((self.wap, self.grantnodetype, '-C', 
236            '-p', project, type)) ==0
237
238    def add_access(self, project, type):
239        """
240        Call run_cmd to add the key.  Return a boolean rather
241        than the subprocess code.
242        """
243        return self.run_cmd((self.wap, self.grantnodetype, 
244            '-p', project, type)) == 0
245
246    def remove_access(self, project, type):
247        """
248        Call run_cmd to remove the key.  Return a boolean rather
249        than the subprocess code.
250        """
251
252        return self.run_cmd((self.wap, self.grantnodetype, '-R', 
253            '-p', project, type)) == 0
254
255    def add_project(self, project, projfile):
256        """
257        Create a project using run_cmd.  This is two steps, and assumes that
258        the relevant XML files are in place and correct.  Make the return value
259        boolean.  Note that if a new user is specified in the XML, that user is
260        created on success.
261        """
262
263        if self.run_cmd((self.wap, self.newproj, projfile)) == 0:
264            return self.run_cmd((self.wap, self.mkproj, project)) ==0
265        else:
266            return False
267
268    def remove_project(self, project):
269        """
270        Call run_cmd to remove the project.  Make the return value boolean.
271        """
272
273        return self.run_cmd(self.wap, self.rmproj, project) == 0
274
275   
276    def add_user(self, name, param_file, project):
277        """
278        Create a user and link them to the given project.  Similar to
279        add_project, this requires a two step approach.  Returns True on success
280        False on failure.
281        """
282
283        if self.run_cmd((self.wap, self.newuser, param_file)) == 0:
284           return self.run_cmd((self.wap, self.user_to_project,
285               user, project)) == 0
286        else:
287           return False
288
289    def remove_user(self, user):
290        """
291        Call run_cmd to remove the user.  Make the return value boolean.
292        """
293
294        return self.run_cmd(self.wap, self.rmuser, user) == 0
295
296
297
298    def dynamic_project(self, req, fedid=None):
299        """
300        Create a dynamic project with ssh access
301
302        Req includes the project and resources as a dictionary
303        """
304
305        # Internal calls do not have a fedid parameter (i.e., local calls on
306        # behalf of already vetted fedids)
307        if fedid and not self.auth.check_attribute(fedid, "allocate"):
308            self.log.debug("[allocate] Access denied (%s)" % fedid)
309            raise service_error(service_error.access, "Access Denied")
310
311        if self.allocation_level < self.dynamic_projects:
312            raise service_error(service_error.access, 
313                    "[dynamic_project] dynamic project allocation not " + \
314                            "permitted: check allocation level")
315        # tempfiles for the parameter files
316        cuf, create_userfile = tempfile.mkstemp(prefix="usr", suffix=".xml",
317                dir="/tmp")
318        suf, service_userfile = tempfile.mkstemp(prefix="usr", suffix=".xml",
319                dir="/tmp")
320        pf, projfile = tempfile.mkstemp(prefix="proj", suffix=".xml",
321                dir="/tmp")
322
323        if req.has_key('AllocateProjectRequestBody'):
324            proj = req['AllocateProjectRequestBody'].get('project', None)
325            if not proj:
326                raise service_error(service_error.req, 
327                        "Badly formed allocation request")
328            resources = req['AllocateProjectRequestBody'].get('resources', { })
329        else:
330            raise service_error(service_error.req, 
331                    "Badly formed allocation request")
332        # Take the first user and ssh key
333        name = proj.get('name', None) or self.random_string("proj",4)
334        user = proj.get('user', [])
335
336        uname = { }
337        ssh = { }
338        for u in user:
339            role = u.get('role', None)
340            if not role: continue
341            if u.has_key('userID'):
342                uid = u['userID']
343                uname[role] = uid.get('localname', None) or \
344                        uid.get('kerberosUsername', None) or \
345                        uid.get('uri', None)
346                if uname[role] == None:
347                    raise service_error(service_error.req, "No ID for user")
348            else:
349                uname[role] = self.random_string("user", 3)
350
351            access = u.get('access', None)
352            if access:
353                # XXX collect and call addpubkey later, for now use first one.
354                for a in access:
355                    ssh[role] = a.get('sshPubkey', None)
356                    if ssh: break
357                else:
358                    raise service_error(service_error.req,
359                            "No SSH key for user %s" % uname[role])
360            else:
361                raise service_error(service_error.req,
362                        "No access mechanisms for for user %s" % uname[role])
363
364        if not (uname.has_key('experimentCreation') and \
365                uname.has_key('serviceAccess')):
366            raise service_error(service_error.req,
367                    "Must specify both user roles")
368       
369
370        create_user_fields = [
371                ("name", "Federation User %s" % uname['experimentCreation']),
372                ("email", "%s-fed@isi.deterlab.net" % \
373                        uname['experimentCreation']),
374                ("password", self.random_string("", 8)),
375                ("login", uname['experimentCreation']),
376                ("address", "4676 Admiralty"),
377                ("city", "Marina del Rey"),
378                ("state", "CA"),
379                ("zip", "90292"),
380                ("country", "USA"),
381                ("phone", "310-448-9190"),
382                ("title", "None"),
383                ("affiliation", "USC/ISI"),
384                ("pubkey", ssh['experimentCreation'])
385        ]
386
387        service_user_fields = [
388                ("name", "Federation User %s" % uname['serviceAccess']),
389                ("email", "%s-fed@isi.deterlab.net" % uname['serviceAccess']),
390                ("password", self.random_string("", 8)),
391                ("login", uname['serviceAccess']),
392                ("address", "4676 Admiralty"),
393                ("city", "Marina del Rey"),
394                ("state", "CA"),
395                ("zip", "90292"),
396                ("country", "USA"),
397                ("phone", "310-448-9190"),
398                ("title", "None"),
399                ("affiliation", "USC/ISI"),
400                ("pubkey", ssh['serviceAccess'])
401        ]
402
403        proj_fields = [
404                ("name", name),
405                ("short description", "dynamic federated project"),
406                ("URL", "http://www.isi.edu/~faber"),
407                ("funders", "USC/USU"),
408                ("long description", "Federation access control"),
409                ("public", "1"),
410                ("num_pcs", "100"),
411                ("linkedtous", "1"),
412                ("newuser_xml", create_userfile)
413        ]
414       
415
416
417        added_projects = [ ]
418        added_users = [ ]
419        added_types = [ ]
420
421        self.state_lock.acquire()
422        try:
423            # Write out the files
424            self.write_attr_xml(cuf, "user", create_user_fields)
425            self.write_attr_xml(suf, "user", service_user_fields)
426            self.write_attr_xml(pf, "project", proj_fields)
427            try:
428                if self.add_project(name, projfile):
429                    # add_project adds a user as well in this case
430                    added_projects.append(name)
431                    added_users.append(uname['createExperiment'])
432                    self.state['projects'].add(name)
433                    self.state['users'].add(uname['createExperiment'])
434
435                    if self.add_user(uname['serviceAccess'], 
436                            service_userfile, name):
437                        added_users.append(uname['serviceAccess'])
438                        self.state['users'].add(uname['serviceAccess'])
439                    else:
440                        raise service_error("Unable to create user %s" % \
441                                uname['serviceAccess'])
442                else:
443                    raise service_error("Unable to create project/user %s/%s" % \
444                            (name, uname['experimentCreation']))
445
446                nodes = resources.get('node', [])
447                # Grant access to restricted resources.  This is simpler than
448                # the corresponding loop from static_project because this is a
449                # clean slate.
450                for nt in [ h for n in nodes\
451                        if n.has_key('hardware')\
452                            for h in n['hardware'] ] :
453                    if self.add_access(name, nt):
454                        self.state['types'].add((name, nt))
455                        added_types.append((name, nt))
456                    else:
457                        raise service_error(service_error.internal,
458                                "Failed to add access for %s to %s"\
459                                        % (name, nt))
460            except service_error, e:
461                # Something failed.  Back out the partial allocation as
462                # completely as possible and re-raise the error.
463                for p, t in added_types:
464                    self.state['types'].discard((p, t))
465                    try:
466                        self.remove_access(p, t)
467                    except service_error:
468                        pass
469                for u in added_users:
470                    self.state['users'].discard(u)
471                    try:
472                        self.remove_user(u)
473                    except service_error:
474                        pass
475
476                for p in added_projects:
477                    self.state['projects'].discard(p)
478                    try:
479                        self.remove_project(p)
480                    except service_error:
481                        pass
482                self.state_lock.release()
483                raise e
484        finally:
485            # Clean up tempfiles
486            os.unlink(create_userfile)
487            os.unlink(service_userfile)
488            os.unlink(projfile)
489
490        rv = {\
491            'project': {\
492                'name': { 'localname': name }, 
493                'user' : [\
494                    {\
495                        'userID': { 'localname' : uname['experimentCreation'] },
496                        'access': [ {'sshPubkey': ssh['experimentCreation'] } ],
497                        'role': 'experimentCreation',
498                    }, \
499                    {\
500                        'userID': { 'localname' : uname['serviceAccess'] },
501                        'access': [ { 'sshPubkey' : ssh['serviceAccess'] } ], 
502                        'role': 'serviceAccess',
503                    } \
504                ]\
505            }\
506        }
507        return rv
508
509    def static_project(self, req, fedid=None):
510        """
511        Be certain that the local project in the request has access to the
512        proper resources and users have correct keys.  Add them if necessary.
513        """
514        # Internal calls do not have a fedid parameter (i.e., local calls on
515        # behalf of already vetted fedids)
516        if fedid and not self.auth.check_attribute(fedid, "allocate"):
517            self.log.debug("[allocate] Access denied (%s)" % fedid)
518            raise service_error(service_error.access, "Access Denied")
519        # While we should be more careful about this, for the short term, add
520        # the keys to the specified users.
521
522        try:
523            users = req['StaticProjectRequestBody']['project']['user']
524            pname = req['StaticProjectRequestBody']['project']\
525                    ['name']['localname']
526            resources = req['StaticProjectRequestBody'].get('resources', { })
527        except KeyError:
528            raise service_error(service_error.req, "Badly formed request")
529
530        added_keys = [ ]
531        added_types = [ ]
532        # Keep track of changes made to the system
533        self.state_lock.acquire()
534
535        try:
536            for u in users:
537                try:
538                    name = u['userID']['localname']
539                except KeyError:
540                    raise service_error(service_error.req, "Badly formed user")
541                for sk in [ k['sshPubkey'] for k in u.get('access', []) \
542                        if k.has_key('sshPubkey')]:
543                    if self.allocation_level >=self.confirm_keys:
544                        key_ok = self.confirm_key(name, sk)
545                        if not key_ok:
546                            if self.allocation_level >= self.dynamic_keys:
547                                if self.add_key(name, sk):
548                                    self.state['keys'].add((name, sk))
549                                    added_keys.append((name, sk))
550                                else:
551                                    raise service_error(service_error.internal,
552                                            "Failed to add key for %s" % name)
553                            else:
554                                raise service_error(service_error.internal,
555                                        "Failed to confirm key for %s" % name)
556                    else:
557                        self.log.warning("[static_project] no checking of " + \
558                            "static keys")
559
560            # Grant access to any resources in the request.  The
561            # list comprehension pulls out the hardware types in the node
562            # entries in the resources list.  The access module knows to
563            # only send resources that are restricted and needed by the
564            # project.
565            nodes = resources.get('node', [])
566            for nt in [ h for n in nodes\
567                    if n.has_key('hardware')\
568                        for h in n['hardware'] ] :
569                if self.allocation_level >= self.confirm_keys:
570                    access_ok = self.confirm_access(pname, nt)
571                    if not access_ok:
572                        if self.allocation_level >= self.dynamic_keys:
573                            if self.add_access(pname, nt):
574                                self.state['types'].add((pname, nt))
575                                added_types.append((pname, nt))
576                            else:
577                                raise service_error(service_error.internal,
578                                        "Failed to add access for %s to %s"\
579                                                % (pname, nt))
580                        else:
581                            raise service_error(service_error.internal,
582                                    "Failed to confirm access for %s to %s"\
583                                            % (pname, nt))
584                else:
585                    self.log.warning("[static_project] no checking of " + \
586                        "node access")
587        except service_error, e:
588            # Do our best to clean up partial allocation and reraise the
589            # error.  Do our best to make sure that both allocation state and
590            # testbed state is restored.
591            for u, k in added_keys:
592                self.state['keys'].discard((u, k))
593                try:
594                    self.remove_key(u, k)
595                except service_error:
596                    pass
597            for p, t in added_types:
598                self.state['types'].discard((p, t))
599                try:
600                    self.remove_access(p, t)
601                except service_error:
602                    pass
603            self.state_lock.release()
604            raise e
605        # All is well, save state and release the lock
606        self.write_state()
607        self.state_lock.release()
608        # return { 'project': req['StaticProjectRequestBody']['project']}
609        return req['StaticProjectRequestBody']
610
611    def release_project(self, req, fedid=None):
612        """
613        Remove user keys from users and delete dynamic projects.
614
615        Only keys this service created are deleted and there are
616        similar protections for projects.
617        """
618        # Internal calls do not have a fedid parameter (i.e., local calls on
619        # behalf of already vetted fedids)
620        if fedid and not self.auth.check_attribute(fedid, "allocate"):
621            self.log.debug("[allocate] Access denied (%s)" % fedid)
622            raise service_error(service_error.access, "Access Denied")
623
624        pname = None
625        users = []
626        nodes = [ ]
627
628        print req
629
630        try:
631            if req['ReleaseProjectRequestBody']['project'].has_key('name'):
632                pname = req['ReleaseProjectRequestBody']['project']\
633                        ['name']['localname']
634            if req['ReleaseProjectRequestBody']['project'].has_key('user'):
635                users = req['ReleaseProjectRequestBody']['project']['user']
636            if req['ReleaseProjectRequestBody'].has_key('resources'):
637                nodes = req['ReleaseProjectRequestBody']\
638                        ['resources'].get('node', [])
639        except KeyError:
640            raise service_error(service_error.req, "Badly formed request")
641
642        if nodes and not pname:
643            raise service_error(service_error.req, 
644                    "Badly formed request (nodes without project)")
645
646        self.state_lock.acquire()
647        try:
648            for nt in [ h for n in nodes if n.has_key('hardware')\
649                    for h in n['hardware'] ] :
650                if (pname, nt ) in self.state['types']:
651                    self.remove_access(pname, nt)
652                    self.state['types'].discard((pname, nt))
653
654            for u in users:
655                try:
656                    name = u['userID']['localname']
657                except KeyError:
658                    raise service_error(service_error.req, "Badly formed user")
659                if name in self.state['users']:
660                    # If we created this user, discard the user, keys and all
661                    self.remove_user(name)
662                    self.state['users'].discard(name)
663                else:
664                    # If not, just strip any keys we added
665                    for sk in [ k['sshPubkey'] for k in u.get('access', []) \
666                            if k.has_key('sshPubkey')]:
667                        if (name, sk) in self.state['keys']:
668                            self.remove_key(name, sk)
669                            self.state['keys'].discard((name, sk))
670            if pname in self.state['projects']:
671                self.remove_project(pname)
672                self.state['projects'].discard(pname)
673
674        except service_error, e:
675            self.write_state()
676            self.state_lock.release()
677            raise e
678        self.write_state()
679        self.state_lock.release()
680
681        return { 'project': req['ReleaseProjectRequestBody']['project']}
682
683class allocate_project_remote:
684    """
685    Allocate projects on a remote machine using the internal SOAP interface
686    """
687    class proxy(service_caller):
688        """
689        This class is a proxy functor (callable) that has the same signature as
690        a function called by soap_handler or xmlrpc_handler, but that used the
691        service_caller class to call the function remotely.
692        """
693
694        def __init__(self, url, cert_file, cert_pwd, trusted_certs, auth, 
695                method):
696            service_caller.__init__(self, method)
697            self.url = url
698            self.cert_file = cert_file
699            self.cert_pwd = cert_pwd
700            self.trusted_certs = trusted_certs
701            self.request_body__name = "%sRequestBody" % method
702            self.resp_name = "%sResponseBody" % method
703            self.auth = auth
704            # Calling the proxy object directly invokes the proxy_call method,
705            # not the service_call method.
706            self.__call__ = self.proxy_call
707           
708
709        # Define the proxy, NB, the parameters to make_proxy are visible to the
710        # definition of proxy.
711        def proxy_call(self, req, fid=None):
712            """
713            Send req on to a remote project instantiator.
714
715            Req is just the message to be sent.  This function re-wraps it.
716            It also rethrows any faults.
717            """
718
719            if req.has_key(self.request_body_name):
720                req = req[self.request_body_name]
721            else:
722                raise service_error(service_error.req, "Bad formated request");
723
724            try:
725                r = self.call_service(self.url, req, self.cert_file,
726                        self.cert_pwd, self.trusted_certs)
727            except service_error, e:
728                if e.code == service_error.connect:
729                    raise service_error(service_error.internal, 
730                            "Cannot connect to internal service: (%d) %s" % \
731                                    (e.code, e.desc))
732                else: raise
733            if r.has_key(self.resp_name):
734                return r[self.resp_name]
735            else:
736                raise service_error(service_error.protocol, 
737                        "Bad proxy response")
738
739    # back to defining the allocate_project_remote class
740    def __init__(self, config, auth=None):
741        """
742        Initializer.  Parses a configuration if one is given.
743        """
744
745        self.debug = config.get("allocate", "debug", False)
746        self.url = config.get("allocate", "uri", "")
747
748        # Keep cert file and password coming from the same source
749        self.cert_file = config.get("allocate", "cert_file", None)
750        if self.cert_file:
751            self.cert_pwd = config.get("allocate", "cert_pwd", None)
752        else:
753            self.cert_file = config.get("globals", "cert_file", None)
754            self.cert_pwd = config.get("globals", "cert_pwd", None)
755
756        self.trusted_certs = config.get("allocate", "trusted_certs", None) or \
757                config.get("globals", "trusted_certs")
758
759        self.soap_services = { }
760        self.xmlrpc_services = { }
761        self.log = logging.getLogger("fedd.allocate.remote")
762        set_log_level(config, "allocate", self.log)
763
764        if auth:
765            self.auth = auth
766        else:
767            auth = authorizer()
768            log.warn("[allocate] No authorizer passed in, using local one")
769
770        # The specializations of the proxy functions
771        self.dynamic_project = self.proxy(self.url, self.cert_file, 
772                self.cert_pwd, self.trusted_certs, self.auth, 
773                "AllocateProject")
774        self.static_project = self.proxy(self.url, self.cert_file, 
775                self.cert_pwd, self.trusted_certs, self.auth, 
776                "StaticProject")
777        self.release_project = self.proxy(self.url, self.cert_file,
778                self.cert_pwd, self.trusted_certs, self.auth, 
779                "ReleaseProject")
780
Note: See TracBrowser for help on using the repository browser.