- Timestamp:
- Dec 6, 2010 1:56:04 PM (14 years ago)
- Branches:
- axis_example, compt_changes, info-ops, master
- Children:
- cf0ff4f
- Parents:
- d31a171
- Location:
- fedd/federation
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
fedd/federation/experiment_control.py
rd31a171 r5ecb9a3 203 203 "creating local one.") 204 204 auth = authorizer() 205 self.get_access = self.legacy_get_access 205 206 elif self.auth_type == 'abac': 206 207 self.auth = abac_authorizer(load=self.auth_dir) … … 1451 1452 return rv 1452 1453 1453 def create_experiment(self, req, fid): 1454 """ 1455 The external interface to experiment creation called from the 1456 dispatcher. 1457 1458 Creates a working directory, splits the incoming description using the 1459 splitter script and parses out the various subsections using the 1460 classes above. Once each sub-experiment is created, use pooled threads 1461 to instantiate them and start it all up. 1462 """ 1463 1464 req = req.get('CreateRequestBody', None) 1465 if not req: 1466 raise service_error(service_error.req, 1467 "Bad request format (no CreateRequestBody)") 1468 1454 @staticmethod 1455 def get_create_key(req): 1456 """ 1457 Parse the experiment identifiers out of the request (the request body 1458 tag has been removed). Specifically this pulls either the fedid or the 1459 localname out of the experimentID field. A fedid is preferred. If 1460 neither is present or the request does not contain the fields, 1461 service_errors are raised. 1462 """ 1469 1463 # Get the experiment access 1470 1464 exp = req.get('experimentID', None) … … 1472 1466 if exp.has_key('fedid'): 1473 1467 key = exp['fedid'] 1474 expid = key1475 eid = None1476 1468 elif exp.has_key('localname'): 1477 1469 key = exp['localname'] 1478 eid = key1479 expid = None1480 1470 else: 1481 1471 raise service_error(service_error.req, "Unknown lookup type") … … 1483 1473 raise service_error(service_error.req, "No request?") 1484 1474 1485 # Import information from the requester 1486 if self.auth.import_credentials(data_list=req.get('credential', [])): 1487 self.auth.save() 1488 1489 self.check_experiment_access(fid, key) 1490 1491 # Install the testbed map entries supplied with the request into a copy 1492 # of the testbed map. 1493 tbmap = dict(self.tbmap) 1494 for m in req.get('testbedmap', []): 1495 if 'testbed' in m and 'uri' in m: 1496 tbmap[m['testbed']] = m['uri'] 1497 1498 try: 1499 tmpdir = tempfile.mkdtemp(prefix="split-") 1500 os.mkdir(tmpdir+"/keys") 1501 except EnvironmentError: 1502 raise service_error(service_error.internal, "Cannot create tmp dir") 1503 1504 gw_pubkey_base = "fed.%s.pub" % self.ssh_type 1505 gw_secretkey_base = "fed.%s" % self.ssh_type 1506 gw_pubkey = tmpdir + "/keys/" + gw_pubkey_base 1507 gw_secretkey = tmpdir + "/keys/" + gw_secretkey_base 1508 tclfile = tmpdir + "/experiment.tcl" 1509 tbparams = { } 1510 try: 1511 access_user = self.accessdb[fid] 1512 except KeyError: 1513 raise service_error(service_error.internal, 1514 "Access map and authorizer out of sync in " + \ 1515 "create_experiment for fedid %s" % fid) 1516 1517 pid = "dummy" 1518 gid = "dummy" 1519 1520 # The tcl parser needs to read a file so put the content into that file 1521 descr=req.get('experimentdescription', None) 1522 if descr: 1523 file_content=descr.get('ns2description', None) 1524 if file_content: 1525 try: 1526 f = open(tclfile, 'w') 1527 f.write(file_content) 1528 f.close() 1529 except EnvironmentError: 1530 raise service_error(service_error.internal, 1531 "Cannot write temp experiment description") 1532 else: 1533 raise service_error(service_error.req, 1534 "Only ns2descriptions supported") 1535 else: 1536 raise service_error(service_error.req, "No experiment description") 1537 1475 return key 1476 1477 def get_experiment_ids_and_start(self, key, tmpdir): 1478 """ 1479 Get the experiment name, id and access certificate from the state, and 1480 set the experiment state to 'starting'. returns a triple (fedid, 1481 localname, access_cert_file). The access_cert_file is a copy of the 1482 contents of the access certificate, created in the tempdir with 1483 restricted permissions. If things are confused, raise an exception. 1484 """ 1485 1486 expid = eid = None 1538 1487 self.state_lock.acquire() 1539 1488 if self.state.has_key(key): … … 1551 1500 self.state_lock.release() 1552 1501 1553 if not (eid and expid):1554 raise service_error(service_error.internal,1555 "Cannot find local experiment info!?")1556 1557 1502 # make a protected copy of the access certificate so the experiment 1558 1503 # controller can act as the experiment principal. 1559 if expcert and self.auth_type != 'legacy':1504 if expcert: 1560 1505 expcert_file = self.make_temp_certfile(expcert, tmpdir) 1561 1506 if not expcert_file: … … 1565 1510 expcert_file = None 1566 1511 1512 return (eid, expid, expcert_file) 1513 1514 def get_topology(self, req, tmpdir): 1515 """ 1516 Get the ns2 content and put it into a file for parsing. Call the local 1517 or remote parser and return the topdl.Topology. Errors result in 1518 exceptions. req is the request and tmpdir is a work directory. 1519 """ 1520 1521 # The tcl parser needs to read a file so put the content into that file 1522 descr=req.get('experimentdescription', None) 1523 if descr: 1524 file_content=descr.get('ns2description', None) 1525 else: 1526 raise service_error(service_error.req, "No experiment description") 1527 1528 1529 if self.splitter_url: 1530 self.log.debug("Calling remote topdl translator at %s" % \ 1531 self.splitter_url) 1532 top = self.remote_ns2topdl(self.splitter_url, file_content) 1533 else: 1534 tclfile = os.path.join(tmpdir, "experiment.tcl") 1535 if file_content: 1536 try: 1537 f = open(tclfile, 'w') 1538 f.write(file_content) 1539 f.close() 1540 except EnvironmentError: 1541 raise service_error(service_error.internal, 1542 "Cannot write temp experiment description") 1543 else: 1544 raise service_error(service_error.req, 1545 "Only ns2descriptions supported") 1546 pid = "dummy" 1547 gid = "dummy" 1548 eid = "dummy" 1549 1550 tclcmd = [self.tclsh, self.tcl_splitter, '-t', '-x', 1551 str(self.muxmax), '-m', 'dummy'] 1552 1553 tclcmd.extend([pid, gid, eid, tclfile]) 1554 1555 self.log.debug("running local splitter %s", " ".join(tclcmd)) 1556 # This is just fantastic. As a side effect the parser copies 1557 # tb_compat.tcl into the current directory, so that directory 1558 # must be writable by the fedd user. Doing this in the 1559 # temporary subdir ensures this is the case. 1560 tclparser = Popen(tclcmd, stdout=PIPE, close_fds=True, 1561 cwd=tmpdir) 1562 split_data = tclparser.stdout 1563 1564 top = topdl.topology_from_xml(file=split_data, top="experiment") 1565 os.remove(tclfile) 1566 1567 return top 1568 1569 def get_testbed_services(self, req): 1570 """ 1571 Parse the services section of the request into into two dicts mapping 1572 testbed to lists of federated_service objects. The first lists all 1573 exporters of services, and the second all exporters of services that 1574 need control portals int the experiment. 1575 """ 1576 masters = { } 1577 pmasters = { } 1578 for s in req.get('service', []): 1579 # If this is a service request with the importall field 1580 # set, fill it out. 1581 1582 if s.get('importall', False): 1583 s['import'] = [ tb for tb in testbeds \ 1584 if tb not in s.get('export',[])] 1585 del s['importall'] 1586 1587 # Add the service to masters 1588 for tb in s.get('export', []): 1589 if s.get('name', None): 1590 1591 params = { } 1592 for a in s.get('fedAttr', []): 1593 params[a.get('attribute', '')] = a.get('value','') 1594 1595 fser = federated_service(name=s['name'], 1596 exporter=tb, importers=s.get('import',[]), 1597 params=params) 1598 if fser.name == 'hide_hosts' \ 1599 and 'hosts' not in fser.params: 1600 fser.params['hosts'] = \ 1601 ",".join(tb_hosts.get(fser.exporter, [])) 1602 if tb in masters: masters[tb].append(fser) 1603 else: masters[tb] = [fser] 1604 1605 if fser.portal: 1606 if tb not in pmasters: pmasters[tb] = [ fser ] 1607 else: pmasters[tb].append(fser) 1608 else: 1609 self.log.error('Testbed service does not have name " + \ 1610 "and importers') 1611 return masters, pmasters 1612 1613 1614 def create_experiment(self, req, fid): 1615 """ 1616 The external interface to experiment creation called from the 1617 dispatcher. 1618 1619 Creates a working directory, splits the incoming description using the 1620 splitter script and parses out the various subsections using the 1621 classes above. Once each sub-experiment is created, use pooled threads 1622 to instantiate them and start it all up. 1623 """ 1624 1625 req = req.get('CreateRequestBody', None) 1626 if req: 1627 key = self.get_create_key(req) 1628 else: 1629 raise service_error(service_error.req, 1630 "Bad request format (no CreateRequestBody)") 1631 1632 # Import information from the requester 1633 if self.auth.import_credentials(data_list=req.get('credential', [])): 1634 self.auth.save() 1635 1636 # Make sure that the caller can talk to us 1637 self.check_experiment_access(fid, key) 1638 1639 # Install the testbed map entries supplied with the request into a copy 1640 # of the testbed map. 1641 tbmap = dict(self.tbmap) 1642 for m in req.get('testbedmap', []): 1643 if 'testbed' in m and 'uri' in m: 1644 tbmap[m['testbed']] = m['uri'] 1645 1646 # a place to work 1647 try: 1648 tmpdir = tempfile.mkdtemp(prefix="split-") 1649 os.mkdir(tmpdir+"/keys") 1650 except EnvironmentError: 1651 raise service_error(service_error.internal, "Cannot create tmp dir") 1652 1653 gw_pubkey_base = "fed.%s.pub" % self.ssh_type 1654 gw_secretkey_base = "fed.%s" % self.ssh_type 1655 gw_pubkey = tmpdir + "/keys/" + gw_pubkey_base 1656 gw_secretkey = tmpdir + "/keys/" + gw_secretkey_base 1657 tbparams = { } 1658 1659 eid, expid, expcert_file = \ 1660 self.get_experiment_ids_and_start(key, tmpdir) 1661 1662 # This catches exceptions to clear the placeholder if necessary 1567 1663 try: 1568 # This catches exceptions to clear the placeholder if necessary 1664 if not (eid and expid): 1665 raise service_error(service_error.internal, 1666 "Cannot find local experiment info!?") 1569 1667 try: 1570 1668 self.generate_ssh_keys(gw_secretkey, self.ssh_type) … … 1573 1671 "Bad key type (%s)" % self.ssh_type) 1574 1672 1575 # Copy the service request 1576 tb_services = [ s for s in req.get('service',[]) ] 1577 # Translate to topdl 1578 if self.splitter_url: 1579 self.log.debug("Calling remote topdl translator at %s" % \ 1580 self.splitter_url) 1581 top = self.remote_ns2topdl(self.splitter_url, file_content) 1582 else: 1583 tclcmd = [self.tclsh, self.tcl_splitter, '-t', '-x', 1584 str(self.muxmax), '-m', 'dummy'] 1585 1586 tclcmd.extend([pid, gid, eid, tclfile]) 1587 1588 self.log.debug("running local splitter %s", " ".join(tclcmd)) 1589 # This is just fantastic. As a side effect the parser copies 1590 # tb_compat.tcl into the current directory, so that directory 1591 # must be writable by the fedd user. Doing this in the 1592 # temporary subdir ensures this is the case. 1593 tclparser = Popen(tclcmd, stdout=PIPE, close_fds=True, 1594 cwd=tmpdir) 1595 split_data = tclparser.stdout 1596 1597 top = topdl.topology_from_xml(file=split_data, top="experiment") 1598 1673 top = self.get_topology(req, tmpdir) 1674 1675 # Assign the IPs 1599 1676 hosts, ip_allocator = self.allocate_ips_to_topo(top) 1600 1677 # Find the testbeds to look up 1601 testbeds = set([ a.value for e in top.elements \1602 for a in e.attribute \1603 if a.attribute == 'testbed'])1604 1605 1678 tb_hosts = { } 1606 for tb in testbeds: 1607 tb_hosts[tb] = [ e.name for e in top.elements \ 1608 if isinstance(e, topdl.Computer) and \ 1609 e.get_attribute('testbed') and \ 1610 e.get_attribute('testbed') == tb] 1611 1612 masters = { } # testbeds exporting services 1613 pmasters = { } # Testbeds exporting services that 1614 # need portals 1615 for s in tb_services: 1616 # If this is a service request with the importall field 1617 # set, fill it out. 1618 1619 if s.get('importall', False): 1620 s['import'] = [ tb for tb in testbeds \ 1621 if tb not in s.get('export',[])] 1622 del s['importall'] 1623 1624 # Add the service to masters 1625 for tb in s.get('export', []): 1626 if s.get('name', None): 1627 if tb not in masters: 1628 masters[tb] = [ ] 1629 1630 params = { } 1631 if 'fedAttr' in s: 1632 for a in s['fedAttr']: 1633 params[a.get('attribute', '')] = \ 1634 a.get('value','') 1635 1636 fser = federated_service(name=s['name'], 1637 exporter=tb, importers=s.get('import',[]), 1638 params=params) 1639 if fser.name == 'hide_hosts' \ 1640 and 'hosts' not in fser.params: 1641 fser.params['hosts'] = \ 1642 ",".join(tb_hosts.get(fser.exporter, [])) 1643 masters[tb].append(fser) 1644 1645 if fser.portal: 1646 if tb not in pmasters: pmasters[tb] = [ fser ] 1647 else: pmasters[tb].append(fser) 1648 else: 1649 self.log.error('Testbed service does not have name " + \ 1650 "and importers') 1651 1652 1679 testbeds = [ ] 1680 for e in top.elements: 1681 if isinstance(e, topdl.Computer): 1682 tb = e.get_attribute('testbed') or 'default' 1683 if tb in tb_hosts: tb_hosts[tb].append(e.name) 1684 else: 1685 tb_hosts[tb] = [ e.name ] 1686 testbeds.append(tb) 1687 1688 masters, pmasters = self.get_testbed_services(req) 1653 1689 allocated = { } # Testbeds we can access 1654 1690 topo ={ } # Sub topologies 1655 1691 connInfo = { } # Connection information 1656 1692 1657 if self.auth_type == 'legacy': 1658 self.get_legcay_access_to_testbeds(testbeds, access_user, 1659 allocated, tbparams, masters, tbmap) 1660 elif self.auth_type == 'abac': 1661 self.get_access_to_testbeds(testbeds, fid, allocated, 1662 tbparams, masters, tbmap, expid, expcert_file) 1663 else: 1664 raise service_error(service_error.internal, 1665 "Unknown auth_type %s" % self.auth_type) 1693 self.get_access_to_testbeds(testbeds, fid, allocated, 1694 tbparams, masters, tbmap, expid, expcert_file) 1666 1695 1667 1696 self.split_topology(top, topo, testbeds) -
fedd/federation/experiment_control_legacy.py
rd31a171 r5ecb9a3 48 48 """ 49 49 50 def get_legacy_access(self, tb, tbparam, access_user, masters, tbmap): 50 def get_legacy_access(self, tb, tbparam, fid, masters, tbmap, expid=None, 51 expcert=None): 51 52 """ 52 53 Get access to testbed through fedd and set the parameters for that tb … … 67 68 raise service_error(service_error.req, 68 69 "More than one project export is not supported") 70 71 try: 72 access_user = self.accessdb[fid] 73 except KeyError: 74 raise service_error(service_error.internal, 75 "Access map and authorizer out of sync in " + \ 76 "create_experiment for fedid %s" % fid) 69 77 70 78 uri = tbmap.get(testbed_base(tb), None) … … 187 195 188 196 189 def get_legacy_access_to_testbeds(self, testbeds, access_user, allocated,190 tbparams, masters, tbmap):191 """192 Request access to the various testbeds required for this instantiation193 (passed in as testbeds). User, access_user, expoert_project and master194 are used to construct the correct requests. Per-testbed parameters are195 returned in tbparams.196 """197 for tb in testbeds:198 self.get_access(tb, tbparams, access_user, masters, tbmap)199 allocated[tb] = 1200
Note: See TracChangeset
for help on using the changeset viewer.