Changeset e02cd14


Ignore:
Timestamp:
Feb 12, 2010 11:30:56 AM (14 years ago)
Author:
Ted Faber <faber@…>
Branches:
axis_example, compt_changes, info-ops, master, version-3.01, version-3.02
Children:
eeb0088
Parents:
8139a48
Message:

Big hunk of the move to services and connectivity descriptors.

Config files are now generated from those params rather than from attributes on topdl nodes (mostly).

This is still quick and dirty in places.

Location:
fedd/federation
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • fedd/federation/emulab_access.py

    r8139a48 re02cd14  
    100100        set_log_level(config, "access", self.log)
    101101        self.state_lock = Lock()
     102        # XXX: Configurable
     103        self.exports = set(('SMB', 'seer', 'tmcd'))
     104        self.imports = set(('SMB', 'seer', 'tmcd'))
    102105
    103106        if auth: self.auth = auth
     
    485488                owners
    486489
    487     def build_response(self, alloc_id, ap):
     490    def export_services(self, sreq, project, user):
     491        exp = [ ]
     492        # XXX: Filthy shortcut here using http so urlparse will give the right
     493        # answers.
     494        for s in sreq:
     495            sname = s.get('name', '')
     496            svis = s.get('visibility', '')
     497            if svis == 'export':
     498                if sname in self.exports:
     499                    outs = s.copy()
     500                    if sname == 'SMB':
     501                        outs = s.copy()
     502                        outs['server'] = "http://fs:139"
     503                        outs['fedAttr'] = [
     504                                { 'attribute': 'SMBSHARE', 'value': 'USERS' },
     505                                { 'attribute': 'SMBUSER', 'value': user },
     506                                { 'attribute': 'SMBPROJ', 'value': project },
     507                            ]
     508                    elif sname == 'seer':
     509                        outs['server'] = "http://control:16606"
     510                    elif sname == 'tmcd':
     511                        outs['server'] = "http://boss:7777"
     512                    exp.append(outs)
     513        return exp
     514
     515    def build_response(self, alloc_id, ap, services):
    488516        """
    489517        Create the SOAP response.
     
    508536                [ { 'attribute': x, 'value' : y } \
    509537                        for x,y in self.attrs.iteritems()])
     538
     539        if services:
     540            msg['service'] = services
    510541        return msg
    511542
     
    676707                        "Misformed allocation response?")
    677708
    678 
    679709            self.allocation[aid]['owners'] = owners
    680710            self.write_state()
     
    689719                raise service_error(service_error.internal,
    690720                        "Can't open %s/%s : %s" % (self.certdir, aid, e))
    691             resp = self.build_response({ 'fedid': allocID } , ap)
     721            services = self.export_services(req.get('service',[]), pname, uname)
     722            resp = self.build_response({ 'fedid': allocID } , ap, services)
    692723            return resp
    693724        else:
     
    819850
    820851    def generate_portal_configs(self, topo, pubkey_base, secretkey_base,
    821             tmpdir, master):
     852            tmpdir, master, lproj, leid, connInfo, services):
     853
     854        def conninfo_to_dict(key, info):
     855            """
     856            Make a cpoy of the connection information about key, and flatten it
     857            into a single dict by parsing out any feddAttrs.
     858            """
     859
     860            rv = None
     861            for i in info:
     862                if i.get('portal', "") == key:
     863                    rv = i.copy()
     864                    break
     865            else:
     866                return rv
     867
     868            if 'fedAttr' in rv:
     869                for a in rv['fedAttr']:
     870                    attr = a.get('attribute', "")
     871                    val = a.get('value', "")
     872                    if attr and attr not in rv:
     873                        rv[attr] = val
     874                del rv['fedAttr']
     875            return rv
     876
     877        # XXX: un hardcode this
     878        def client_null(f, s): pass
     879
     880        def client_smb(f, s):
     881            smbshare = None
     882            smbuser = None
     883            smbproj = None
     884            for a in s.get('fedAttr', []):
     885                if a.get('attribute', '') == 'SMBSHARE':
     886                    smbshare = a.get('value', None)
     887                elif a.get('attribute', '') == 'SMBUSER':
     888                    smbuser = a.get('value', None)
     889                elif a.get('attribute', '') == 'SMBPROJ':
     890                    smbproj = a.get('value', None)
     891
     892            if all((smbshare, smbuser, smbproj)):
     893                print >>f, "SMBshare: %s" % smbshare
     894                print >>f, "ProjectUser: %s" % smbuser
     895                print >>f, "ProjectName: %s" % smbproj
     896
     897        client_service_out = {
     898                'SMB': client_smb,
     899                'tmcd': client_null,
     900                'seer': client_null,
     901                'userconfig': client_null,
     902            }
     903        # XXX: end un hardcode this
     904
    822905
    823906        seer_out = False
     
    826909                if isinstance(e, topdl.Computer) and e.get_attribute('portal')]:
    827910            myname = e.name[0]
    828             peer = e.get_attribute('peer')
    829             lexp = e.get_attribute('experiment')
    830             lproj, leid = lexp.split('/', 1)
    831             ldomain = e.get_attribute('domain')
    832             mexp = e.get_attribute('masterexperiment')
     911            type = e.get_attribute('portal_type')
     912
     913            info = conninfo_to_dict(myname, connInfo)
     914
     915            if not info:
     916                raise service_error(service_error.req,
     917                        "No connectivity info for %s" % myname)
     918
     919            peer = info.get('peer', "")
     920            ldomain = self.domain;
     921
     922            mexp = info.get('masterexperiment',"")
    833923            mproj, meid = mexp.split("/", 1)
    834             mdomain = e.get_attribute('masterdomain')
    835             muser = e.get_attribute('masteruser') or 'root'
    836             smbshare = e.get_attribute('smbshare') or 'USERS'
    837             scriptdir = e.get_attribute('scriptdir')
    838             active = e.get_attribute('active')
    839             type = e.get_attribute('portal_type')
    840             segid = fedid(hexstr=e.get_attribute('peer_segment'))
    841             for e in topo.elements:
    842                 if isinstance(e, topdl.Segment) and e.id.fedid == segid:
    843                     seg = e
    844                     break
    845             else:
    846                 raise service_error(service_error.req,
    847                         "Can't find segment for portal %s" % myname)
    848 
    849             is_ip = re.match('\d+\.\d+\.\d+\.\d+', peer)
    850 
    851             rexp = seg.get_attribute('experiment')
    852             rproj, reid = rexp.split("/", 1)
    853             rdomain = seg.get_attribute('domain')
     924            mdomain = info.get('masterdomain',"")
     925            muser = info.get('masteruser','root')
     926            smbshare = info.get('smbshare', 'USERS')
     927
     928            active = info.get('active', 'False')
     929
     930
    854931            cfn = "%s/%s.gw.conf" % (tmpdir, myname.lower())
    855932            tunnelconfig = self.attrs.has_key('TunnelCfg')
     
    857934                f = open(cfn, "w")
    858935                if active == 'True':
    859                     print >>f, "active: %s" % active
    860936                    if type in ('control', 'both'):
    861                         print >>f, 'port: remote:139:fs:139'
    862                         print >>f, 'port: remote:7777:boss:7777'
    863                         print >>f, 'port: remote:16606:control:16606'
     937                        for s in [s for s in services \
     938                                if s.get('name', "") in self.imports]:
     939                            p = urlparse(s.get('server', 'http://localhost'))
     940                            print >>f, 'port: remote:%s:%s:%s' % \
     941                                    (p.port, p.hostname, p.port)
    864942
    865943                if tunnelconfig:
    866944                    print >>f, "tunnelip: %s" % tunnelconfig
    867                 print >>f, "seercontrol: control.%s.%s%s" % \
    868                         (meid.lower(), mproj.lower(), mdomain)
    869                 if is_ip:
    870                     print >>f, "peer: %s" % peer
    871                 else:
    872                     print >>f, "peer: %s.%s.%s%s" % \
    873                             (peer.lower(), reid.lower(),
    874                                     rproj.lower(), rdomain)
     945                # XXX: send this an fedattr
     946                #print >>f, "seercontrol: control.%s.%s%s" % \
     947                        #(meid.lower(), mproj.lower(), mdomain)
     948                print >>f, "peer: %s" % peer.lower()
    875949                print >>f, "ssh_pubkey: /proj/%s/exp/%s/tmp/%s" % \
    876950                        (lproj, leid, pubkey_base)
     
    903977                        (myname.lower(), leid.lower(), lproj.lower(),
    904978                                ldomain.lower())
    905                     print >>f, "SMBshare: %s" % smbshare
    906                     print >>f, "ProjectUser: %s" % muser
    907                     print >>f, "ProjectName: %s" % mproj
    908                     print >>f, "ExperimentID: %s/%s" % (mproj, meid)
     979                    for s in services:
     980                        if s.get('name',"") in self.imports:
     981                            client_service_out[s['name']](f, s)
     982                    # Does seer need this?
     983                    # print >>f, "ExperimentID: %s/%s" % (mproj, meid)
    909984                    f.close()
    910985                except IOError, e:
     
    10511126            raise service_error(server_error.req, "Badly formed request")
    10521127
     1128        connInfo = req.get('connection', [])
     1129        services = req.get('service', [])
    10531130        auth_attr = req['allocID']['fedid']
    10541131        aid = "%s" % auth_attr
     
    10831160                os.mkdir(softdir)
    10841161            for s in sw:
    1085                 print "%s %s %s" % ( s, certfile, softdir)
     1162                self.log.debug("Retrieving %s" % s)
    10861163                get_url(s, certfile, softdir)
    10871164
     
    11311208
    11321209            self.generate_portal_configs(topo, pubkey_base,
    1133                     secretkey_base, tmpdir, master)
     1210                    secretkey_base, tmpdir, master, proj, ename, connInfo,
     1211                    services)
    11341212            self.generate_ns2(topo, expfile,
    11351213                    "/proj/%s/software/%s/" % (proj, ename), master)
     
    11401218        except service_error, e:
    11411219            err = e
     1220        except e:
     1221            err = service_error(service_error.internal, str(e))
    11421222
    11431223        # Walk up tmpdir, deleting as we go
  • fedd/federation/experiment_control.py

    r8139a48 re02cd14  
    726726
    727727    def get_access(self, tb, nodes, tbparam, master, export_project,
    728             access_user):
     728            access_user, services):
    729729        """
    730730        Get access to testbed through fedd and set the parameters for that tb
     
    769769                # the type
    770770                req['exportProject'] = export_project
     771                req['service'] = [
     772                        { 'name': 'userconfig', 'visibility': 'export'},
     773                        { 'name': 'SMB', 'visibility': 'export'},
     774                        { 'name': 'seer', 'visibility': 'export'},
     775                        { 'name': 'tmcd', 'visibility': 'export'},
     776                    ]
    771777
    772778            # node resources if any
     
    820826                "uri": uri,
    821827                }
     828        if 'service' in r:
     829            services.extend(r['service'])
    822830
    823831        # Add attributes to parameter space.  We don't allow attributes to
     
    890898            self.response = None
    891899
    892         def __call__(self, uri, aid, topo, master, attrs=None):
     900        def __call__(self, uri, aid, topo, master, attrs=None, connInfo=None,
     901                services=None):
    893902            req = {
    894903                    'allocID': { 'fedid' : aid },
     
    898907                    'master': master,
    899908                }
     909
     910            if connInfo:
     911                req['connection'] = connInfo
     912            # Add services to request.  The master exports, everyone else
     913            # imports.
     914            if services:
     915                svcs = [ x.copy() for x in services]
     916                for s in svcs:
     917                    if master: s['visibility'] = 'export'
     918                    else: s['visibility'] = 'import'
     919                req['service'] = svcs
    900920            if attrs:
    901921                req['fedAttr'] = attrs
     
    950970    def allocate_resources(self, allocated, master, eid, expid,
    951971            tbparams, topo, tmpdir, alloc_log=None, log_collector=None,
    952             attrs=None):
     972            attrs=None, connInfo={}, services=[]):
    953973        def get_vlan(r):
    954974            if r.has_key('StartSegmentResponseBody'):
     
    10011021            t = self.pooled_thread(
    10021022                    target=ss,
    1003                     args =(uri, aid, topo[tb], False, attrs),
     1023                    args =(uri, aid, topo[tb], False, attrs, connInfo[tb],
     1024                        services),
    10041025                    name=tb, pdata=thread_pool, trace_file=self.trace_file)
    10051026            threads.append(t)
     
    10541075                            caller=self.call_StartSegment,
    10551076                            log_collector=log_collector),
    1056                         args=(uri, aid, topo[tb], False, attrs), name=tb,
     1077                        args=(uri, aid, topo[tb], False, attrs, connInfo[tb],
     1078                            services),
     1079                        name=tb,
    10571080                        pdata=thread_pool, trace_file=self.trace_file)
    10581081                threads.append(t)
     
    10901113                        caller=self.call_StartSegment,
    10911114                        log_collector=log_collector),
    1092                     args =(uri, aid, topo[master], True, attrs),
     1115                    args =(uri, aid, topo[master], True, attrs,
     1116                        connInfo[master], services),
    10931117                    name=master, pdata=thread_pool, trace_file=self.trace_file)
    10941118            threads.append(t)
     
    12941318
    12951319    def get_access_to_testbeds(self, testbeds, access_user,
    1296             export_project, master, allocated, tbparams):
     1320            export_project, master, allocated, tbparams, services):
    12971321        """
    12981322        Request access to the various testbeds required for this instantiation
     
    13031327        for tb in testbeds:
    13041328            self.get_access(tb, None, tbparams, master,
    1305                     export_project, access_user)
     1329                    export_project, access_user, services)
    13061330            allocated[tb] = 1
    13071331
    13081332    def split_topology(self, top, topo, testbeds, eid, master, tbparams):
    13091333        """
    1310         Create the sub-topologies that are needed for experimetn instantiation.
    1311         Along the way attach startup commands to the computers in the
    1312         subtopologies.
     1334        Create the sub-topologies that are needed for experiment instantiation.
    13131335        """
    13141336        for tb in testbeds:
    13151337            topo[tb] = top.clone()
    13161338            to_delete = [ ]
     1339            # XXX: copy in for loop to simplify
    13171340            for e in topo[tb].elements:
    13181341                etb = e.get_attribute('testbed')
     
    13321355            for e in [ e for e in topo[tb].elements \
    13331356                    if isinstance(e,topdl.Computer)]:
    1334                 if tb == master:
    1335                     cmd = 'sudo -H /usr/local/federation/bin/make_hosts /proj/%s/exp/%s/tmp/hosts >& /tmp/federate' % (tbparams[tb].get('project', 'project'), eid)
    1336                 else:
    1337                     cmd = "sudo -H /bin/sh /usr/local/federation/bin/federate.sh >& /tmp/federate"
    1338                 scmd = e.get_attribute('startup')
    1339                 if scmd:
    1340                     cmd = "%s \\$USER '%s'" % (cmd, scmd)
    1341 
    1342                 e.set_attribute('startup', cmd)
    13431357                if self.fedkit: self.add_kit(e, self.fedkit)
    13441358
    13451359    def new_portal_node(self, st, dt, tbparams, master, eid, myname, desthost,
    13461360            portal_type, iface_desc=()):
     1361        """
     1362        Return a new internet portal node and a dict with the connectionInfo to
     1363        be attached.
     1364        """
    13471365        sproject = tbparams[st].get('project', 'project')
    1348         dproject = tbparams[dt].get('project', 'project')
     1366        sdomain = tbparams[st].get('domain', ".example.com")
     1367        mdomain = tbparams[master].get('domain', '.example.com')
    13491368        mproject = tbparams[master].get('project', 'project')
    1350         sdomain = tbparams[st].get('domain', ".example.com")
    1351         ddomain = tbparams[dt].get('domain', ".example.com")
    1352         mdomain = tbparams[master].get('domain', '.example.com')
    13531369        muser = tbparams[master].get('user', 'root')
    13541370        smbshare = tbparams[master].get('smbshare', 'USERS')
    1355         aid = tbparams[dt]['allocID']['fedid']
     1371
    13561372        if st == master or dt == master:
    13571373            active = ("%s" % (st == master))
    13581374        else:
    1359             active = ("%s" %(st > dt))
     1375            active = ("%s" % (st > dt))
    13601376
    13611377        ifaces = [ ]
     
    13711387                    )
    13721388            ifaces.append(inf)
    1373         return topdl.Computer(
     1389        info = {
     1390                "type" : "ssh",
     1391                "portal": myname,
     1392                'peer': "%s.%s.%s%s" %  (desthost.lower(), eid.lower(),
     1393                            sproject.lower(), sdomain.lower()),
     1394                'fedAttr': [
     1395                        { 'attribute': 'masterdomain', 'value': mdomain},
     1396                        { 'attribute': 'masterexperiment', 'value':
     1397                            "%s/%s" % (mproject, eid)},
     1398                        { 'attribute': 'active', 'value': "%s" % active},
     1399                        # Move to SMB service description
     1400                        { 'attribute': 'masteruser', 'value': muser},
     1401                        { 'attribute': 'smbshare', 'value': smbshare},
     1402                    ],
     1403                }
     1404        return (topdl.Computer(
    13741405                name=myname,
    13751406                attribute=[
     
    13771408                        for n, v in (\
    13781409                            ('portal', 'true'),
    1379                             ('domain', sdomain),
    1380                             ('masterdomain', mdomain),
    1381                             ('masterexperiment', "%s/%s" % \
    1382                                     (mproject, eid)),
    1383                             ('masteruser', muser),
    1384                             ('smbshare', smbshare),
    1385                             ('experiment', "%s/%s" % \
    1386                                     (sproject, eid)),
    1387                             ('peer', "%s" % desthost),
    1388                             ('peer_segment', "%s" % aid),
    1389                             ('scriptdir',
    1390                                 "/usr/local/federation/bin"),
    1391                             ('active', "%s" % active),
    13921410                            ('portal_type', portal_type),
    13931411                        )
    13941412                    ],
    13951413                interface=ifaces,
    1396                 )
     1414                ), info)
    13971415
    13981416    def new_portal_substrate(self, st, dt, eid, tbparams):
     
    14961514
    14971515    def insert_internet_portals(self, sub, topo, tbs, tbparams, master, eid,
    1498             segment_substrate, portals):
     1516            segment_substrate, portals, connInfo):
    14991517        # More than one testbed is on this substrate.  Insert
    15001518        # some portals into the subtopologies.  st == source testbed,
     
    15051523            if not portals.has_key(st):
    15061524                portals[st] = { }
     1525            if not connInfo.has_key(st):
     1526                connInfo[st] = [ ]
    15071527            for dt in [ t for t in tbs.keys() if t != st]:
    15081528                sproject = tbparams[st].get('project', 'project')
     
    15311551                if portals[st].has_key(dt):
    15321552                    # There's a portal set up to go to this destination.
    1533                     # See if there's room to multiples this connection on
     1553                    # See if there's room to multiplex this connection on
    15341554                    # it.  If so, add an interface to the portal; if not,
    15351555                    # set up to add a portal below.
     
    15731593                                (('ip4_address', tbs[dt]),))
    15741594                        )
    1575                     portal =  self.new_portal_node(st, dt, tbparams,
     1595                    portal, info =  self.new_portal_node(st, dt, tbparams,
    15761596                            master, eid, myname, desthost, portal_type,
    15771597                            infs)
     
    15831603                    topo[st].elements.append(portal)
    15841604                    portals[st][dt].append(portal)
    1585 
    1586     def add_control_portal(self, st, dt, master, eid, topo, tbparams):
     1605                    connInfo[st].append(info)
     1606
     1607    def add_control_portal(self, st, dt, master, eid, topo, tbparams, connInfo):
    15871608        # Add to the master testbed
    15881609        tsubstrate, segment_element = \
     
    15911612        desthost = "%stunnel" % st
    15921613
    1593         portal = self.new_portal_node(st, dt, tbparams, master,
     1614        portal, info = self.new_portal_node(st, dt, tbparams, master,
    15941615                eid, myname, desthost, "control",
    15951616                ((tsubstrate.name,(('portal','true'),)),))
     
    16021623        topo[st].elements.append(segment_element)
    16031624        topo[st].elements.append(portal)
     1625        if not connInfo.has_key(st):
     1626            connInfo[st] = [ ]
     1627        connInfo[st].append(info)
    16041628
    16051629    def new_dragon_portal(self, st, dt, master, eid, myip, dip, idx,
     
    16231647        return portal
    16241648
    1625     def add_portals(self, top, topo, eid, master, tbparams, ip_allocator):
     1649    def add_portals(self, top, topo, eid, master, tbparams, ip_allocator,
     1650            connInfo):
    16261651        """
    16271652        For each substrate in the main topology, find those that
     
    16521677            else:
    16531678                self.insert_internet_portals(s, topo, tbs, tbparams, master,
    1654                         eid, segment_substrate, portals)
     1679                        eid, segment_substrate, portals, connInfo)
    16551680
    16561681        # Make sure that all the slaves have a control portal back to the
     
    17381763                else:
    17391764                    self.add_control_portal(master, tb, master, eid, topo,
    1740                             tbparams)
     1765                            tbparams, connInfo)
    17411766                    self.add_control_portal(tb, master, master, eid, topo,
    1742                             tbparams)
     1767                            tbparams, connInfo)
    17431768
    17441769        # Connect the portal nodes into the topologies and clear out
     
    20302055            allocated = { }         # Testbeds we can access
    20312056            topo ={ }               # Sub topologies
     2057            connInfo = { }          # Connection information
     2058            services = [ ]
    20322059            self.get_access_to_testbeds(testbeds, access_user,
    2033                     export_project, master, allocated, tbparams)
     2060                    export_project, master, allocated, tbparams, services)
    20342061            self.split_topology(top, topo, testbeds, eid, master, tbparams)
    20352062
     
    20662093                    self.auth.set_attribute(asignee, "%s/%s" % (configpath, f))
    20672094
    2068             self.add_portals(top, topo, eid, master, tbparams, ip_allocator)
     2095            self.add_portals(top, topo, eid, master, tbparams, ip_allocator,
     2096                    connInfo)
    20692097            # Now get access to the dynamic testbeds
    20702098            for k, t in topo.items():
     
    20742102                if tb:
    20752103                    self.get_access(tb, None, user, tbparams, master,
    2076                             export_project, access_user)
     2104                            export_project, access_user, services)
    20772105                    tbparams[k] = tbparams[tb]
    20782106                    del tbparams[tb]
     
    21682196        t  = Thread(target=self.allocate_resources,
    21692197                args=(allocated, master, eid, expid, tbparams,
    2170                     topo, tmpdir, alloc_log, alloc_collector, attrs),
     2198                    topo, tmpdir, alloc_log, alloc_collector, attrs, connInfo,
     2199                    services),
    21712200                name=eid)
    21722201        t.start()
Note: See TracChangeset for help on using the changeset viewer.