Changeset 73e7f5c


Ignore:
Timestamp:
Apr 7, 2010 6:27:04 AM (14 years ago)
Author:
Ted Faber <faber@…>
Branches:
axis_example, compt_changes, info-ops, master, version-3.01, version-3.02
Children:
5f96438
Parents:
7fe81be
Message:

Split the experiment partition routines out into a separate class

Location:
fedd/federation
Files:
1 added
1 edited

Legend:

Unmodified
Added
Removed
  • fedd/federation/experiment_control.py

    r7fe81be r73e7f5c  
    2929from service_error import service_error
    3030from synch_store import synch_store
     31from experiment_partition import experiment_partition
    3132
    3233import topdl
     
    13291330            topo[tb].make_indices()
    13301331
    1331     def new_portal_node(self, st, dt, tbparams, master, eid, myname, desthost,
    1332             portal_type, iface_desc=(), conn_type="ssh", conn_attrs=[],
    1333             expid=None):
    1334         """
    1335         Return a new internet portal node and a dict with the connectionInfo to
    1336         be attached.
    1337         """
    1338         dproject = tbparams[dt].get('project', 'project')
    1339         ddomain = tbparams[dt].get('domain', ".example.com")
    1340         mdomain = tbparams[master].get('domain', '.example.com')
    1341         mproject = tbparams[master].get('project', 'project')
    1342         muser = tbparams[master].get('user', 'root')
    1343         smbshare = tbparams[master].get('smbshare', 'USERS')
    1344 
    1345         if st == master or dt == master:
    1346             active = ("%s" % (st == master))
    1347         else:
    1348             active = ("%s" % (st > dt))
    1349 
    1350         ifaces = [ ]
    1351         for sub, attrs in iface_desc:
    1352             inf = topdl.Interface(
    1353                     name="inf%03d" % len(ifaces),
    1354                     substrate=sub,
    1355                     attribute=[
    1356                         topdl.Attribute(
    1357                             attribute=n,
    1358                             value = v)
    1359                         for n, v in attrs
    1360                         ]
    1361                     )
    1362             ifaces.append(inf)
    1363         if conn_type == "ssh":
    1364             try:
    1365                 aid = tbparams[st]['allocID']['fedid']
    1366             except:
    1367                 self.log.debug("[new_portal_node] Can't get alloc id for %s?" \
    1368                         % st)
    1369                 aid = None
    1370             info = {
    1371                     "type" : conn_type,
    1372                     "portal": myname,
    1373                     'fedAttr': [
    1374                             { 'attribute': 'masterdomain', 'value': mdomain},
    1375                             { 'attribute': 'masterexperiment', 'value':
    1376                                 "%s/%s" % (mproject, eid)},
    1377                             { 'attribute': 'active', 'value': active},
    1378                             # Move to SMB service description
    1379                             { 'attribute': 'masteruser', 'value': muser},
    1380                             { 'attribute': 'smbshare', 'value': smbshare},
    1381                         ],
    1382                     'parameter': [
    1383                         {
    1384                             'name': 'peer',
    1385                             'key': 'fedid:%s/%s' % (expid, myname),
    1386                             'store': self.store_url,
    1387                             'type': 'output',
    1388                         },
    1389                         {
    1390                             'name': 'ssh_port',
    1391                             'key': 'fedid:%s/%s-port' % (expid, myname),
    1392                             'store': self.store_url,
    1393                             'type': 'output',
    1394                         },
    1395                         {
    1396                             'name': 'peer',
    1397                             'key': 'fedid:%s/%s' % (expid, desthost),
    1398                             'store': self.store_url,
    1399                             'type': 'input',
    1400                         },
    1401                         {
    1402                             'name': 'ssh_port',
    1403                             'key': 'fedid:%s/%s-port' % (expid, desthost),
    1404                             'store': self.store_url,
    1405                             'type': 'input',
    1406                         },
    1407                         ]
    1408                     }
    1409             # Give this allocation the rights to access the key of the
    1410             # peers
    1411             if aid:
    1412                 for h in (myname, desthost):
    1413                     self.auth.set_attribute(aid, 'fedid:%s/%s' % (expid, h))
    1414                     self.auth.set_attribute(aid, 'fedid:%s/%s-port' % \
    1415                             (expid, h))
    1416             else:
    1417                 self.log.error("No aid for %s in new_portal_node" % st)
    1418         else:
    1419             info = None
    1420 
    1421         return (topdl.Computer(
    1422                 name=myname,
    1423                 attribute=[
    1424                     topdl.Attribute(attribute=n,value=v)
    1425                         for n, v in (\
    1426                             ('portal', 'true'),
    1427                             ('portal_type', portal_type),
    1428                         )
    1429                     ],
    1430                 interface=ifaces,
    1431                 ), info)
    1432 
    1433     def new_portal_substrate(self, st, dt, eid, tbparams, expid):
    1434         ddomain = tbparams[dt].get('domain', ".example.com")
    1435         dproject = tbparams[dt].get('project', 'project')
    1436         tsubstrate = \
    1437                 topdl.Substrate(name='%s-%s' % (st, dt),
    1438                         attribute= [
    1439                             topdl.Attribute(
    1440                                 attribute='portal',
    1441                                 value='true')
    1442                             ]
    1443                         )
    1444         segment_element = topdl.Segment(
    1445                 id= tbparams[dt]['allocID'],
    1446                 type='emulab',
    1447                 uri = self.tbmap.get(dt, None),
    1448                 interface=[
    1449                     topdl.Interface(
    1450                         substrate=tsubstrate.name),
    1451                     ],
    1452                 attribute = [
    1453                     topdl.Attribute(attribute=n, value=v)
    1454                         for n, v in (\
    1455                             ('domain', ddomain),
    1456                             ('experiment', "%s/%s" % \
    1457                                     (dproject, eid)),)
    1458                     ],
    1459                 )
    1460 
    1461         return (tsubstrate, segment_element)
    1462 
    1463     def new_dragon_topo(self, idx, sub, topo, tbs, tbparams, connInfo, expid):
    1464         if sub.capacity is None:
    1465             raise service_error(service_error.internal,
    1466                     "Cannot DRAGON split substrate w/o capacity")
    1467         segs = [ ]
    1468         substr = topdl.Substrate(name="dragon%d" % idx,
    1469                 capacity=sub.capacity.clone(),
    1470                 attribute=[ topdl.Attribute(attribute=n, value=v)
    1471                     for n, v, in (\
    1472                             ('vlan', 'unassigned%d' % idx),)])
    1473         name = "dragon%d" % idx
    1474         store_key = 'fedid:%s/vlan%d' % (expid, idx)
    1475         for tb in tbs.keys():
    1476             seg = topdl.Segment(
    1477                     id = tbparams[tb]['allocID'],
    1478                     type='emulab',
    1479                     uri = self.tbmap.get(tb, None),
    1480                     interface=[
    1481                         topdl.Interface(
    1482                             substrate=substr.name),
    1483                         ],
    1484                     attribute=[ topdl.Attribute(
    1485                         attribute='dragon_endpoint',
    1486                         value=tbparams[tb]['dragon']),
    1487                         ]
    1488                     )
    1489             if tbparams[tb].has_key('vlans'):
    1490                 seg.set_attribute('vlans', tbparams[tb]['vlans'])
    1491             segs.append(seg)
    1492 
    1493             # Give this allocation the rights to access the key of the
    1494             # vlan_id
    1495             try:
    1496                 aid = tbparams[tb]['allocID']['fedid']
    1497                 self.auth.set_attribute(aid, store_key)
    1498             except:
    1499                 self.log.debug("[new_dragon_topo] Can't get alloc id for %s?"\
    1500                         % tb)
    1501 
    1502         connInfo[name] = [ {
    1503             'type': 'transit',
    1504             'parameter': [ {
    1505                 'name': 'vlan_id',
    1506                 'key': store_key,
    1507                 'store': self.store_url,
    1508                 'type': 'output'
    1509                 } ]
    1510             } ]
    1511 
    1512         topo[name] = \
    1513                 topdl.Topology(substrates=[substr], elements=segs,
    1514                         attribute=[
    1515                             topdl.Attribute(attribute="transit", value='true'),
    1516                             topdl.Attribute(attribute="dynamic", value='true'),
    1517                             topdl.Attribute(attribute="testbed",
    1518                                 value='dragon'),
    1519                             topdl.Attribute(attribute="store_keys",
    1520                                 value=store_key),
    1521                             ]
    1522                         )
    1523 
    1524     def create_dragon_substrate(self, sub, topo, tbs, tbparams, master, eid,
    1525             connInfo, expid=None):
    1526         """
    1527         Add attribiutes to the various elements indicating that they are to be
    1528         dragon connected and create a dragon segment in topo to be
    1529         instantiated.
    1530         """
    1531 
    1532         def get_substrate_from_topo(name, t):
    1533             for s in t.substrates:
    1534                 if s.name == name: return s
    1535             else: return None
    1536 
    1537 
    1538         mdomain = tbparams[master].get('domain', '.example.com')
    1539         mproject = tbparams[master].get('project', 'project')
    1540         # dn is the number of previously created dragon nets.  This routine
    1541         # creates a net numbered by dn
    1542         dn = len([x for x in topo.keys() if x.startswith('dragon')])
    1543         # Count the number of interfaces on this substrate in each testbed from
    1544         # the global topology
    1545         count = { }
    1546         node = { }
    1547         for e in [ i.element for i in sub.interfaces ]:
    1548             tb = e.get_attribute('testbed')
    1549             count[tb] = count.get(tb, 0) + 1
    1550             node[tb] = i.get_attribute('ip4_address')
    1551 
    1552 
    1553         # Set the attributes in the copies that will allow setup of dragon
    1554         # connections.
    1555         for tb in tbs.keys():
    1556             s = get_substrate_from_topo(sub.name, topo[tb])
    1557             if s:
    1558                 if not connInfo.has_key(tb):
    1559                     connInfo[tb] = [ ]
    1560 
    1561                 try:
    1562                     aid = tbparams[tb]['allocID']['fedid']
    1563                 except:
    1564                     self.log.debug("[creat_dragon_substrate] " +
    1565                             "Can't get alloc id for %s?" %tb)
    1566                     aid = None
    1567 
    1568                 # This may need another look, but only a service gateway will
    1569                 # look at the active parameter, and these are only inserted to
    1570                 # connect to the master.
    1571                 active = "%s" % ( tb == master)
    1572                 info = {
    1573                         'type': 'transit',
    1574                         'member': [ {
    1575                             'element': i.element.name[0],
    1576                             'interface': i.name
    1577                             } for i in s.interfaces \
    1578                                     if isinstance(i.element, topdl.Computer) ],
    1579                         'fedAttr': [
    1580                             { 'attribute': 'masterdomain', 'value': mdomain},
    1581                             { 'attribute': 'masterexperiment', 'value':
    1582                                 "%s/%s" % (mproject, eid)},
    1583                             { 'attribute': 'active', 'value': active},
    1584                             ],
    1585                         'parameter': [ {
    1586                             'name': 'vlan_id',
    1587                             'key': 'fedid:%s/vlan%d' % (expid, dn),
    1588                             'store': self.store_url,
    1589                             'type': 'input',
    1590                             } ]
    1591                         }
    1592                 if tbs.has_key(tb):
    1593                     info['peer'] = tbs[tb]
    1594                 connInfo[tb].append(info)
    1595 
    1596                 # Give this allocation the rights to access the key of the
    1597                 # vlan_id
    1598                 if aid:
    1599                     self.auth.set_attribute(aid,
    1600                             'fedid:%s/vlan%d' % (expid, dn))
    1601             else:
    1602                 raise service_error(service_error.internal,
    1603                         "No substrate %s in testbed %s" % (sub.name, tb))
    1604 
    1605         self.new_dragon_topo(dn, sub, topo, tbs, tbparams, connInfo, expid)
    1606 
    1607     def insert_internet_portals(self, sub, topo, tbs, tbparams, master, eid,
    1608             segment_substrate, portals, connInfo, expid):
    1609         # More than one testbed is on this substrate.  Insert
    1610         # some portals into the subtopologies.  st == source testbed,
    1611         # dt == destination testbed.
    1612         for st in tbs.keys():
    1613             if not segment_substrate.has_key(st):
    1614                 segment_substrate[st] = { }
    1615             if not portals.has_key(st):
    1616                 portals[st] = { }
    1617             if not connInfo.has_key(st):
    1618                 connInfo[st] = [ ]
    1619             for dt in [ t for t in tbs.keys() if t != st]:
    1620                 sproject = tbparams[st].get('project', 'project')
    1621                 dproject = tbparams[dt].get('project', 'project')
    1622                 mproject = tbparams[master].get('project', 'project')
    1623                 sdomain = tbparams[st].get('domain', ".example.com")
    1624                 ddomain = tbparams[dt].get('domain', ".example.com")
    1625                 mdomain = tbparams[master].get('domain', '.example.com')
    1626                 muser = tbparams[master].get('user', 'root')
    1627                 smbshare = tbparams[master].get('smbshare', 'USERS')
    1628                 aid = tbparams[dt]['allocID']['fedid']
    1629                 if st == master or dt == master:
    1630                     active = ("%s" % (st == master))
    1631                 else:
    1632                     active = ("%s" %(st > dt))
    1633                 if not segment_substrate[st].has_key(dt):
    1634                     # Put a substrate and a segment for the connected
    1635                     # testbed in there.
    1636                     tsubstrate, segment_element = \
    1637                             self.new_portal_substrate(st, dt, eid, tbparams,
    1638                                     expid)
    1639                     segment_substrate[st][dt] = tsubstrate
    1640                     topo[st].substrates.append(tsubstrate)
    1641                     topo[st].elements.append(segment_element)
    1642 
    1643                 new_portal = False
    1644                 if portals[st].has_key(dt):
    1645                     # There's a portal set up to go to this destination.
    1646                     # See if there's room to multiplex this connection on
    1647                     # it.  If so, add an interface to the portal; if not,
    1648                     # set up to add a portal below.
    1649                     # [This little festival of braces is just a pop of the
    1650                     # last element in the list of portals between st and
    1651                     # dt.]
    1652                     portal = portals[st][dt][-1]
    1653                     mux = len([ i for i in portal.interface \
    1654                             if not i.get_attribute('portal')])
    1655                     if mux == self.muxmax:
    1656                         new_portal = True
    1657                         portal_type = "experiment"
    1658                         myname = "%stunnel%d" % (dt, len(portals[st][dt]))
    1659                         desthost = "%stunnel%d" % (st.lower(),
    1660                                 len(portals[st][dt]))
    1661                     else:
    1662                         new_i = topdl.Interface(
    1663                                 substrate=sub.name,
    1664                                 attribute=[
    1665                                     topdl.Attribute(
    1666                                         attribute='ip4_address',
    1667                                         value=tbs[dt]
    1668                                     )
    1669                                 ])
    1670                         portal.interface.append(new_i)
    1671                 else:
    1672                     # First connection to this testbed, make an empty list
    1673                     # and set up to add the new portal below
    1674                     new_portal = True
    1675                     portals[st][dt] = [ ]
    1676                     myname = "%stunnel%d" % (dt, len(portals[st][dt]))
    1677                     desthost = "%stunnel%d" % (st.lower(), len(portals[st][dt]))
    1678 
    1679                     if dt == master or st == master: portal_type = "both"
    1680                     else: portal_type = "experiment"
    1681 
    1682                 if new_portal:
    1683                     infs = (
    1684                             (segment_substrate[st][dt].name,
    1685                                 (('portal', 'true'),)),
    1686                             (sub.name,
    1687                                 (('ip4_address', tbs[dt]),))
    1688                         )
    1689                     portal, info  =  self.new_portal_node(st, dt, tbparams,
    1690                             master, eid, myname, desthost, portal_type,
    1691                             infs, conn_type="ssh", conn_attrs=[], expid=expid)
    1692 
    1693                     topo[st].elements.append(portal)
    1694                     portals[st][dt].append(portal)
    1695                     connInfo[st].append(info)
    1696 
    1697     def add_control_portal(self, st, dt, master, eid, topo, tbparams, connInfo, expid):
    1698         # Add to the master testbed
    1699         tsubstrate, segment_element = \
    1700                 self.new_portal_substrate(st, dt, eid, tbparams, expid)
    1701         myname = "%stunnel" % dt
    1702         desthost = "%stunnel" % st
    1703 
    1704         portal, info = self.new_portal_node(st, dt, tbparams, master,
    1705                 eid, myname, desthost, "control",
    1706                 ((tsubstrate.name,(('portal','true'),)),), conn_type="ssh",
    1707                 conn_attrs=[], expid=expid)
    1708 
    1709         topo[st].substrates.append(tsubstrate)
    1710         topo[st].elements.append(segment_element)
    1711         topo[st].elements.append(portal)
    1712         if not connInfo.has_key(st):
    1713             connInfo[st] = [ ]
    1714         connInfo[st].append(info)
    1715 
    1716     def new_dragon_portal(self, st, dt, master, eid, myip, dip, idx,
    1717             substrate, tbparams, expid):
    1718         # Add to the master testbed
    1719         myname = "%stunnel" % dt
    1720         desthost = "%s" % ip_addr(dip)
    1721 
    1722         portal, info = self.new_portal_node(st, dt, tbparams, master,
    1723                 eid, myname, desthost, "control",
    1724                 ((substrate.name,(
    1725                     ('portal','true'),
    1726                     ('ip4_address', "%s" % ip_addr(myip)),)),),
    1727                 conn_type="transit", conn_attrs=[], expid=expid)
    1728 
    1729         return portal
    1730 
    1731     def add_portals(self, top, topo, eid, master, tbparams, ip_allocator,
    1732             connInfo, expid):
    1733         """
    1734         For each substrate in the main topology, find those that
    1735         have nodes on more than one testbed.  Insert portal nodes
    1736         into the copies of those substrates on the sub topologies.
    1737         """
    1738         segment_substrate = { }
    1739         portals = { }
    1740         for s in top.substrates:
    1741             # tbs will contain an ip address on this subsrate that is in
    1742             # each testbed.
    1743             tbs = { }
    1744             for i in s.interfaces:
    1745                 e = i.element
    1746                 tb = e.get_attribute('testbed')
    1747                 if tb and not tbs.has_key(tb):
    1748                     for i in e.interface:
    1749                         if s in i.subs:
    1750                             tbs[tb]= i.get_attribute('ip4_address')
    1751             if len(tbs) < 2:
    1752                 continue
    1753 
    1754             # DRAGON will not create multi-site vlans yet
    1755             if len(tbs) == 2 and \
    1756                     all([tbparams[x].has_key('dragon') for x in tbs]):
    1757                 self.create_dragon_substrate(s, topo, tbs, tbparams,
    1758                         master, eid, connInfo, expid)
    1759             else:
    1760                 self.insert_internet_portals(s, topo, tbs, tbparams, master,
    1761                         eid, segment_substrate, portals, connInfo, expid)
    1762 
    1763         # Make sure that all the slaves have a control portal back to the
    1764         # master.
    1765         for tb in [ t for t in tbparams.keys() if t != master ]:
    1766             if len([e for e in topo[tb].elements \
    1767                     if isinstance(e, topdl.Computer) and \
    1768                     e.get_attribute('portal') and \
    1769                     e.get_attribute('portal_type') == 'both']) == 0:
    1770 
    1771                 if tbparams[master].has_key('dragon') \
    1772                         and tbparams[tb].has_key('dragon'):
    1773 
    1774                     idx = len([x for x in topo.keys() \
    1775                             if x.startswith('dragon')])
    1776                     dip, leng = ip_allocator.allocate(4)
    1777                     dip += 1
    1778                     mip = dip+1
    1779                     csub = topdl.Substrate(
    1780                             name="dragon-control-%s" % tb,
    1781                             capacity=topdl.Capacity(100000.0, 'max'),
    1782                             attribute=[
    1783                                 topdl.Attribute(
    1784                                     attribute='portal',
    1785                                     value='true'
    1786                                     )
    1787                                 ]
    1788                             )
    1789                     seg = topdl.Segment(
    1790                             id= tbparams[master]['allocID'],
    1791                             type='emulab',
    1792                             uri = self.tbmap.get(master, None),
    1793                             interface=[
    1794                                 topdl.Interface(
    1795                                     substrate=csub.name),
    1796                                 ],
    1797                             attribute = [
    1798                                 topdl.Attribute(attribute=n, value=v)
    1799                                     for n, v in (\
    1800                                         ('domain',
    1801                                             tbparams[master].get('domain',
    1802                                                 ".example.com")),
    1803                                         ('experiment', "%s/%s" % \
    1804                                                 (tbparams[master].get(
    1805                                                     'project',
    1806                                                     'project'),
    1807                                                     eid)),)
    1808                                 ],
    1809                             )
    1810                     portal = self.new_dragon_portal(tb, master,
    1811                             master, eid, dip, mip, idx, csub, tbparams, expid)
    1812                     topo[tb].substrates.append(csub)
    1813                     topo[tb].elements.append(portal)
    1814                     topo[tb].elements.append(seg)
    1815 
    1816                     mcsub = csub.clone()
    1817                     seg = topdl.Segment(
    1818                             id= tbparams[tb]['allocID'],
    1819                             type='emulab',
    1820                             uri = self.tbmap.get(tb, None),
    1821                             interface=[
    1822                                 topdl.Interface(
    1823                                     substrate=csub.name),
    1824                                 ],
    1825                             attribute = [
    1826                                 topdl.Attribute(attribute=n, value=v)
    1827                                     for n, v in (\
    1828                                         ('domain',
    1829                                             tbparams[tb].get('domain',
    1830                                                 ".example.com")),
    1831                                         ('experiment', "%s/%s" % \
    1832                                                 (tbparams[tb].get('project',
    1833                                                     'project'),
    1834                                                     eid)),)
    1835                                 ],
    1836                             )
    1837                     portal = self.new_dragon_portal(master, tb, master,
    1838                             eid, mip, dip, idx, mcsub, tbparams, expid)
    1839                     topo[master].substrates.append(mcsub)
    1840                     topo[master].elements.append(portal)
    1841                     topo[master].elements.append(seg)
    1842                     for t in (master, tb):
    1843                         topo[t].incorporate_elements()
    1844 
    1845                     self.create_dragon_substrate(csub, topo,
    1846                             {tb: ip_addr(mip), master: ip_addr(dip)},
    1847                             tbparams, master, eid, connInfo,
    1848                             expid)
    1849                 else:
    1850                     self.add_control_portal(master, tb, master, eid, topo,
    1851                             tbparams, connInfo, expid)
    1852                     self.add_control_portal(tb, master, master, eid, topo,
    1853                             tbparams, connInfo, expid)
    1854 
    1855         # Connect the portal nodes into the topologies and clear out
    1856         # substrates that are not in the topologies
    1857         for tb in tbparams.keys():
    1858             topo[tb].incorporate_elements()
    1859             topo[tb].substrates = \
    1860                     [s for s in topo[tb].substrates \
    1861                         if len(s.interfaces) >0]
    1862 
    18631332    def wrangle_software(self, expid, top, topo, tbparams):
    18641333        """
     
    21871656                    self.auth.set_attribute(asignee, "%s/%s" % (configpath, f))
    21881657
    2189             self.add_portals(top, topo, eid, master, tbparams, ip_allocator,
     1658            part = experiment_partition(self.auth, self.store_url, self.tbmap,
     1659                    self.muxmax)
     1660            part.add_portals(top, topo, eid, master, tbparams, ip_allocator,
    21901661                    connInfo, expid)
    21911662            # Now get access to the dynamic testbeds
Note: See TracChangeset for help on using the changeset viewer.