source: fedd/federation/access.py @ 8cf2b90e

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

Beginning cleanup of access controllers/plugins for general release. Separating function out to a base class and cleaning up some of the code. Removing all the proxy code, and much of the resources stuff in the access requests.

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