source: fedd/federation/access.py @ 027b87b

axis_examplecompt_changesinfo-ops
Last change on this file since 027b87b was 027b87b, checked in by Ted Faber <faber@…>, 13 years ago

This little class added a useless complexity. While I'm in here I removed it.

  • Property mode set to 100644
File size: 24.2 KB
Line 
1#!/usr/local/bin/python
2
3import os,sys
4import stat # for chmod constants
5import re
6import random
7import string
8import copy
9import pickle
10import logging
11import subprocess
12
13from threading import *
14from M2Crypto.SSL import SSLError
15
16from util import *
17from allocate_project import allocate_project_local, allocate_project_remote
18from fedid import fedid, generate_fedid
19from authorizer import authorizer
20from service_error import service_error
21from remote_service import xmlrpc_handler, soap_handler, service_caller
22
23import httplib
24import tempfile
25from urlparse import urlparse
26
27import topdl
28import list_log
29import proxy_emulab_segment
30import local_emulab_segment
31
32
33# Make log messages disappear if noone configures a fedd logger
34class nullHandler(logging.Handler):
35    def emit(self, record): pass
36
37fl = logging.getLogger("fedd.access")
38fl.addHandler(nullHandler())
39
40class access_base:
41    """
42    The implementation of access control based on mapping users to projects.
43
44    Users can be mapped to existing projects or have projects created
45    dynamically.  This implements both direct requests and proxies.
46    """
47
48    class parse_error(RuntimeError): pass
49
50    def __init__(self, config=None, auth=None):
51        """
52        Initializer.  Pulls parameters out of the ConfigParser's access section.
53        """
54
55        # Make sure that the configuration is in place
56        if not config: 
57            raise RunTimeError("No config to fedd.access")
58
59        self.project_priority = config.getboolean("access", "project_priority")
60
61        self.certdir = config.get("access","certdir")
62        self.create_debug = config.getboolean("access", "create_debug")
63        self.cleanup = not config.getboolean("access", "leave_tmpfiles")
64        self.access_type = config.get("access", "type")
65        self.log = logging.getLogger("fedd.access")
66        set_log_level(config, "access", self.log)
67        self.state_lock = Lock()
68        self.state = { }
69        # subclasses fill with what and how they export.
70        self.exports = { }
71        # XXX: Configurable
72        self.imports = set(('SMB', 'seer', 'userconfig', 'seer_master',
73            'hide_hosts'))
74
75        if auth: self.auth = auth
76        else:
77            self.log.error(\
78                    "[access]: No authorizer initialized, creating local one.")
79            auth = authorizer()
80
81        self.state_filename = config.get("access", "access_state")
82        self.read_state()
83
84        # Keep cert_file and cert_pwd coming from the same place
85        self.cert_file = config.get("access", "cert_file")
86        if self.cert_file:
87            self.cert_pwd = config.get("access", "cert_pw")
88        else:
89            self.cert_file = config.get("globals", "cert_file")
90            self.sert_pwd = config.get("globals", "cert_pw")
91
92        self.trusted_certs = config.get("access", "trusted_certs") or \
93                config.get("globals", "trusted_certs")
94
95
96    @staticmethod
97    def software_list(v):
98        """
99        From a string containing a sequence of space separated pairs, return a
100        list of tuples with pairs of location and file.
101        """
102        l = [ ]
103        if v:
104            ps = v.split(" ")
105            while len(ps):
106                loc, file = ps[0:2]
107                del ps[0:2]
108                l.append((loc, file))
109        return l
110
111    @staticmethod
112    def add_kit(e, kit):
113        """
114        Add a Software object created from the list of (install, location)
115        tuples passed as kit  to the software attribute of an object e.  We
116        do this enough to break out the code, but it's kind of a hack to
117        avoid changing the old tuple rep.
118        """
119
120        s = [ topdl.Software(install=i, location=l) for i, l in kit]
121
122        if isinstance(e.software, list): e.software.extend(s)
123        else: e.software = s
124
125
126    def read_access(self, config, access_obj=None):
127        """
128        Read an access DB with filename config  of the form:
129            (id, id, id) -> attribute, something
130        where the ids can be fedids, strings, or <any> or <none>, attribute is
131        the attribute to assign , and something is any set of charcters.  The
132        hash self.access is populated with mappings from those triples to the
133        results of access_obj being called on the remainder of the line (if
134        present).  If access_obj is not given, the string itself is entered in
135        the hash.  Additionally, a triple with <any> and <none> mapped to None
136        is entered in self.auth with the attribute given.
137
138        Parsing errors result in a self.parse_error exception being raised.
139        access_obj should throw that as well.
140        """
141        lineno=0
142        name_expr = "["+string.ascii_letters + string.digits + "\.\-_]+"
143        fedid_expr = "fedid:[" + string.hexdigits + "]+"
144        key_name = "(<ANY>|<NONE>|"+fedid_expr + "|"+ name_expr + ")"
145        access_re = re.compile('\('+key_name+'\s*,\s*'+key_name+'\s*,\s*'+
146                key_name+'\s*\)\s*->\s*([^,]+)\s*(.*)', re.IGNORECASE)
147
148        def parse_name(n):
149            if n.startswith('fedid:'): return fedid(hexstr=n[len('fedid:'):])
150            else: return n
151       
152        def auth_name(n):
153            if isinstance(n, basestring):
154                if n =='<any>' or n =='<none>': return None
155                else: return unicode(n)
156            else:
157                return n
158        def strip_comma(s):
159            s = s.strip()
160            if s.startswith(','):
161                s = s[1:].strip()
162            return s
163
164        if access_obj is None:
165            access_obj = lambda(x): "%s" % x
166
167        f = open(config, "r");
168        try:
169            for line in f:
170                lineno += 1
171                line = line.strip();
172                if len(line) == 0 or line.startswith('#'):
173                    continue
174
175                # Access line (t, p, u) -> anything
176                m = access_re.match(line)
177                if m != None:
178                    access_key = tuple([ parse_name(x) \
179                            for x in m.group(1,2,3)])
180                    attribute = m.group(4)
181                    auth_key = tuple([ auth_name(x) for x in access_key])
182                    self.auth.set_attribute(auth_key, attribute)
183                    if len(m.group(5)) > 0:
184                        access_val = access_obj(strip_comma(m.group(5)))
185                        self.access[access_key] = access_val
186                    continue
187
188                # Nothing matched to here: unknown line - raise exception
189                f.close()
190                raise self.parse_error(
191                        "Unknown statement at line %d of %s" % \
192                        (lineno, config))
193        finally:
194            if f: f.close()
195
196    def read_abac_access(self, fn, access_obj=None):
197        """
198        Read an access DB of the form
199            abac.attribute -> local_auth_data
200        The access dict is filled with mappings from the abac attributes (as
201        strings) to the access objects.  The objects are strings by default,
202        but the class constructor is called with the string following the ->
203        and whitespace in the file.
204        """
205
206        map_re = re.compile("(\S+)\s+->\s+(.*)");
207        if access_obj is None:
208            access_obj = lambda(x): "%s" % x
209
210        f = open(fn, 'r')
211        try:
212            lineno = 0
213            for line in f:
214                lineno += 1
215                line = line.strip();
216                if len(line) == 0 or line.startswith('#'):
217                    continue
218                m = map_re.match(line)
219                if m != None:
220                    self.access[m.group(1)] = access_obj(m.group(2))
221                    continue
222
223                # Nothing matched to here: unknown line - raise exception
224                # (finally will close f)
225                raise self.parse_error(
226                        "Unknown statement at line %d of %s" % \
227                        (lineno, fn))
228        finally:
229            if f: f.close()
230
231
232    def get_users(self, obj):
233        """
234        Return a list of the IDs of the users in dict
235        """
236        if obj.has_key('user'):
237            return [ unpack_id(u['userID']) \
238                    for u in obj['user'] if u.has_key('userID') ]
239        else:
240            return None
241
242    def write_state(self):
243        if self.state_filename:
244            try:
245                f = open(self.state_filename, 'w')
246                pickle.dump(self.state, f)
247                self.log.debug("Wrote state to %s" % self.state_filename)
248            except EnvironmentError, e:
249                self.log.error("Can't write file %s: %s" % \
250                        (self.state_filename, e))
251            except pickle.PicklingError, e:
252                self.log.error("Pickling problem: %s" % e)
253            except TypeError, e:
254                self.log.error("Pickling problem (TypeError): %s" % e)
255
256
257    def read_state(self):
258        """
259        Read a new copy of access state.  Old state is overwritten.
260
261        State format is a simple pickling of the state dictionary.
262        """
263        if self.state_filename:
264            try:
265                f = open(self.state_filename, "r")
266                self.state = pickle.load(f)
267                self.log.debug("[read_state]: Read state from %s" % \
268                        self.state_filename)
269            except EnvironmentError, e:
270                self.log.warning(("[read_state]: No saved state: " +\
271                        "Can't open %s: %s") % (self.state_filename, e))
272            except EOFError, e:
273                self.log.warning(("[read_state]: " +\
274                        "Empty or damaged state file: %s:") % \
275                        self.state_filename)
276            except pickle.UnpicklingError, e:
277                self.log.warning(("[read_state]: No saved state: " + \
278                        "Unpickling failed: %s") % e)
279
280
281
282    def permute_wildcards(self, a, p):
283        """Return a copy of a with various fields wildcarded.
284
285        The bits of p control the wildcards.  A set bit is a wildcard
286        replacement with the lowest bit being user then project then testbed.
287        """
288        if p & 1: user = ["<any>"]
289        else: user = a[2]
290        if p & 2: proj = "<any>"
291        else: proj = a[1]
292        if p & 4: tb = "<any>"
293        else: tb = a[0]
294
295        return (tb, proj, user)
296
297    def find_access(self, search):
298        """
299        Search the access DB for a match on this tuple.  Return the matching
300        access tuple and the user that matched.
301       
302        NB, if the initial tuple fails to match we start inserting wildcards in
303        an order determined by self.project_priority.  Try the list of users in
304        order (when wildcarded, there's only one user in the list).
305        """
306        if self.project_priority: perm = (0, 1, 2, 3, 4, 5, 6, 7)
307        else: perm = (0, 2, 1, 3, 4, 6, 5, 7)
308
309        for p in perm: 
310            s = self.permute_wildcards(search, p)
311            # s[2] is None on an anonymous, unwildcarded request
312            if s[2] != None:
313                for u in s[2]:
314                    if self.access.has_key((s[0], s[1], u)):
315                        return (self.access[(s[0], s[1], u)], u)
316            else:
317                if self.access.has_key(s):
318                    return (self.access[s], None)
319        return None, None
320
321    def lookup_access_base(self, req, fid):
322        """
323        Determine the allowed access for this request.  Return the access and
324        which fields are dynamic.
325
326        The fedid is needed to construct the request
327        """
328        user_re = re.compile("user:\s(.*)")
329        project_re = re.compile("project:\s(.*)")
330
331        # Search keys
332        tb = fid
333        user = [ user_re.findall(x)[0] for x in req.get('credential', []) \
334                if user_re.match(x)]
335        project = [ project_re.findall(x)[0] \
336                for x in req.get('credential', []) \
337                    if project_re.match(x)]
338
339        if len(project) == 1: project = project[0]
340        elif len(project) == 0: project = None
341        else: 
342            raise service_error(service_error.req, 
343                    "More than one project credential")
344
345        # Confirm authorization
346        for u in user:
347            self.log.debug("[lookup_access] Checking access for %s" % \
348                    ((tb, project, u),))
349            if self.auth.check_attribute((tb, project, u), 'access'):
350                self.log.debug("[lookup_access] Access granted")
351                break
352            else:
353                self.log.debug("[lookup_access] Access Denied")
354        else:
355            raise service_error(service_error.access, "Access denied")
356
357        # This maps a valid user to the Emulab projects and users to use
358        found, user_match = self.find_access((tb, project, user))
359
360        return (found, (tb, project, user_match))
361       
362
363    def get_handler(self, path, fid):
364        self.log.info("Get handler %s %s" % (path, fid))
365        if self.auth.check_attribute(fid, path) and self.userconfdir:
366            return ("%s/%s" % (self.userconfdir, path), "application/binary")
367        else:
368            return (None, None)
369
370    def export_userconf(self, project):
371        dev_null = None
372        confid, confcert = generate_fedid("test", dir=self.userconfdir, 
373                log=self.log)
374        conffilename = "%s/%s" % (self.userconfdir, str(confid))
375        cf = None
376        try:
377            cf = open(conffilename, "w")
378            os.chmod(conffilename, stat.S_IRUSR | stat.S_IWUSR)
379        except EnvironmentError, e:
380            raise service_error(service_error.internal, 
381                    "Cannot create user configuration data")
382
383        try:
384            dev_null = open("/dev/null", "a")
385        except EnvironmentError, e:
386            self.log.error("export_userconf: can't open /dev/null: %s" % e)
387
388        cmd = "%s %s" % (self.userconfcmd, project)
389        conf = subprocess.call(cmd.split(" "),
390                stdout=cf, stderr=dev_null, close_fds=True)
391
392        self.auth.set_attribute(confid, "/%s" % str(confid))
393
394        return confid, confcert
395
396    def export_SMB(self, id, state, project, user, attrs):
397        if project and user:
398            return [{ 
399                    'id': id,
400                    'name': 'SMB',
401                    'visibility': 'export',
402                    'server': 'http://fs:139',
403                    'fedAttr': [
404                            { 'attribute': 'SMBSHARE', 'value': 'USERS' },
405                            { 'attribute': 'SMBUSER', 'value': user },
406                            { 'attribute': 'SMBPROJ', 'value': project },
407                        ]
408                    }]
409        else:
410            self.log.warn("Cannot export SMB w/o user and project")
411            return [ ]
412
413    def export_seer(self, id, state, project, user, attrs):
414        return [{ 
415                'id': id,
416                'name': 'seer',
417                'visibility': 'export',
418                'server': 'http://control:16606',
419                }]
420
421    def export_local_seer(self, id, state, project, user, attrs):
422        return [{ 
423                'id': id,
424                'name': 'local_seer_control',
425                'visibility': 'export',
426                'server': 'http://control:16606',
427                }]
428
429    def export_seer_master(self, id, state, project, user, attrs):
430        return [{ 
431                'id': id,
432                'name': 'seer_master',
433                'visibility': 'export',
434                'server': 'http://seer-master:17707',
435                }]
436
437    def export_tmcd(self, id, state, project, user, attrs):
438        return [{ 
439                'id': id,
440                'name': 'seer',
441                'visibility': 'export',
442                'server': 'http://boss:7777',
443                }]
444
445    def export_userconfig(self, id, state, project, user, attrs):
446        if self.userconfdir and self.userconfcmd \
447                and self.userconfurl:
448            cid, cert = self.export_userconf(project)
449            state['userconfig'] = unicode(cid)
450            return [{
451                    'id': id,
452                    'name': 'userconfig',
453                    'visibility': 'export',
454                    'server': "%s/%s" % (self.userconfurl, str(cid)),
455                    'fedAttr': [
456                        { 'attribute': 'cert', 'value': cert },
457                    ]
458                    }]
459        else:
460            return [ ]
461
462    def export_hide_hosts(self, id, state, project, user, attrs):
463        return [{
464                'id': id, 
465                'name': 'hide_hosts',
466                'visibility': 'export',
467                'fedAttr': [ x for x in attrs \
468                        if x.get('attribute', "") == 'hosts'],
469                }]
470
471    def export_project_export(self, id, state, project, user, attrs):
472        rv = [ ]
473        rv.extend(self.export_SMB(id, state, project, user, attrs))
474        rv.extend(self.export_userconfig(id, state, project, user, attrs))
475        return rv
476
477    def export_services(self, sreq, project=None, user=None):
478        exp = [ ]
479        state = { }
480        for s in sreq:
481            sname = s.get('name', '')
482            svis = s.get('visibility', '')
483            sattrs = s.get('fedAttr', [])
484            if svis == 'export':
485                if sname in self.exports:
486                    id = s.get('id', 'no_id')
487                    exp.extend(self.exports[sname](id, state, project, user,
488                            sattrs))
489
490        return (exp, state)
491
492    def build_access_response(self, alloc_id, ap, services):
493        """
494        Create the SOAP response.
495
496        Build the dictionary description of the response and use
497        fedd_utils.pack_soap to create the soap message.  ap is the allocate
498        project message returned from a remote project allocation (even if that
499        allocation was done locally).
500        """
501        # Because alloc_id is already a fedd_services_types.IDType_Holder,
502        # there's no need to repack it
503        msg = { 
504                'allocID': alloc_id,
505                'fedAttr': [
506                    { 'attribute': 'domain', 'value': self.domain } , 
507                    { 'attribute': 'project', 'value': 
508                        ap['project'].get('name', {}).get('localname', "???") },
509                ]
510            }
511
512        if self.dragon_endpoint:
513            msg['fedAttr'].append({'attribute': 'dragon',
514                'value': self.dragon_endpoint})
515        if self.deter_internal:
516            msg['fedAttr'].append({'attribute': 'deter_internal',
517                'value': self.deter_internal})
518        #XXX: ??
519        if self.dragon_vlans:
520            msg['fedAttr'].append({'attribute': 'vlans',
521                'value': self.dragon_vlans})
522
523        if services:
524            msg['service'] = services
525        return msg
526
527    def generate_portal_configs(self, topo, pubkey_base, secretkey_base, 
528            tmpdir, lproj, leid, connInfo, services):
529
530        def conninfo_to_dict(key, info):
531            """
532            Make a cpoy of the connection information about key, and flatten it
533            into a single dict by parsing out any feddAttrs.
534            """
535
536            rv = None
537            for i in info:
538                if key == i.get('portal', "") or \
539                        key in [e.get('element', "") \
540                        for e in i.get('member', [])]:
541                    rv = i.copy()
542                    break
543
544            else:
545                return rv
546
547            if 'fedAttr' in rv:
548                for a in rv['fedAttr']:
549                    attr = a.get('attribute', "")
550                    val = a.get('value', "")
551                    if attr and attr not in rv:
552                        rv[attr] = val
553                del rv['fedAttr']
554            return rv
555
556        # XXX: un hardcode this
557        def client_null(f, s):
558            print >>f, "Service: %s" % s['name']
559
560        def client_seer_master(f, s):
561            print >>f, 'PortalAlias: seer-master'
562
563        def client_smb(f, s):
564            print >>f, "Service: %s" % s['name']
565            smbshare = None
566            smbuser = None
567            smbproj = None
568            for a in s.get('fedAttr', []):
569                if a.get('attribute', '') == 'SMBSHARE':
570                    smbshare = a.get('value', None)
571                elif a.get('attribute', '') == 'SMBUSER':
572                    smbuser = a.get('value', None)
573                elif a.get('attribute', '') == 'SMBPROJ':
574                    smbproj = a.get('value', None)
575
576            if all((smbshare, smbuser, smbproj)):
577                print >>f, "SMBshare: %s" % smbshare
578                print >>f, "ProjectUser: %s" % smbuser
579                print >>f, "ProjectName: %s" % smbproj
580
581        def client_hide_hosts(f, s):
582            for a in s.get('fedAttr', [ ]):
583                if a.get('attribute', "") == 'hosts':
584                    print >>f, "Hide: %s" % a.get('value', "")
585
586        client_service_out = {
587                'SMB': client_smb,
588                'tmcd': client_null,
589                'seer': client_null,
590                'userconfig': client_null,
591                'project_export': client_null,
592                'seer_master': client_seer_master,
593                'hide_hosts': client_hide_hosts,
594            }
595
596        def client_seer_master_export(f, s):
597            print >>f, "AddedNode: seer-master"
598
599        def client_seer_local_export(f, s):
600            print >>f, "AddedNode: control"
601
602        client_export_service_out = {
603                'seer_master': client_seer_master_export,
604                'local_seer_control': client_seer_local_export,
605            }
606
607        def server_port(f, s):
608            p = urlparse(s.get('server', 'http://localhost'))
609            print >>f, 'port: remote:%s:%s:%s' % (p.port, p.hostname, p.port) 
610
611        def server_null(f,s): pass
612
613        def server_seer(f, s):
614            print >>f, 'seer: True'
615
616        server_service_out = {
617                'SMB': server_port,
618                'tmcd': server_port,
619                'userconfig': server_null,
620                'project_export': server_null,
621                'seer': server_seer,
622                'seer_master': server_port,
623                'hide_hosts': server_null,
624            }
625        # XXX: end un hardcode this
626
627
628        seer_out = False
629        client_out = False
630        mproj = None
631        mexp = None
632        control_gw = None
633        testbed = ""
634        # Create configuration files for the portals
635        for e in [ e for e in topo.elements \
636                if isinstance(e, topdl.Computer) and e.get_attribute('portal')]:
637            myname = e.name
638            type = e.get_attribute('portal_type')
639
640            info = conninfo_to_dict(myname, connInfo)
641
642            if not info:
643                raise service_error(service_error.req,
644                        "No connectivity info for %s" % myname)
645
646            peer = info.get('peer', "")
647            ldomain = self.domain
648            ssh_port = info.get('ssh_port', 22)
649
650            # Collect this for the client.conf file
651            if 'masterexperiment' in info:
652                mproj, meid = info['masterexperiment'].split("/", 1)
653
654            if type in ('control', 'both'):
655                testbed = e.get_attribute('testbed')
656                control_gw = myname
657
658            active = info.get('active', 'False')
659
660            cfn = "%s/%s.gw.conf" % (tmpdir, myname.lower())
661            tunnelconfig = self.tunnel_config
662            try:
663                f = open(cfn, "w")
664                if active == 'True':
665                    print >>f, "active: True"
666                    print >>f, "ssh_port: %s" % ssh_port
667                    if type in ('control', 'both'):
668                        for s in [s for s in services \
669                                if s.get('name', "") in self.imports]:
670                            server_service_out[s['name']](f, s)
671
672                if tunnelconfig:
673                    print >>f, "tunnelip: %s" % tunnelconfig
674                print >>f, "peer: %s" % peer.lower()
675                print >>f, "ssh_pubkey: /proj/%s/exp/%s/tmp/%s" % \
676                        (lproj, leid, pubkey_base)
677                print >>f, "ssh_privkey: /proj/%s/exp/%s/tmp/%s" % \
678                        (lproj, leid, secretkey_base)
679                f.close()
680            except EnvironmentError, e:
681                raise service_error(service_error.internal,
682                        "Can't write protal config %s: %s" % (cfn, e))
683
684        # Done with portals, write the client config file.
685        try:
686            f = open("%s/client.conf" % tmpdir, "w")
687            if control_gw:
688                print >>f, "ControlGateway: %s.%s.%s%s" % \
689                    (myname.lower(), leid.lower(), lproj.lower(),
690                            ldomain.lower())
691            for s in services:
692                if s.get('name',"") in self.imports and \
693                        s.get('visibility','') == 'import':
694                    client_service_out[s['name']](f, s)
695                if s.get('name', '') in self.exports and \
696                        s.get('visibility', '') == 'export' and \
697                        s['name'] in client_export_service_out:
698                    client_export_service_out[s['name']](f, s)
699            # Seer uses this.
700            if mproj and meid:
701                print >>f, "ExperimentID: %s/%s" % (mproj, meid)
702            f.close()
703        except EnvironmentError, e:
704            raise service_error(service_error.internal,
705                    "Cannot write client.conf: %s" %s)
706
707    def configure_userconf(self, services, tmpdir):
708        """
709        If the userconf service was imported, collect the configuration data.
710        """
711        for s in services:
712            s_name = s.get('name', '')
713            s_vis = s.get('visibility','')
714            if s_name  == 'userconfig' and s_vis == 'import':
715                # Collect ther server and certificate info.
716                u = s.get('server', None)
717                for a in s.get('fedAttr', []):
718                    if a.get('attribute',"") == 'cert':
719                        cert = a.get('value', None)
720                        break
721                else:
722                    cert = None
723
724                if cert:
725                    # Make a temporary certificate file for get_url.  The
726                    # finally clause removes it whether something goes
727                    # wrong (including an exception from get_url) or not.
728                    try:
729                        tfos, tn = tempfile.mkstemp(suffix=".pem")
730                        tf = os.fdopen(tfos, 'w')
731                        print >>tf, cert
732                        tf.close()
733                        self.log.debug("Getting userconf info: %s" % u)
734                        get_url(u, tn, tmpdir, "userconf")
735                        self.log.debug("Got userconf info: %s" % u)
736                    except EnvironmentError, e:
737                        raise service_error(service.error.internal, 
738                                "Cannot create temp file for " + 
739                                "userconfig certificates: %s" % e)
740                    except:
741                        t, v, st = sys.exc_info()
742                        raise service_error(service_error.internal,
743                                "Error retrieving %s: %s" % (u, v))
744                    finally:
745                        if tn: os.remove(tn)
746                else:
747                    raise service_error(service_error.req,
748                            "No certificate for retreiving userconfig")
749                break
750
751    def import_store_info(self, cf, connInfo):
752        """
753        Pull any import parameters in connInfo in.  We translate them either
754        into known member names or fedAddrs.
755        """
756
757        for c in connInfo:
758            for p in [ p for p in c.get('parameter', []) \
759                    if p.get('type', '') == 'input']:
760                name = p.get('name', None)
761                key = p.get('key', None)
762                store = p.get('store', None)
763
764                if name and key and store :
765                    req = { 'name': key, 'wait': True }
766                    self.log.debug("Waiting for %s (%s) from %s" % \
767                            (name, key, store))
768                    r = self.call_GetValue(store, req, cf)
769                    r = r.get('GetValueResponseBody', None)
770                    if r :
771                        if r.get('name', '') == key:
772                            v = r.get('value', None)
773                            if v is not None:
774                                if name == 'peer':
775                                    self.log.debug("Got peer %s" % v)
776                                    c['peer'] = v
777                                else:
778                                    self.log.debug("Got %s %s" % (name, v))
779                                    if c.has_key('fedAttr'):
780                                        c['fedAttr'].append({
781                                            'attribute': name, 'value': v})
782                                    else:
783                                        c['fedAttr']= [{
784                                            'attribute': name, 'value': v}]
785                            else:
786                                raise service_error(service_error.internal, 
787                                        'None value exported for %s'  % key)
788                        else:
789                            raise service_error(service_error.internal, 
790                                    'Different name returned for %s: %s' \
791                                            % (key, r.get('name','')))
792                    else:
793                        raise service_error(service_error.internal, 
794                            'Badly formatted response: no GetValueResponseBody')
795                else:
796                    raise service_error(service_error.internal, 
797                        'Bad Services missing info for import %s' % c)
798
799    def remove_dirs(self, dir):
800        """
801        Remove the directory tree and all files rooted at dir.  Log any errors,
802        but continue.
803        """
804        self.log.debug("[removedirs]: removing %s" % dir)
805        try:
806            for path, dirs, files in os.walk(dir, topdown=False):
807                for f in files:
808                    os.remove(os.path.join(path, f))
809                for d in dirs:
810                    os.rmdir(os.path.join(path, d))
811            os.rmdir(dir)
812        except EnvironmentError, e:
813            self.log.error("Error deleting directory tree in %s" % e);
Note: See TracBrowser for help on using the repository browser.