Ignore:
Timestamp:
Sep 8, 2009 2:33:33 PM (15 years ago)
Author:
Ted Faber <faber@…>
Branches:
axis_example, compt_changes, info-ops, master, version-2.00, version-3.01, version-3.02
Children:
574055e
Parents:
e794984
Message:

Better modularity of experiment creation.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • fedd/federation/experiment_control.py

    re794984 r895a133  
    10971097
    10981098
    1099     def create_experiment(self, req, fid):
    1100         """
    1101         The external interface to experiment creation called from the
    1102         dispatcher.
    1103 
    1104         Creates a working directory, splits the incoming description using the
    1105         splitter script and parses out the avrious subsections using the
    1106         lcasses above.  Once each sub-experiment is created, use pooled threads
    1107         to instantiate them and start it all up.
    1108         """
    1109 
    1110         def add_kit(e, kit):
    1111             """
    1112             Add a Software object created from the list of (install, location)
    1113             tuples passed as kit  to the software attribute of an object e.  We
    1114             do this enough to break out the code, but it's kind of a hack to
    1115             avoid changing the old tuple rep.
    1116             """
    1117 
    1118             s = [ topdl.Software(install=i, location=l) for i, l in kit]
    1119 
    1120             if isinstance(e.software, list): e.software.extend(s)
    1121             else: e.software = s
    1122 
    1123 
    1124         if not self.auth.check_attribute(fid, 'create'):
    1125             raise service_error(service_error.access, "Create access denied")
    1126 
    1127         try:
    1128             tmpdir = tempfile.mkdtemp(prefix="split-")
    1129         except IOError:
    1130             raise service_error(service_error.internal, "Cannot create tmp dir")
    1131 
    1132         gw_pubkey_base = "fed.%s.pub" % self.ssh_type
    1133         gw_secretkey_base = "fed.%s" % self.ssh_type
    1134         gw_pubkey = tmpdir + "/keys/" + gw_pubkey_base
    1135         gw_secretkey = tmpdir + "/keys/" + gw_secretkey_base
    1136         tclfile = tmpdir + "/experiment.tcl"
    1137         tbparams = { }
    1138         try:
    1139             access_user = self.accessdb[fid]
    1140         except KeyError:
    1141             raise service_error(service_error.internal,
    1142                     "Access map and authorizer out of sync in " + \
    1143                             "create_experiment for fedid %s"  % fid)
    1144 
    1145         pid = "dummy"
    1146         gid = "dummy"
    1147         try:
    1148             os.mkdir(tmpdir+"/keys")
    1149         except OSError:
    1150             raise service_error(service_error.internal,
    1151                     "Can't make temporary dir")
    1152 
    1153         req = req.get('CreateRequestBody', None)
    1154         if not req:
    1155             raise service_error(service_error.req,
    1156                     "Bad request format (no CreateRequestBody)")
    1157         # The tcl parser needs to read a file so put the content into that file
    1158         descr=req.get('experimentdescription', None)
    1159         if descr:
    1160             file_content=descr.get('ns2description', None)
    1161             if file_content:
    1162                 try:
    1163                     f = open(tclfile, 'w')
    1164                     f.write(file_content)
    1165                     f.close()
    1166                 except IOError:
    1167                     raise service_error(service_error.internal,
    1168                             "Cannot write temp experiment description")
    1169             else:
    1170                 raise service_error(service_error.req,
    1171                         "Only ns2descriptions supported")
    1172         else:
    1173             raise service_error(service_error.req, "No experiment description")
    1174 
    1175         # Generate an ID for the experiment (slice) and a certificate that the
    1176         # allocator can use to prove they own it.  We'll ship it back through
    1177         # the encrypted connection.
    1178         (expid, expcert) = generate_fedid("test", dir=tmpdir, log=self.log)
     1099    def add_kit(self, e, kit):
     1100        """
     1101        Add a Software object created from the list of (install, location)
     1102        tuples passed as kit  to the software attribute of an object e.  We
     1103        do this enough to break out the code, but it's kind of a hack to
     1104        avoid changing the old tuple rep.
     1105        """
     1106
     1107        s = [ topdl.Software(install=i, location=l) for i, l in kit]
     1108
     1109        if isinstance(e.software, list): e.software.extend(s)
     1110        else: e.software = s
     1111
     1112
     1113    def create_experiment_state(self, fid, req, expid, expcert):
     1114        """
     1115        Create the initial entry in the experiment's state.  The expid and
     1116        expcert are the experiment's fedid and certifacte that represents that
     1117        ID, which are installed in the experiment state.  If the request
     1118        includes a suggested local name that is used if possible.  If the local
     1119        name is already taken by an experiment owned by this user that has
     1120        failed, it is overwriutten.  Otherwise new letters are added until a
     1121        valid localname is found.  The generated local name is returned.
     1122        """
    11791123
    11801124        if req.has_key('experimentID') and \
     
    12331177            self.state_lock.release()
    12341178
     1179        return eid
     1180
     1181
     1182    def allocate_ips_to_topo(self, top):
     1183        """
     1184        Add an ip4_address attribute to all the hosts in teh topology, based on
     1185        the shared substrates on which they sit.  An /etc/hosts file is also
     1186        created and returned as a list of hostfiles entries.
     1187        """
     1188        subs = sorted(top.substrates,
     1189                cmp=lambda x,y: cmp(len(x.interfaces), len(y.interfaces)),
     1190                reverse=True)
     1191        ips = ip_allocator(int(ip_addr("10.0.0.0")), 2 **24)
     1192        ifs = { }
     1193        hosts = [ ]
     1194
     1195        for idx, s in enumerate(subs):
     1196            a = ips.allocate(len(s.interfaces)+2)
     1197            if a :
     1198                base, num = a
     1199                if num < len(s.interfaces) +2 :
     1200                    raise service_error(service_error.internal,
     1201                            "Allocator returned wrong number of IPs??")
     1202            else:
     1203                raise service_error(service_error.req,
     1204                        "Cannot allocate IP addresses")
     1205
     1206            base += 1
     1207            for i in s.interfaces:
     1208                i.attribute.append(
     1209                        topdl.Attribute('ip4_address',
     1210                            "%s" % ip_addr(base)))
     1211                hname = i.element.name[0]
     1212                if ifs.has_key(hname):
     1213                    hosts.append("%s\t%s-%s %s-%d" % \
     1214                            (ip_addr(base), hname, s.name, hname,
     1215                                ifs[hname]))
     1216                else:
     1217                    ifs[hname] = 0
     1218                    hosts.append("%s\t%s-%s %s-%d %s" % \
     1219                            (ip_addr(base), hname, s.name, hname,
     1220                                ifs[hname], hname))
     1221
     1222                ifs[hname] += 1
     1223                base += 1
     1224        return hosts
     1225
     1226    def get_access_to_testbeds(self, testbeds, user, access_user,
     1227            export_project, master, allocated, tbparams):
     1228        """
     1229        Request access to the various testbeds required for this instantiation
     1230        (passed in as testbeds).  User, access_user, expoert_project and master
     1231        are used to construct the correct requests.  Per-testbed parameters are
     1232        returned in tbparams.
     1233        """
     1234        for tb in testbeds:
     1235            self.get_access(tb, None, user, tbparams, master,
     1236                    export_project, access_user)
     1237            allocated[tb] = 1
     1238
     1239    def split_topology(self, top, topo, testbeds, eid, master, tbparams):
     1240        """
     1241        Create the sub-topologies that are needed for experimetn instantiation.
     1242        Along the way attach startup commands to the computers in the
     1243        subtopologies.
     1244        """
     1245        for tb in testbeds:
     1246            topo[tb] = top.clone()
     1247            to_delete = [ ]
     1248            for e in topo[tb].elements:
     1249                etb = e.get_attribute('testbed')
     1250                if etb and etb != tb:
     1251                    for i in e.interface:
     1252                        for s in i.subs:
     1253                            try:
     1254                                s.interfaces.remove(i)
     1255                            except ValueError:
     1256                                raise service_error(service_error.internal,
     1257                                        "Can't remove interface??")
     1258                    to_delete.append(e)
     1259            for e in to_delete:
     1260                topo[tb].elements.remove(e)
     1261            topo[tb].make_indices()
     1262
     1263            for e in [ e for e in topo[tb].elements \
     1264                    if isinstance(e,topdl.Computer)]:
     1265                if tb == master:
     1266                    cmd = 'sudo -H /usr/local/federation/bin/make_hosts /proj/%s/exp/%s/tmp/hosts >& /tmp/federate' % (tbparams[tb].get('project', 'project'), eid)
     1267                else:
     1268                    cmd = "sudo -H /bin/sh /usr/local/federation/bin/federate.sh >& /tmp/federate"
     1269                scmd = e.get_attribute('startup')
     1270                if scmd:
     1271                    cmd = "%s \\$USER '%s'" % (cmd, scmd)
     1272
     1273                e.set_attribute('startup', cmd)
     1274                if self.fedkit: self.add_kit(e, self.fedkit)
     1275
     1276    def add_portals(self, top, topo, eid, master, tbparams):
     1277        """
     1278        For each substrate in the main topology, find those that
     1279        have nodes on more than one testbed.  Insert portal nodes
     1280        into the copies of those substrates on the sub topologies.
     1281        """
     1282        for s in top.substrates:
     1283            # tbs will contain an ip address on this subsrate that is in
     1284            # each testbed.
     1285            tbs = { }
     1286            for i in s.interfaces:
     1287                e = i.element
     1288                tb = e.get_attribute('testbed')
     1289                if tb and not tbs.has_key(tb):
     1290                    for i in e.interface:
     1291                        if s in i.subs:
     1292                            tbs[tb]= i.get_attribute('ip4_address')
     1293            if len(tbs) < 2:
     1294                continue
     1295
     1296            # More than one testbed is on this substrate.  Insert
     1297            # some portals into the subtopologies.  st == source testbed,
     1298            # dt == destination testbed.
     1299            segment_substrate = { }
     1300            for st in tbs.keys():
     1301                segment_substrate[st] = { }
     1302                for dt in [ t for t in tbs.keys() if t != st]:
     1303                    myname =  "%stunnel" % dt
     1304                    desthost  =  "%stunnel" % st
     1305                    sproject = tbparams[st].get('project', 'project')
     1306                    dproject = tbparams[dt].get('project', 'project')
     1307                    mproject = tbparams[master].get('project', 'project')
     1308                    sdomain = tbparams[st].get('domain', ".example.com")
     1309                    ddomain = tbparams[dt].get('domain', ".example.com")
     1310                    mdomain = tbparams[master].get('domain', '.example.com')
     1311                    muser = tbparams[master].get('user', 'root')
     1312                    smbshare = tbparams[master].get('smbshare', 'USERS')
     1313                    # XXX: active and type need to be unkludged
     1314                    active = ("%s" % (st == master))
     1315                    if not segment_substrate[st].has_key(dt):
     1316                        # Put a substrate and a segment for the connected
     1317                        # testbed in there.
     1318                        tsubstrate = \
     1319                                topdl.Substrate(name='%s-%s' % (st, dt),
     1320                                        attribute= [
     1321                                            topdl.Attribute(
     1322                                                attribute='portal',
     1323                                                value='true')
     1324                                            ]
     1325                                        )
     1326                        segment_element = topdl.Segment(
     1327                                id= tbparams[dt]['allocID'],
     1328                                type='emulab',
     1329                                uri = self.tbmap.get(dt, None),
     1330                                interface=[
     1331                                    topdl.Interface(
     1332                                        substrate=tsubstrate.name),
     1333                                    ],
     1334                                attribute = [
     1335                                    topdl.Attribute(attribute=n, value=v)
     1336                                        for n, v in (\
     1337                                            ('domain', ddomain),
     1338                                            ('experiment', "%s/%s" % \
     1339                                                    (dproject, eid)),)
     1340                                    ],
     1341                                )
     1342                        segment_substrate[st][dt] = tsubstrate
     1343                        topo[st].substrates.append(tsubstrate)
     1344                        topo[st].elements.append(segment_element)
     1345                    portal = topdl.Computer(
     1346                            name="%stunnel" % dt,
     1347                            attribute=[
     1348                                topdl.Attribute(attribute=n,value=v)
     1349                                    for n, v in (\
     1350                                        ('portal', 'true'),
     1351                                        ('domain', sdomain),
     1352                                        ('masterdomain', mdomain),
     1353                                        ('masterexperiment', "%s/%s" % \
     1354                                                (mproject, eid)),
     1355                                        ('masteruser', muser),
     1356                                        ('smbshare', smbshare),
     1357                                        ('experiment', "%s/%s" % \
     1358                                                (sproject, eid)),
     1359                                        ('peer', "%s" % desthost),
     1360                                        ('peer_segment', "%s" % \
     1361                                                tbparams[dt]['allocID']['fedid']),
     1362                                        ('scriptdir',
     1363                                            "/usr/local/federation/bin"),
     1364                                        ('active', "%s" % active),
     1365                                        ('portal_type', 'both'),
     1366                                        ('startup', 'sudo -H /usr/local/federation/bin/fed-tun.pl -f /proj/%s/exp/%s/tmp/%s.%s.%s%s.gw.conf >& /tmp/bridge.log' % (sproject, eid, myname.lower(), eid.lower(), sproject.lower(), sdomain.lower())))
     1367                                ],
     1368                            interface=[
     1369                                topdl.Interface(
     1370                                    substrate=s.name,
     1371                                    attribute=[
     1372                                        topdl.Attribute(
     1373                                            attribute='ip4_address',
     1374                                            value=tbs[dt]
     1375                                        )
     1376                                    ]),
     1377                                topdl.Interface(
     1378                                    substrate=\
     1379                                        segment_substrate[st][dt].name,
     1380                                    attribute=[
     1381                                        topdl.Attribute(attribute='portal',
     1382                                            value='true')
     1383                                        ]
     1384                                    ),
     1385                                ],
     1386                            )
     1387                    if self.fedkit: self.add_kit(portal, self.fedkit)
     1388                    if self.gatewaykit: self.add_kit(portal, self.gatewaykit)
     1389
     1390                    topo[st].elements.append(portal)
     1391
     1392        # Connect the gateway nodes into the topologies and clear out
     1393        # substrates that are not in the topologies
     1394        for tb in tbparams.keys():
     1395            topo[tb].incorporate_elements()
     1396            topo[tb].substrates = \
     1397                    [s for s in topo[tb].substrates \
     1398                        if len(s.interfaces) >0]
     1399
     1400    def wrangle_software(self, expid, top, topo, tbparams):
     1401        """
     1402        Copy software out to the repository directory, allocate permissions and
     1403        rewrite the segment topologies to look for the software in local
     1404        places.
     1405        """
     1406
     1407        # Copy the rpms and tarfiles to a distribution directory from
     1408        # which the federants can retrieve them
     1409        linkpath = "%s/software" %  expid
     1410        softdir ="%s/%s" % ( self.repodir, linkpath)
     1411        softmap = { }
     1412        # These are in a list of tuples format (each kit).  This comprehension
     1413        # unwraps them into a single list of tuples that initilaizes the set of
     1414        # tuples.
     1415        pkgs = set([ t for l in [self.fedkit, self.gatewaykit] \
     1416                for p, t in l ])
     1417        pkgs.update([x.location for e in top.elements \
     1418                for x in e.software])
     1419        try:
     1420            os.makedirs(softdir)
     1421        except IOError, e:
     1422            raise service_error(
     1423                    "Cannot create software directory: %s" % e)
     1424        # The actual copying.  Everything's converted into a url for copying.
     1425        for pkg in pkgs:
     1426            loc = pkg
     1427
     1428            scheme, host, path = urlparse(loc)[0:3]
     1429            dest = os.path.basename(path)
     1430            if not scheme:
     1431                if not loc.startswith('/'):
     1432                    loc = "/%s" % loc
     1433                loc = "file://%s" %loc
     1434            try:
     1435                u = urlopen(loc)
     1436            except Exception, e:
     1437                raise service_error(service_error.req,
     1438                        "Cannot open %s: %s" % (loc, e))
     1439            try:
     1440                f = open("%s/%s" % (softdir, dest) , "w")
     1441                self.log.debug("Writing %s/%s" % (softdir,dest) )
     1442                data = u.read(4096)
     1443                while data:
     1444                    f.write(data)
     1445                    data = u.read(4096)
     1446                f.close()
     1447                u.close()
     1448            except Exception, e:
     1449                raise service_error(service_error.internal,
     1450                        "Could not copy %s: %s" % (loc, e))
     1451            path = re.sub("/tmp", "", linkpath)
     1452            # XXX
     1453            softmap[pkg] = \
     1454                    "https://users.isi.deterlab.net:23232/%s/%s" %\
     1455                    ( path, dest)
     1456
     1457            # Allow the individual segments to access the software.
     1458            for tb in tbparams.keys():
     1459                self.auth.set_attribute(tbparams[tb]['allocID']['fedid'],
     1460                        "/%s/%s" % ( path, dest))
     1461
     1462        # Convert the software locations in the segments into the local
     1463        # copies on this host
     1464        for soft in [ s for tb in topo.values() \
     1465                for e in tb.elements \
     1466                    if getattr(e, 'software', False) \
     1467                        for s in e.software ]:
     1468            if softmap.has_key(soft.location):
     1469                soft.location = softmap[soft.location]
     1470
     1471
     1472    def create_experiment(self, req, fid):
     1473        """
     1474        The external interface to experiment creation called from the
     1475        dispatcher.
     1476
     1477        Creates a working directory, splits the incoming description using the
     1478        splitter script and parses out the avrious subsections using the
     1479        lcasses above.  Once each sub-experiment is created, use pooled threads
     1480        to instantiate them and start it all up.
     1481        """
     1482        if not self.auth.check_attribute(fid, 'create'):
     1483            raise service_error(service_error.access, "Create access denied")
     1484
     1485        try:
     1486            tmpdir = tempfile.mkdtemp(prefix="split-")
     1487            os.mkdir(tmpdir+"/keys")
     1488        except IOError:
     1489            raise service_error(service_error.internal, "Cannot create tmp dir")
     1490
     1491        gw_pubkey_base = "fed.%s.pub" % self.ssh_type
     1492        gw_secretkey_base = "fed.%s" % self.ssh_type
     1493        gw_pubkey = tmpdir + "/keys/" + gw_pubkey_base
     1494        gw_secretkey = tmpdir + "/keys/" + gw_secretkey_base
     1495        tclfile = tmpdir + "/experiment.tcl"
     1496        tbparams = { }
     1497        try:
     1498            access_user = self.accessdb[fid]
     1499        except KeyError:
     1500            raise service_error(service_error.internal,
     1501                    "Access map and authorizer out of sync in " + \
     1502                            "create_experiment for fedid %s"  % fid)
     1503
     1504        pid = "dummy"
     1505        gid = "dummy"
     1506
     1507        req = req.get('CreateRequestBody', None)
     1508        if not req:
     1509            raise service_error(service_error.req,
     1510                    "Bad request format (no CreateRequestBody)")
     1511        # The tcl parser needs to read a file so put the content into that file
     1512        descr=req.get('experimentdescription', None)
     1513        if descr:
     1514            file_content=descr.get('ns2description', None)
     1515            if file_content:
     1516                try:
     1517                    f = open(tclfile, 'w')
     1518                    f.write(file_content)
     1519                    f.close()
     1520                except IOError:
     1521                    raise service_error(service_error.internal,
     1522                            "Cannot write temp experiment description")
     1523            else:
     1524                raise service_error(service_error.req,
     1525                        "Only ns2descriptions supported")
     1526        else:
     1527            raise service_error(service_error.req, "No experiment description")
     1528
     1529        # Generate an ID for the experiment (slice) and a certificate that the
     1530        # allocator can use to prove they own it.  We'll ship it back through
     1531        # the encrypted connection.
     1532        (expid, expcert) = generate_fedid("test", dir=tmpdir, log=self.log)
     1533
     1534        eid = self.create_experiment_state(fid, req, expid, expcert)
    12351535        try:
    12361536            # This catches exceptions to clear the placeholder if necessary
     
    12521552            if not export_project:
    12531553                raise service_error(service_error.req, "No export project")
    1254            
     1554           
     1555            # Translate to topdl
    12551556            if self.splitter_url:
     1557                # XXX: need remote topdl translator
    12561558                self.log.debug("Calling remote splitter at %s" % \
    12571559                        self.splitter_url)
     
    12791581                split_data = tclparser.stdout
    12801582
     1583            top = topdl.topology_from_xml(file=split_data, top="experiment")
     1584
     1585            hosts = self.allocate_ips_to_topo(top)
     1586             # Find the testbeds to look up
     1587            testbeds = set([ a.value for e in top.elements \
     1588                    for a in e.attribute \
     1589                    if a.attribute == 'testbed'] )
     1590
    12811591            allocated = { }         # Testbeds we can access
    1282             # Allocate IP addresses: The allocator is a buddy system memory
    1283             # allocator.  Allocate from the largest substrate to the
    1284             # smallest to make the packing more likely to work - i.e.
    1285             # avoiding internal fragmentation.
    1286             top = topdl.topology_from_xml(file=split_data, top="experiment")
    1287             subs = sorted(top.substrates,
    1288                     cmp=lambda x,y: cmp(len(x.interfaces),
    1289                         len(y.interfaces)),
    1290                     reverse=True)
    1291             ips = ip_allocator(int(ip_addr("10.0.0.0")), 2 **24)
    1292             ifs = { }
    1293             hosts = [ ]
     1592            topo ={ }               # Sub topologies
     1593            self.get_access_to_testbeds(testbeds, user, access_user,
     1594                    export_project, master, allocated, tbparams)
     1595            self.split_topology(top, topo, testbeds, eid, master, tbparams)
     1596
     1597            # Copy configuration files into the remote file store
    12941598            # The config urlpath
    12951599            configpath = "/%s/config" % expid
    12961600            # The config file system location
    12971601            configdir ="%s%s" % ( self.repodir, configpath)
    1298 
    1299             for idx, s in enumerate(subs):
    1300                 a = ips.allocate(len(s.interfaces)+2)
    1301                 if a :
    1302                     base, num = a
    1303                     if num < len(s.interfaces) +2 :
    1304                         raise service_error(service_error.internal,
    1305                                 "Allocator returned wrong number of IPs??")
    1306                 else:
    1307                     raise service_error(service_error.req,
    1308                             "Cannot allocate IP addresses")
    1309 
    1310                 base += 1
    1311                 for i in s.interfaces:
    1312                     i.attribute.append(
    1313                             topdl.Attribute('ip4_address',
    1314                                 "%s" % ip_addr(base)))
    1315                     hname = i.element.name[0]
    1316                     if ifs.has_key(hname):
    1317                         hosts.append("%s\t%s-%s %s-%d" % \
    1318                                 (ip_addr(base), hname, s.name, hname,
    1319                                     ifs[hname]))
    1320                     else:
    1321                         ifs[hname] = 0
    1322                         hosts.append("%s\t%s-%s %s-%d %s" % \
    1323                                 (ip_addr(base), hname, s.name, hname,
    1324                                     ifs[hname], hname))
    1325 
    1326                     ifs[hname] += 1
    1327                     base += 1
    1328             # save config files
    13291602            try:
    13301603                os.makedirs(configdir)
     
    13321605                raise service_error(
    13331606                        "Cannot create config directory: %s" % e)
    1334             # Find the testbeds to look up
    1335             testbeds = set([ a.value for e in top.elements \
    1336                     for a in e.attribute \
    1337                         if a.attribute == 'testbed'] )
    1338 
    1339 
    1340             # Make per testbed topologies.  Copy the main topo and remove
    1341             # interfaces and nodes that don't live in the testbed.
    1342             topo ={ }
    1343             for tb in testbeds:
    1344                 self.get_access(tb, None, user, tbparams, master,
    1345                         export_project, access_user)
    1346                 allocated[tb] = 1
    1347                 topo[tb] = top.clone()
    1348                 to_delete = [ ]
    1349                 for e in topo[tb].elements:
    1350                     etb = e.get_attribute('testbed')
    1351                     if etb and etb != tb:
    1352                         for i in e.interface:
    1353                             for s in i.subs:
    1354                                 try:
    1355                                     s.interfaces.remove(i)
    1356                                 except ValueError:
    1357                                     raise service_error(service_error.internal,
    1358                                             "Can't remove interface??")
    1359                         to_delete.append(e)
    1360                 for e in to_delete:
    1361                     topo[tb].elements.remove(e)
    1362                 topo[tb].make_indices()
    1363 
    1364                 for e in topo[tb].elements:
    1365                     if tb == master:
    1366                         cmd = 'sudo -H /usr/local/federation/bin/make_hosts /proj/%s/exp/%s/tmp/hosts >& /tmp/federate' % (tbparams[tb].get('project', 'project'), eid)
    1367                     else:
    1368                         cmd = "sudo -H /bin/sh /usr/local/federation/bin/federate.sh >& /tmp/federate"
    1369                     scmd = e.get_attribute('startup')
    1370                     if scmd:
    1371                         cmd = "%s \\$USER '%s'" % (cmd, scmd)
    1372 
    1373                     e.set_attribute('startup', cmd)
    1374                     if self.fedkit: add_kit(e, self.fedkit)
    1375 
    1376             # Copy configuration files into the remote file store
    13771607            try:
    13781608                f = open("%s/hosts" % configdir, "w")
     
    13971627                    self.auth.set_attribute(asignee, "%s/%s" % (configpath, f))
    13981628
    1399             # Now, for each substrate in the main topology, find those that
    1400             # have nodes on more than one testbed.  Insert portal nodes
    1401             # into the copies of those substrates on the sub topologies.
    1402             for s in top.substrates:
    1403                 # tbs will contain an ip address on this subsrate that is in
    1404                 # each testbed.
    1405                 tbs = { }
    1406                 for i in s.interfaces:
    1407                     e = i.element
    1408                     tb = e.get_attribute('testbed')
    1409                     if tb and not tbs.has_key(tb):
    1410                         for i in e.interface:
    1411                             if s in i.subs:
    1412                                 tbs[tb]= i.get_attribute('ip4_address')
    1413                 if len(tbs) < 2:
    1414                     continue
    1415 
    1416                 # More than one testbed is on this substrate.  Insert
    1417                 # some portals into the subtopologies.  st == source testbed,
    1418                 # dt == destination testbed.
    1419                 segment_substrate = { }
    1420                 for st in tbs.keys():
    1421                     segment_substrate[st] = { }
    1422                     for dt in [ t for t in tbs.keys() if t != st]:
    1423                         myname =  "%stunnel" % dt
    1424                         desthost  =  "%stunnel" % st
    1425                         sproject = tbparams[st].get('project', 'project')
    1426                         dproject = tbparams[dt].get('project', 'project')
    1427                         mproject = tbparams[master].get('project', 'project')
    1428                         sdomain = tbparams[st].get('domain', ".example.com")
    1429                         ddomain = tbparams[dt].get('domain', ".example.com")
    1430                         mdomain = tbparams[master].get('domain', '.example.com')
    1431                         muser = tbparams[master].get('user', 'root')
    1432                         smbshare = tbparams[master].get('smbshare', 'USERS')
    1433                         # XXX: active and type need to be unkludged
    1434                         active = ("%s" % (st == master))
    1435                         if not segment_substrate[st].has_key(dt):
    1436                             # Put a substrate and a segment for the connected
    1437                             # testbed in there.
    1438                             tsubstrate = \
    1439                                     topdl.Substrate(name='%s-%s' % (st, dt),
    1440                                             attribute= [
    1441                                                 topdl.Attribute(
    1442                                                     attribute='portal',
    1443                                                     value='true')
    1444                                                 ]
    1445                                             )
    1446                             segment_element = topdl.Segment(
    1447                                     id= tbparams[dt]['allocID'],
    1448                                     type='emulab',
    1449                                     uri = self.tbmap.get(dt, None),
    1450                                     interface=[
    1451                                         topdl.Interface(
    1452                                             substrate=tsubstrate.name),
    1453                                         ],
    1454                                     attribute = [
    1455                                         topdl.Attribute(attribute=n, value=v)
    1456                                             for n, v in (\
    1457                                                 ('domain', ddomain),
    1458                                                 ('experiment', "%s/%s" % \
    1459                                                         (dproject, eid)),)
    1460                                         ],
    1461                                     )
    1462                             segment_substrate[st][dt] = tsubstrate
    1463                             topo[st].substrates.append(tsubstrate)
    1464                             topo[st].elements.append(segment_element)
    1465                         portal = topdl.Computer(
    1466                                 name="%stunnel" % dt,
    1467                                 attribute=[
    1468                                     topdl.Attribute(attribute=n,value=v)
    1469                                         for n, v in (\
    1470                                             ('portal', 'true'),
    1471                                             ('domain', sdomain),
    1472                                             ('masterdomain', mdomain),
    1473                                             ('masterexperiment', "%s/%s" % \
    1474                                                     (mproject, eid)),
    1475                                             ('masteruser', muser),
    1476                                             ('smbshare', smbshare),
    1477                                             ('experiment', "%s/%s" % \
    1478                                                     (sproject, eid)),
    1479                                             ('peer', "%s" % desthost),
    1480                                             ('peer_segment', "%s" % \
    1481                                                     tbparams[dt]['allocID']['fedid']),
    1482                                             ('scriptdir',
    1483                                                 "/usr/local/federation/bin"),
    1484                                             ('active', "%s" % active),
    1485                                             ('portal_type', 'both'),
    1486                                             ('startup', 'sudo -H /usr/local/federation/bin/fed-tun.pl -f /proj/%s/exp/%s/tmp/%s.%s.%s%s.gw.conf >& /tmp/bridge.log' % (sproject, eid, myname.lower(), eid.lower(), sproject.lower(), sdomain.lower())))
    1487                                     ],
    1488                                 interface=[
    1489                                     topdl.Interface(
    1490                                         substrate=s.name,
    1491                                         attribute=[
    1492                                             topdl.Attribute(
    1493                                                 attribute='ip4_address',
    1494                                                 value=tbs[dt]
    1495                                             )
    1496                                         ]),
    1497                                     topdl.Interface(
    1498                                         substrate=\
    1499                                             segment_substrate[st][dt].name,
    1500                                         attribute=[
    1501                                             topdl.Attribute(attribute='portal',
    1502                                                 value='true')
    1503                                             ]
    1504                                         ),
    1505                                     ],
    1506                                 )
    1507                         if self.fedkit: add_kit(portal, self.fedkit)
    1508                         if self.gatewaykit: add_kit(portal, self.gatewaykit)
    1509 
    1510                         topo[st].elements.append(portal)
    1511 
    1512             # Connect the gateway nodes into the topologies and clear out
    1513             # substrates that are not in the topologies
    1514             for tb in testbeds:
    1515                 topo[tb].incorporate_elements()
    1516                 topo[tb].substrates = \
    1517                         [s for s in topo[tb].substrates \
    1518                             if len(s.interfaces) >0]
    1519 
    1520             # Copy the rpms and tarfiles to a distribution directory from
    1521             # which the federants can retrieve them
    1522             linkpath = "%s/software" %  expid
    1523             softdir ="%s/%s" % ( self.repodir, linkpath)
    1524             softmap = { }
    1525             pkgs = set([ t for l in [self.fedkit, self.gatewaykit] \
    1526                     for p, t in l ])
    1527             pkgs.update([x.location for e in top.elements \
    1528                     for x in e.software])
    1529             try:
    1530                 os.makedirs(softdir)
    1531             except IOError, e:
    1532                 raise service_error(
    1533                         "Cannot create software directory: %s" % e)
    1534             for pkg in pkgs:
    1535                 loc = pkg
    1536 
    1537                 scheme, host, path = urlparse(loc)[0:3]
    1538                 dest = os.path.basename(path)
    1539                 if not scheme:
    1540                     if not loc.startswith('/'):
    1541                         loc = "/%s" % loc
    1542                     loc = "file://%s" %loc
    1543                 try:
    1544                     u = urlopen(loc)
    1545                 except Exception, e:
    1546                     raise service_error(service_error.req,
    1547                             "Cannot open %s: %s" % (loc, e))
    1548                 try:
    1549                     f = open("%s/%s" % (softdir, dest) , "w")
    1550                     self.log.debug("Writing %s/%s" % (softdir,dest) )
    1551                     data = u.read(4096)
    1552                     while data:
    1553                         f.write(data)
    1554                         data = u.read(4096)
    1555                     f.close()
    1556                     u.close()
    1557                 except Exception, e:
    1558                     raise service_error(service_error.internal,
    1559                             "Could not copy %s: %s" % (loc, e))
    1560                 path = re.sub("/tmp", "", linkpath)
    1561                 # XXX
    1562                 softmap[pkg] = \
    1563                         "https://users.isi.deterlab.net:23232/%s/%s" %\
    1564                         ( path, dest)
    1565 
    1566                 # Allow the individual testbeds to access the software.
    1567                 for tb in tbparams.keys():
    1568                     self.auth.set_attribute(tbparams[tb]['allocID']['fedid'],
    1569                             "/%s/%s" % ( path, dest))
    1570 
    1571             # Convert the software locations in the segments into the local
    1572             # copies on this host
    1573             for soft in [ s for tb in topo.values() \
    1574                     for e in tb.elements \
    1575                         if getattr(e, 'software', False) \
    1576                             for s in e.software ]:
    1577                 if softmap.has_key(soft.location):
    1578                     soft.location = softmap[soft.location]
     1629            self.add_portals(top, topo, eid, master, tbparams)
     1630            self.wrangle_software(expid, top, topo, tbparams)
    15791631
    15801632            vtopo = topdl.topology_to_vtopo(top)
Note: See TracChangeset for help on using the changeset viewer.