Changeset 3551ae1 for fedd/federation


Ignore:
Timestamp:
May 28, 2010 10:12:41 AM (15 years ago)
Author:
Ted Faber <faber@…>
Branches:
axis_example, compt_changes, info-ops, master, version-3.01, version-3.02
Children:
703859f
Parents:
623a2c9
Message:

access is looking better, but segment is a screaming mess. I'm not sure that division makes any sense at all.

Location:
fedd/federation
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • fedd/federation/protogeni_access.py

    r623a2c9 r3551ae1  
    1010import logging
    1111import subprocess
     12import traceback
    1213
    1314from threading import *
     
    2526from urlparse import urlparse
    2627
     28from access import access_base
     29
    2730import topdl
    2831import list_log
     
    3740fl.addHandler(nullHandler())
    3841
    39 class access:
     42class access(access_base):
    4043    """
    4144    The implementation of access control based on mapping users to projects.
     
    4447    dynamically.  This implements both direct requests and proxies.
    4548    """
    46 
    47     class parse_error(RuntimeError): pass
    48 
    49 
    50     proxy_RequestAccess= service_caller('RequestAccess')
    51     proxy_ReleaseAccess= service_caller('ReleaseAccess')
    5249
    5350    def __init__(self, config=None, auth=None):
     
    5653        """
    5754
    58         def software_list(v):
    59             l = [ ]
    60             if v:
    61                 ps = v.split(" ")
    62                 while len(ps):
    63                     loc, file = ps[0:2]
    64                     del ps[0:2]
    65                     if loc == 'rpm':
    66                         loc = None
    67                     l.append((loc, file))
    68             return l
    69 
    70         # Make sure that the configuration is in place
    71         if not config:
    72             raise RunTimeError("No config to fedd.access")
    73 
    74         self.project_priority = config.getboolean("access", "project_priority")
    75         self.allow_proxy = config.getboolean("access", "allow_proxy")
     55        access_base.__init__(self, config, auth)
    7656
    7757        self.domain = config.get("access", "domain")
    78         self.certdir = config.get("access","certdir")
    7958        self.userconfdir = config.get("access","userconfdir")
    8059        self.userconfcmd = config.get("access","userconfcmd")
     
    8564        self.sshd = config.get("access","sshd")
    8665        self.sshd_config = config.get("access", "sshd_config")
    87         self.create_debug = config.getboolean("access", "create_debug")
    88         self.cleanup = not config.getboolean("access", "leave_tmpfiles")
    8966        self.access_type = config.get("access", "type")
    9067        self.staging_dir = config.get("access", "staging_dir") or "/tmp"
     
    10683        self.node_startcommand = config.get("access", "node_startcommand")
    10784
    108         self.federation_software = software_list(self.federation_software)
    109         self.portal_software = software_list(self.portal_software)
    110         self.local_seer_software = software_list(self.local_seer_software)
     85        self.federation_software = self.software_list(self.federation_software)
     86        self.portal_software = self.software_list(self.portal_software)
     87        self.local_seer_software = self.software_list(self.local_seer_software)
    11188
    11289        self.renewal_interval = config.get("access", "renewal") or (3 * 60 )
     
    11794        self.cm_url = config.get("access", "cm_url")
    11895
    119         self.access = { }
    12096        self.restricted = [ ]
    121         self.projects = { }
    122         self.keys = { }
    123         self.types = { }
    124         self.allocation = { }
    125         self.state = {
    126             'projects': self.projects,
    127             'allocation' : self.allocation,
    128             'keys' : self.keys,
    129             'types': self.types
    130         }
     97
     98        # read_state in the base_class
     99        self.state_lock.acquire()
     100        for a  in ('allocation', 'projects', 'keys', 'types'):
     101            if a not in self.state:
     102                self.state[a] = { }
     103        self.allocation = self.state['allocation']
     104        self.projects = self.state['projects']
     105        self.keys = self.state['keys']
     106        self.types = self.state['types']
     107        # Add the ownership attributes to the authorizer.  Note that the
     108        # indices of the allocation dict are strings, but the attributes are
     109        # fedids, so there is a conversion.
     110        for k in self.state.get('allocation', {}).keys():
     111            for o in self.state['allocation'][k].get('owners', []):
     112                self.auth.set_attribute(o, fedid(hexstr=k))
     113            self.auth.set_attribute(fedid(hexstr=k),fedid(hexstr=k))
     114
     115        self.state_lock.release()
     116
     117
    131118        self.log = logging.getLogger("fedd.access")
    132119        set_log_level(config, "access", self.log)
    133         self.state_lock = Lock()
    134         # XXX: Configurable
    135         self.exports = set(('SMB', 'seer', 'tmcd', 'userconfig'))
    136         self.imports = set(('SMB', 'seer', 'userconfig'))
    137 
    138         if auth: self.auth = auth
    139         else:
    140             self.log.error(\
    141                     "[access]: No authorizer initialized, creating local one.")
    142             auth = authorizer()
    143 
    144         tb = config.get('access', 'testbed')
    145         if tb: self.testbed = [ t.strip() for t in tb.split(',') ]
    146         else: self.testbed = [ ]
    147 
     120
     121        self.access = { }
    148122        if config.has_option("access", "accessdb"):
    149             self.read_access(config.get("access", "accessdb"))
    150 
    151         self.state_filename = config.get("access", "access_state")
    152         print "Calling read_state %s" % self.state_filename
    153         self.read_state()
    154 
    155         # Keep cert_file and cert_pwd coming from the same place
    156         self.cert_file = config.get("access", "cert_file")
    157         if self.cert_file:
    158             self.sert_pwd = config.get("access", "cert_pw")
    159         else:
    160             self.cert_file = config.get("globals", "cert_file")
    161             self.sert_pwd = config.get("globals", "cert_pw")
    162 
    163         self.trusted_certs = config.get("access", "trusted_certs") or \
    164                 config.get("globals", "trusted_certs")
     123            self.read_access(config.get("access", "accessdb"),
     124                    access_obj=self.make_access_info)
    165125
    166126        self.start_segment = proxy_protogeni_segment.start_segment
     
    168128        self.renew_segment = proxy_protogeni_segment.renew_segment
    169129
     130        self.lookup_access = self.lookup_access_base
     131
    170132        self.call_SetValue = service_caller('SetValue')
    171133        self.call_GetValue = service_caller('GetValue')
     134        self.exports = {
     135                'local_seer_control': self.export_local_seer,
     136                'seer_master': self.export_seer_master,
     137                'hide_hosts': self.export_hide_hosts,
     138                }
     139
     140        if not self.local_seer_image or not self.local_seer_software or \
     141                not self.local_seer_start:
     142            if 'local_seer_control' in self.exports:
     143                del self.exports['local_seer_control']
     144
     145        if not self.local_seer_image or not self.local_seer_software or \
     146                not self.seer_master_start:
     147            if 'seer_master' in self.exports:
     148                del self.exports['seer_master']
    172149
    173150        self.RenewSlices()
     
    190167            }
    191168
    192     def read_access(self, config):
    193         """
    194         Read a configuration file and set internal parameters.
    195 
    196         There are access lines of the
    197         form (tb, proj, user) -> user that map the first tuple of
    198         names to the user for for access purposes.  Names in the key (left side)
    199         can include "<NONE> or <ANY>" to act as wildcards or to require the
    200         fields to be empty.  Similarly aproj or auser can be <SAME> or
    201         <DYNAMIC> indicating that either the matching key is to be used or a
    202         dynamic user or project will be created.  These names can also be
    203         federated IDs (fedid's) if prefixed with fedid:.  The user is the
    204         ProtoGENI identity certificate.
    205         Testbed attributes outside the forms above can be given using the
    206         format attribute: name value: value.  The name is a single word and the
    207         value continues to the end of the line.  Empty lines and lines startin
    208         with a # are ignored.
    209 
    210         Parsing errors result in a self.parse_error exception being raised.
    211         """
    212         lineno=0
    213         name_expr = "["+string.ascii_letters + string.digits + "\/\.\-_]+"
    214         fedid_expr = "fedid:[" + string.hexdigits + "]+"
    215         key_name = "(<ANY>|<NONE>|"+fedid_expr + "|"+ name_expr + ")"
    216 
    217         access_str = '\('+key_name+'\s*,\s*'+key_name+'\s*,\s*'+ \
    218                 key_name+'\s*\)\s*->\s*\(('+name_expr +')\s*,\s*('\
    219                         + name_expr + ')\s*,\s*('+name_expr+')\s*,?\s*(' + \
    220                         name_expr+ ')?\)'
    221         access_re = re.compile(access_str, re.IGNORECASE)
    222 
    223 
    224         def parse_name(n):
    225             if n.startswith('fedid:'): return fedid(hexstr=n[len('fedid:'):])
    226             else: return n
    227        
    228         def auth_name(n):
    229             if isinstance(n, basestring):
    230                 if n =='<any>' or n =='<none>': return None
    231                 else: return unicode(n)
    232             else:
    233                 return n
    234 
    235         f = open(config, "r");
    236         for line in f:
    237             lineno += 1
    238             line = line.strip();
    239             if len(line) == 0 or line.startswith('#'):
    240                 continue
    241 
    242             # Access line (t, p, u) -> (a, pw) line
    243             m = access_re.match(line)
    244             if m != None:
    245                 access_key = tuple([ parse_name(x) for x in m.group(1,2,3)])
    246                 auth_key = tuple([ auth_name(x) for x in access_key])
    247                 cert = auth_name(parse_name(m.group(4)))
    248                 user_name = auth_name(parse_name(m.group(5)))
    249                 ssh_key = unicode(m.group(6))
    250                 if m.group(6): pw = unicode(m.group(7))
    251                 else: pw = None
    252 
    253                 self.access[access_key] = (cert, user_name, ssh_key, pw)
    254                 self.auth.set_attribute(auth_key, "access")
    255                 continue
    256 
    257             # Nothing matched to here: unknown line - raise exception
    258             f.close()
    259             raise self.parse_error("Unknown statement at line %d of %s" % \
    260                     (lineno, config))
    261         f.close()
    262 
    263     def write_state(self):
    264         if self.state_filename:
    265             try:
    266                 f = open(self.state_filename, 'w')
    267                 pickle.dump(self.state, f)
    268             except EnvironmentError, e:
    269                 self.log.error("Can't write file %s: %s" % \
    270                         (self.state_filename, e))
    271             except pickle.PicklingError, e:
    272                 self.log.error("Pickling problem: %s" % e)
    273             except TypeError, e:
    274                 self.log.error("Pickling problem (TypeError): %s" % e)
    275 
    276 
    277     def read_state(self):
    278         """
    279         Read a new copy of access state.  Old state is overwritten.
    280 
    281         State format is a simple pickling of the state dictionary.
    282         """
    283         if self.state_filename:
    284             try:
    285                 f = open(self.state_filename, "r")
    286                 self.state = pickle.load(f)
    287                 self.log.debug("[read_state]: Read state from %s" % \
    288                         self.state_filename)
    289             except EnvironmentError, e:
    290                 self.log.warning(("[read_state]: No saved state: " +\
    291                         "Can't open %s: %s") % (self.state_filename, e))
    292             except EOFError, e:
    293                 self.log.warning(("[read_state]: " +\
    294                         "Empty or damaged state file: %s:") % \
    295                         self.state_filename)
    296             except pickle.UnpicklingError, e:
    297                 self.log.warning(("[read_state]: No saved state: " + \
    298                         "Unpickling failed: %s") % e)
    299 
    300             # Add the ownership attributes to the authorizer.  Note that the
    301             # indices of the allocation dict are strings, but the attributes are
    302             # fedids, so there is a conversion.
    303             for k in self.state.get('allocation', {}).keys():
    304                 for o in self.state['allocation'][k].get('owners', []):
    305                     self.auth.set_attribute(o, fedid(hexstr=k))
    306                 self.auth.set_attribute(fedid(hexstr=k),fedid(hexstr=k))
    307 
    308             if self.allocation != self.state['allocation']:
    309                 self.allocation = self.state['allocation']
    310 
    311     def permute_wildcards(self, a, p):
    312         """Return a copy of a with various fields wildcarded.
    313 
    314         The bits of p control the wildcards.  A set bit is a wildcard
    315         replacement with the lowest bit being user then project then testbed.
    316         """
    317         if p & 1: user = ["<any>"]
    318         else: user = a[2]
    319         if p & 2: proj = "<any>"
    320         else: proj = a[1]
    321         if p & 4: tb = "<any>"
    322         else: tb = a[0]
    323 
    324         return (tb, proj, user)
    325 
    326 
    327     def find_access(self, search):
    328         """
    329         Search the access DB for a match on this tuple.  Return the matching
    330         user (protoGENI cert).
    331        
    332         NB, if the initial tuple fails to match we start inserting wildcards in
    333         an order determined by self.project_priority.  Try the list of users in
    334         order (when wildcarded, there's only one user in the list).
    335         """
    336         if self.project_priority: perm = (0, 1, 2, 3, 4, 5, 6, 7)
    337         else: perm = (0, 2, 1, 3, 4, 6, 5, 7)
    338 
    339         for p in perm:
    340             s = self.permute_wildcards(search, p)
    341             # s[2] is None on an anonymous, unwildcarded request
    342             if s[2] != None:
    343                 for u in s[2]:
    344                     if self.access.has_key((s[0], s[1], u)):
    345                         return self.access[(s[0], s[1], u)]
    346             else:
    347                 if self.access.has_key(s):
    348                     return self.access[s]
    349         return None
    350 
    351     def lookup_access(self, req, fid):
    352         """
    353         Determine the allowed access for this request.  Return the access and
    354         which fields are dynamic.
    355 
    356         The fedid is needed to construct the request
    357         """
    358         # Search keys
    359         tb = None
    360         project = None
    361         user = None
    362         # Return values
    363         rp = access_project(None, ())
    364         ru = None
    365         user_re = re.compile("user:\s(.*)")
    366         project_re = re.compile("project:\s(.*)")
    367 
    368         user = [ user_re.findall(x)[0] for x in req.get('credential', []) \
    369                 if user_re.match(x)]
    370         project = [ project_re.findall(x)[0] \
    371                 for x in req.get('credential', []) \
    372                     if project_re.match(x)]
    373 
    374         if len(project) == 1: project = project[0]
    375         elif len(project) == 0: project = None
    376         else:
    377             raise service_error(service_error.req,
    378                     "More than one project credential")
    379 
    380 
    381         user_fedids = [ u for u in user if isinstance(u, fedid)]
    382 
    383         # Determine how the caller is representing itself.  If its fedid shows
    384         # up as a project or a singleton user, let that stand.  If neither the
    385         # usernames nor the project name is a fedid, the caller is a testbed.
    386         if project and isinstance(project, fedid):
    387             if project == fid:
    388                 # The caller is the project (which is already in the tuple
    389                 # passed in to the authorizer)
    390                 owners = user_fedids
    391                 owners.append(project)
    392             else:
    393                 raise service_error(service_error.req,
    394                         "Project asserting different fedid")
    395         else:
    396             if fid not in user_fedids:
    397                 tb = fid
    398                 owners = user_fedids
    399                 owners.append(fid)
    400             else:
    401                 if len(fedids) > 1:
    402                     raise service_error(service_error.req,
    403                             "User asserting different fedid")
    404                 else:
    405                     # Which is a singleton
    406                     owners = user_fedids
    407         # Confirm authorization
    408 
    409         for u in user:
    410             self.log.debug("[lookup_access] Checking access for %s" % \
    411                     ((tb, project, u),))
    412             if self.auth.check_attribute((tb, project, u), 'access'):
    413                 self.log.debug("[lookup_access] Access granted")
    414                 break
    415             else:
    416                 self.log.debug("[lookup_access] Access Denied")
    417         else:
    418             raise service_error(service_error.access, "Access denied")
    419 
    420         # This maps a valid user to the ProtoGENI credentials to use
    421         found = self.find_access((tb, project, user))
    422        
    423         if found == None:
    424             raise service_error(service_error.access,
    425                     "Access denied - cannot map access")
    426         return found, owners
     169    @staticmethod
     170    def make_access_info(s):
     171        """
     172        Split a string of the form (id, id, id, id) ito its constituent tuples
     173        and return them as a tuple.  Use to import access info from the
     174        access_db.
     175        """
     176
     177        ss = s.strip()
     178        if ss.startswith('(') and ss.endswith(')'):
     179            l = [ s.strip() for s  in ss[1:-1].split(",")]
     180            if len(l) == 4:
     181                return tuple(l)
     182            else:
     183                raise self.parse_error(
     184                        "Exactly 4 elements in access info required")
     185        else:
     186            raise self.parse_error("Expecting parenthezied values")
     187
    427188
    428189    def get_handler(self, path, fid):
     
    433194            return (None, None)
    434195
    435     def export_userconf(self, project):
    436         dev_null = None
    437         confid, confcert = generate_fedid("test", dir=self.userconfdir,
    438                 log=self.log)
    439         conffilename = "%s/%s" % (self.userconfdir, str(confid))
    440         cf = None
    441         try:
    442             cf = open(conffilename, "w")
    443             os.chmod(conffilename, stat.S_IRUSR | stat.S_IWUSR)
    444         except EnvironmentError, e:
    445             raise service_error(service_error.internal,
    446                     "Cannot create user configuration data")
    447 
    448         try:
    449             dev_null = open("/dev/null", "a")
    450         except EnvironmentError, e:
    451             self.log.error("export_userconf: can't open /dev/null: %s" % e)
    452 
    453         cmd = "%s %s" % (self.userconfcmd, project)
    454         conf = subprocess.call(cmd.split(" "),
    455                 stdout=cf, stderr=dev_null, close_fds=True)
    456 
    457         self.auth.set_attribute(confid, "/%s" % str(confid))
    458 
    459         return confid, confcert
    460 
    461 
    462     def export_SMB(self, id, state, project, user):
    463         return {
    464                 'id': id,
    465                 'name': 'SMB',
    466                 'visibility': 'export',
    467                 'server': 'http://fs:139',
    468                 'fedAttr': [
    469                         { 'attribute': 'SMBSHARE', 'value': 'USERS' },
    470                         { 'attribute': 'SMBUSER', 'value': user },
    471                         { 'attribute': 'SMBPROJ', 'value': project },
    472                     ]
    473                 }
    474 
    475     def export_seer(self, id, state, project, user):
    476         return {
    477                 'id': id,
    478                 'name': 'seer',
    479                 'visibility': 'export',
    480                 'server': 'http://control:16606',
    481                 }
    482 
    483     def export_tmcd(self, id, state, project, user):
    484         return {
    485                 'id': id,
    486                 'name': 'seer',
    487                 'visibility': 'export',
    488                 'server': 'http://boss:7777',
    489                 }
    490 
    491     def export_userconfig(self, id, state, project, user):
    492         if self.userconfdir and self.userconfcmd \
    493                 and self.userconfurl:
    494             cid, cert = self.export_userconf(project)
    495             state['userconfig'] = unicode(cid)
    496             return {
    497                     'id': id,
    498                     'name': 'userconfig',
    499                     'visibility': 'export',
    500                     'server': "%s/%s" % (self.userconfurl, str(cid)),
    501                     'fedAttr': [
    502                         { 'attribute': 'cert', 'value': cert },
    503                     ]
    504                     }
    505         else:
    506             return None
    507 
    508     def export_services(self, sreq, project, user):
    509         exp = [ ]
    510         state = { }
    511         # XXX: Filthy shortcut here using http: so urlparse will give the right
    512         # answers.
    513         for s in sreq:
    514             sname = s.get('name', '')
    515             svis = s.get('visibility', '')
    516             if svis == 'export':
    517                 if sname in self.exports:
    518                     id = s.get('id', 'no_id')
    519                     if sname == 'SMB':
    520                         exp.append(self.export_SMB(id, state, project, user))
    521                     elif sname == 'seer':
    522                         exp.append(self.export_seer(id, state, project, user))
    523                     elif sname == 'tmcd':
    524                         exp.append(self.export_tmcd(id, state, project, user))
    525                     elif sname == 'userconfig':
    526                         exp.append(self.export_userconfig(id, state,
    527                             project, user))
    528                     elif sname == 'project_export':
    529                         exp.append(self.export_SMB(id, state, project, user))
    530                         exp.append(self.export_seer(id, state, project, user))
    531                         exp.append(self.export_userconfig(id, state,
    532                             project, user))
    533         return (exp, state)
    534 
    535     def build_response(self, alloc_id, ap, services):
     196    def build_access_response(self, alloc_id, services):
    536197        """
    537198        Create the SOAP response.
     
    548209                'fedAttr': [
    549210                    { 'attribute': 'domain', 'value': self.domain } ,
    550                     { 'attribute': 'project', 'value':
    551                         ap['project'].get('name', {}).get('localname', "???") },
    552211                ]
    553212            }
     
    556215                'value': self.dragon_endpoint})
    557216        if self.deter_internal:
    558             print 'adding internal'
    559217            msg['fedAttr'].append({'attribute': 'deter_internal',
    560218                'value': self.deter_internal})
    561         else: print "internal: %s" % self.deter_internal
    562219        #XXX: ??
    563220        if self.dragon_vlans:
     
    571228    def RequestAccess(self, req, fid):
    572229        """
    573         Handle the access request.  Proxy if not for us.
    574 
    575         Parse out the fields and make the allocations or rejections if for us,
    576         otherwise, assuming we're willing to proxy, proxy the request out.
     230        Handle the access request.
    577231        """
    578232
     
    586240            dt = unpack_id(req['destinationTestbed'])
    587241
    588         if dt == None or dt in self.testbed:
    589             # Request for this fedd
    590             found, owners = self.lookup_access(req, fid)
    591             # keep track of what's been added
    592             allocID, alloc_cert = generate_fedid(subj="alloc", log=self.log)
    593             aid = unicode(allocID)
    594 
    595             self.state_lock.acquire()
    596             self.allocation[aid] = { }
    597             # The protoGENI certificate
    598             self.allocation[aid]['credentials'] = found
    599             # The list of owner FIDs
    600             self.allocation[aid]['owners'] = owners
    601             self.write_state()
    602             self.state_lock.release()
    603             for o in owners:
    604                 self.auth.set_attribute(o, allocID)
    605             self.auth.set_attribute(allocID, allocID)
    606 
    607             try:
    608                 f = open("%s/%s.pem" % (self.certdir, aid), "w")
    609                 print >>f, alloc_cert
    610                 f.close()
    611             except EnvironmentError, e:
    612                 raise service_error(service_error.internal,
    613                         "Can't open %s/%s : %s" % (self.certdir, aid, e))
    614             return { 'allocID': { 'fedid': allocID } }
    615         else:
    616             if self.allow_proxy:
    617                 resp = self.proxy_RequestAccess.call_service(dt, req,
    618                             self.cert_file, self.cert_pwd,
    619                             self.trusted_certs)
    620                 if resp.has_key('RequestAccessResponseBody'):
    621                     return resp['RequestAccessResponseBody']
    622                 else:
    623                     return None
    624             else:
    625                 raise service_error(service_error.access,
    626                         "Access proxying denied")
     242        # Request for this fedd
     243        found, match = self.lookup_access(req, fid)
     244        services, svc_state = self.export_services(req.get('service',[]),
     245                None, None)
     246        # keep track of what's been added
     247        allocID, alloc_cert = generate_fedid(subj="alloc", log=self.log)
     248        aid = unicode(allocID)
     249
     250        self.state_lock.acquire()
     251        self.allocation[aid] = { }
     252        # The protoGENI certificate
     253        self.allocation[aid]['credentials'] = found
     254        # The list of owner FIDs
     255        self.allocation[aid]['owners'] = [ fid ]
     256        self.write_state()
     257        self.state_lock.release()
     258        self.auth.set_attribute(fid, allocID)
     259        self.auth.set_attribute(allocID, allocID)
     260
     261        try:
     262            f = open("%s/%s.pem" % (self.certdir, aid), "w")
     263            print >>f, alloc_cert
     264            f.close()
     265        except EnvironmentError, e:
     266            raise service_error(service_error.internal,
     267                    "Can't open %s/%s : %s" % (self.certdir, aid, e))
     268        return self.build_access_response({ 'fedid': allocID }, None)
    627269
    628270
     
    634276            raise service_error(service_error.req, "No request!?")
    635277
    636         if req.has_key('destinationTestbed'):
    637             dt = unpack_id(req['destinationTestbed'])
    638         else:
    639             dt = None
    640 
    641         if dt == None or dt in self.testbed:
    642             # Local request
    643             try:
    644                 if req['allocID'].has_key('localname'):
    645                     auth_attr = aid = req['allocID']['localname']
    646                 elif req['allocID'].has_key('fedid'):
    647                     aid = unicode(req['allocID']['fedid'])
    648                     auth_attr = req['allocID']['fedid']
    649                 else:
    650                     raise service_error(service_error.req,
    651                             "Only localnames and fedids are understood")
    652             except KeyError:
    653                 raise service_error(service_error.req, "Badly formed request")
    654 
    655             self.log.debug("[access] deallocation requested for %s", aid)
    656             if not self.auth.check_attribute(fid, auth_attr):
    657                 self.log.debug("[access] deallocation denied for %s", aid)
    658                 raise service_error(service_error.access, "Access Denied")
    659 
    660             self.state_lock.acquire()
    661             if self.allocation.has_key(aid):
    662                 self.log.debug("Found allocation for %s" %aid)
    663                 del self.allocation[aid]
    664                 self.write_state()
    665                 self.state_lock.release()
    666                 # And remove the access cert
    667                 cf = "%s/%s.pem" % (self.certdir, aid)
    668                 self.log.debug("Removing %s" % cf)
    669                 os.remove(cf)
    670                 return { 'allocID': req['allocID'] }
    671             else:
    672                 self.state_lock.release()
    673                 raise service_error(service_error.req, "No such allocation")
    674 
    675         else:
    676             if self.allow_proxy:
    677                 resp = self.proxy_ReleaseAccess.call_service(dt, req,
    678                             self.cert_file, self.cert_pwd,
    679                             self.trusted_certs)
    680                 if resp.has_key('ReleaseAccessResponseBody'):
    681                     return resp['ReleaseAccessResponseBody']
    682                 else:
    683                     return None
    684             else:
    685                 raise service_error(service_error.access,
    686                         "Access proxying denied")
    687 
    688     def import_store_info(self, cf, connInfo):
    689         """
    690         Pull any import parameters in connInfo in.  We translate them either
    691         into known member names or fedAddrs.
    692         """
    693 
    694         for c in connInfo:
    695             for p in [ p for p in c.get('parameter', []) \
    696                     if p.get('type', '') == 'input']:
    697                 name = p.get('name', None)
    698                 key = p.get('key', None)
    699                 store = p.get('store', None)
    700 
    701                 if name and key and store :
    702                     req = { 'name': key, 'wait': True }
    703                     r = self.call_GetValue(store, req, cf)
    704                     r = r.get('GetValueResponseBody', None)
    705                     if r :
    706                         if r.get('name', '') == key:
    707                             v = r.get('value', None)
    708                             if v is not None:
    709                                 if name == 'peer':
    710                                     c['peer'] = v
    711                                 else:
    712                                     if c.has_key('fedAttr'):
    713                                         c['fedAttr'].append({
    714                                             'attribute': name, 'value': v})
    715                                     else:
    716                                         c['fedAttr']= [{
    717                                             'attribute': name, 'value': v}]
    718                             else:
    719                                 raise service_error(service_error.internal,
    720                                         'None value exported for %s'  % key)
    721                         else:
    722                             raise service_error(service_error.internal,
    723                                     'Different name returned for %s: %s' \
    724                                             % (key, r.get('name','')))
    725                     else:
    726                         raise service_error(service_error.internal,
    727                             'Badly formatted response: no GetValueResponseBody')
    728                 else:
    729                     raise service_error(service_error.internal,
    730                         'Bad Services missing info for import %s' % c)
    731 
    732     def generate_portal_configs(self, topo, pubkey_base, secretkey_base,
    733             tmpdir, master, leid, connInfo, services):
    734 
    735         def conninfo_to_dict(key, info):
    736             """
    737             Make a cpoy of the connection information about key, and flatten it
    738             into a single dict by parsing out any feddAttrs.
    739             """
    740 
    741             rv = None
    742             for i in info:
    743                 if key == i.get('portal', "") or \
    744                         key in [e.get('element', "") \
    745                         for e in i.get('member', [])]:
    746                     rv = i.copy()
    747                     break
    748 
     278        # Local request
     279        try:
     280            if req['allocID'].has_key('localname'):
     281                auth_attr = aid = req['allocID']['localname']
     282            elif req['allocID'].has_key('fedid'):
     283                aid = unicode(req['allocID']['fedid'])
     284                auth_attr = req['allocID']['fedid']
    749285            else:
    750                 return rv
    751 
    752             if 'fedAttr' in rv:
    753                 for a in rv['fedAttr']:
    754                     attr = a.get('attribute', "")
    755                     val = a.get('value', "")
    756                     if attr and attr not in rv:
    757                         rv[attr] = val
    758                 del rv['fedAttr']
    759             return rv
    760 
    761         # XXX: un hardcode this
    762         def client_null(f, s):
    763             print >>f, "Service: %s" % s['name']
    764 
    765         def client_smb(f, s):
    766             print >>f, "Service: %s" % s['name']
    767             smbshare = None
    768             smbuser = None
    769             smbproj = None
    770             for a in s.get('fedAttr', []):
    771                 if a.get('attribute', '') == 'SMBSHARE':
    772                     smbshare = a.get('value', None)
    773                 elif a.get('attribute', '') == 'SMBUSER':
    774                     smbuser = a.get('value', None)
    775                 elif a.get('attribute', '') == 'SMBPROJ':
    776                     smbproj = a.get('value', None)
    777 
    778             if all((smbshare, smbuser, smbproj)):
    779                 print >>f, "SMBshare: %s" % smbshare
    780                 print >>f, "ProjectUser: %s" % smbuser
    781                 print >>f, "ProjectName: %s" % smbproj
    782 
    783         client_service_out = {
    784                 'SMB': client_smb,
    785                 'tmcd': client_null,
    786                 'seer': client_null,
    787                 'userconfig': client_null,
    788             }
    789         # XXX: end un hardcode this
    790 
    791 
    792         seer_out = False
    793         client_out = False
    794         for e in [ e for e in topo.elements \
    795                 if isinstance(e, topdl.Computer) and e.get_attribute('portal')]:
    796             myname = e.name[0]
    797             type = e.get_attribute('portal_type')
    798 
    799             info = conninfo_to_dict(myname, connInfo)
    800 
    801             if not info:
    802286                raise service_error(service_error.req,
    803                         "No connectivity info for %s" % myname)
    804 
    805             peer = info.get('peer', "")
    806             ldomain = self.domain;
    807 
    808             mexp = info.get('masterexperiment',"")
    809             mproj, meid = mexp.split("/", 1)
    810             mdomain = info.get('masterdomain',"")
    811             muser = info.get('masteruser','root')
    812             smbshare = info.get('smbshare', 'USERS')
    813             ssh_port = info.get('ssh_port', '22')
    814 
    815             active = info.get('active', 'False')
    816 
    817             cfn = "%s/%s.gw.conf" % (tmpdir, myname.lower())
    818             tunnelconfig = self.tunnel_config
    819             try:
    820                 f = open(cfn, "w")
    821                 if active == 'True':
    822                     print >>f, "active: True"
    823                     print >>f, "ssh_port: %s" % ssh_port
    824                     if type in ('control', 'both'):
    825                         for s in [s for s in services \
    826                                 if s.get('name', "") in self.imports]:
    827                             p = urlparse(s.get('server', 'http://localhost'))
    828                             print >>f, 'port: remote:%s:%s:%s' % \
    829                                     (p.port, p.hostname, p.port)
    830 
    831                 if tunnelconfig:
    832                     print >>f, "tunnelip: %s" % tunnelconfig
    833                 # XXX: send this an fedattr
    834                 #print >>f, "seercontrol: control.%s.%s%s" % \
    835                         #(meid.lower(), mproj.lower(), mdomain)
    836                 print >>f, "peer: %s" % peer.lower()
    837                 print >>f, "ssh_pubkey: /usr/local/federation/etc/%s" % \
    838                         pubkey_base
    839                 print >>f, "ssh_privkey: /usr/local/federation/etc/%s" % \
    840                         secretkey_base
    841                 f.close()
    842             except EnvironmentError, e:
    843                 raise service_error(service_error.internal,
    844                         "Can't write protal config %s: %s" % (cfn, e))
    845            
    846             # XXX: This little seer config file needs to go away.
    847             if not seer_out:
    848                 try:
    849                     seerfn = "%s/seer.conf" % tmpdir
    850                     f = open(seerfn, "w")
    851                     if not master:
    852                         print >>f, "ControlNode: control.%s.%s%s" % \
    853                             (meid.lower(), mproj.lower(), mdomain)
    854                     print >>f, "ExperimentID: %s" % mexp
    855                     f.close()
    856                 except EnvironmentError, e:
    857                     raise service_error(service_error.internal,
    858                             "Can't write seer.conf: %s" %e)
    859                 seer_out = True
    860 
    861             if not client_out and type in ('control', 'both'):
    862                 try:
    863                     f = open("%s/client.conf" % tmpdir, "w")
    864                     print >>f, "ControlGateway: %s%s" % \
    865                         (myname.lower(), ldomain.lower())
    866                     for s in services:
    867                         if s.get('name',"") in self.imports and \
    868                                 s.get('visibility','') == 'import':
    869                             client_service_out[s['name']](f, s)
    870                     # Does seer need this?
    871                     # print >>f, "ExperimentID: %s/%s" % (mproj, meid)
    872                     f.close()
    873                 except EnvironmentError, e:
    874                     raise service_error(service_error.internal,
    875                             "Cannot write client.conf: %s" %s)
    876                 client_out = True
    877 
    878 
    879     def generate_rspec(self, topo, softdir, master, connInfo):
     287                        "Only localnames and fedids are understood")
     288        except KeyError:
     289            raise service_error(service_error.req, "Badly formed request")
     290
     291        self.log.debug("[access] deallocation requested for %s", aid)
     292        if not self.auth.check_attribute(fid, auth_attr):
     293            self.log.debug("[access] deallocation denied for %s", aid)
     294            raise service_error(service_error.access, "Access Denied")
     295
     296        self.state_lock.acquire()
     297        if self.allocation.has_key(aid):
     298            self.log.debug("Found allocation for %s" %aid)
     299            del self.allocation[aid]
     300            self.write_state()
     301            self.state_lock.release()
     302            # And remove the access cert
     303            cf = "%s/%s.pem" % (self.certdir, aid)
     304            self.log.debug("Removing %s" % cf)
     305            os.remove(cf)
     306            return { 'allocID': req['allocID'] }
     307        else:
     308            self.state_lock.release()
     309            raise service_error(service_error.req, "No such allocation")
     310
     311    def generate_rspec(self, topo, softdir, connInfo):
    880312        t = topo.clone()
    881313
     
    928360        return exp_rspec
    929361
     362    def retrieve_software(self, topo, certfile, softdir):
     363        """
     364        Collect the software that nodes in the topology need loaded and stage
     365        it locally.  This implies retrieving it from the experiment_controller
     366        and placing it into softdir.  Certfile is used to prove that this node
     367        has access to that data (it's the allocation/segment fedid).  Finally
     368        local portal and federation software is also copied to the same staging
     369        directory for simplicity - all software needed for experiment creation
     370        is in softdir.
     371        """
     372        sw = set()
     373        for e in topo.elements:
     374            for s in getattr(e, 'software', []):
     375                sw.add(s.location)
     376        os.mkdir(softdir)
     377        for s in sw:
     378            self.log.debug("Retrieving %s" % s)
     379            try:
     380                get_url(s, certfile, softdir)
     381            except:
     382                t, v, st = sys.exc_info()
     383                raise service_error(service_error.internal,
     384                        "Error retrieving %s: %s" % (s, v))
     385
     386        # Copy local portal node software to the tempdir
     387        for s in (self.portal_software, self.federation_software):
     388            for l, f in s:
     389                base = os.path.basename(f)
     390                copy_file(f, "%s/%s" % (softdir, base))
     391
     392        # Ick.  Put this python rpm in a place that it will get moved into
     393        # the staging area.  It's a hack to install a modern (in a Roman
     394        # sense of modern) python on ProtoGENI
     395        python_rpm ="python2.4-2.4-1pydotorg.i586.rpm"
     396        if os.access("./%s" % python_rpm, os.R_OK):
     397            copy_file("./%s" % python_rpm, "%s/%s" % (softdir, python_rpm))
     398
     399
     400    def initialize_experiment_info(self, attrs, aid, certfile, tmpdir):
     401        """
     402        Gather common configuration files, retrieve or create an experiment
     403        name and project name, and return the ssh_key filenames.  Create an
     404        allocation log bound to the state log variable as well.
     405        """
     406        configs = set(('hosts', 'ssh_pubkey', 'ssh_secretkey'))
     407        ename = None
     408        pubkey_base = None
     409        secretkey_base = None
     410        alloc_log = None
     411
     412        for a in attrs:
     413            if a['attribute'] in configs:
     414                try:
     415                    self.log.debug("Retrieving %s" % a['value'])
     416                    get_url(a['value'], certfile, tmpdir)
     417                except:
     418                    t, v, st = sys.exc_info()
     419                    raise service_error(service_error.internal,
     420                            "Error retrieving %s: %s" % (a.get('value', ""), v))
     421            if a['attribute'] == 'ssh_pubkey':
     422                pubkey_base = a['value'].rpartition('/')[2]
     423            if a['attribute'] == 'ssh_secretkey':
     424                secretkey_base = a['value'].rpartition('/')[2]
     425            if a['attribute'] == 'experiment_name':
     426                ename = a['value']
     427
     428        if not ename:
     429            ename = ""
     430            for i in range(0,5):
     431                ename += random.choice(string.ascii_letters)
     432            self.log.warn("No experiment name: picked one randomly: %s" \
     433                    % ename)
     434
     435        self.state_lock.acquire()
     436        if self.allocation.has_key(aid):
     437            cf, user, ssh_key, cpw = self.allocation[aid]['credentials']
     438            self.allocation[aid]['experiment'] = ename
     439            self.allocation[aid]['log'] = [ ]
     440            # Create a logger that logs to the experiment's state object as
     441            # well as to the main log file.
     442            alloc_log = logging.getLogger('fedd.access.%s' % ename)
     443            h = logging.StreamHandler(
     444                    list_log.list_log(self.allocation[aid]['log']))
     445            # XXX: there should be a global one of these rather than
     446            # repeating the code.
     447            h.setFormatter(logging.Formatter(
     448                "%(asctime)s %(name)s %(message)s",
     449                        '%d %b %y %H:%M:%S'))
     450            alloc_log.addHandler(h)
     451            self.write_state()
     452        else:
     453            self.log.error("No allocation for %s!?" % aid)
     454        self.state_lock.release()
     455
     456        return (ename, pubkey_base, secretkey_base, cf, user, ssh_key,
     457                cpw, alloc_log)
     458
     459    def finalize_experiment(self, topo, starter, aid, alloc_id):
     460        # Copy the assigned names into the return topology
     461        rvtopo = topo.clone()
     462        embedding = [ ]
     463        for n in starter.node:
     464            embedding.append({
     465                'toponame': n,
     466                'physname': ["%s%s" %  (starter.node[n], self.domain)],
     467                })
     468        # Grab the log (this is some anal locking, but better safe than
     469        # sorry)
     470        self.state_lock.acquire()
     471        logv = "".join(self.allocation[aid]['log'])
     472        # It's possible that the StartSegment call gets retried (!).
     473        # if the 'started' key is in the allocation, we'll return it rather
     474        # than redo the setup.
     475        self.allocation[aid]['started'] = {
     476                'allocID': alloc_id,
     477                'allocationLog': logv,
     478                'segmentdescription': {
     479                    'topdldescription': rvtopo.to_dict() },
     480                'embedding': embedding,
     481                }
     482        retval = copy.deepcopy(self.allocation[aid]['started'])
     483        self.write_state()
     484        self.state_lock.release()
     485
     486        return retval
     487
    930488    def StartSegment(self, req, fid):
    931 
    932         configs = set(('hosts', 'ssh_pubkey', 'ssh_secretkey'))
    933 
    934489        err = None  # Any service_error generated after tmpdir is created
    935490        rv = None   # Return value from segment creation
     
    937492        try:
    938493            req = req['StartSegmentRequestBody']
     494            topref = req['segmentdescription']['topdldescription']
    939495        except KeyError:
    940496            raise service_error(service_error.req, "Badly formed request")
     
    959515                return retval
    960516
    961 
    962         if req.has_key('segmentdescription') and \
    963                 req['segmentdescription'].has_key('topdldescription'):
    964             topo = \
    965                 topdl.Topology(**req['segmentdescription']['topdldescription'])
     517        if topref:
     518            topo = topdl.Topology(**topref)
    966519        else:
    967520            raise service_error(service_error.req,
    968521                    "Request missing segmentdescription'")
    969 
    970         master = req.get('master', False)
    971522
    972523        certfile = "%s/%s.pem" % (self.certdir, auth_attr)
     
    979530        # Try block alllows us to clean up temporary files.
    980531        try:
    981             sw = set()
    982             for e in topo.elements:
    983                 for s in getattr(e, 'software', []):
    984                     sw.add(s.location)
    985             os.mkdir(softdir)
    986             for s in sw:
    987                 self.log.debug("Retrieving %s" % s)
    988                 try:
    989                     get_url(s, certfile, softdir)
    990                 except:
    991                     t, v, st = sys.exc_info()
    992                     raise service_error(service_error.internal,
    993                             "Error retrieving %s: %s" % (s, v))
    994 
    995             # Copy local portal node software to the tempdir
    996             for s in (self.portal_software, self.federation_software):
    997                 for l, f in s:
    998                     base = os.path.basename(f)
    999                     copy_file(f, "%s/%s" % (softdir, base))
    1000 
    1001             # Ick.  Put this python rpm in a place that it will get moved into
    1002             # the staging area.  It's a hack to install a modern (in a Roman
    1003             # sense of modern) python on ProtoGENI
    1004             python_rpm ="python2.4-2.4-1pydotorg.i586.rpm"
    1005             if os.access("./%s" % python_rpm, os.R_OK):
    1006                 copy_file("./%s" % python_rpm, "%s/%s" % (softdir, python_rpm))
    1007 
    1008             for a in attrs:
    1009                 if a['attribute'] in configs:
    1010                     try:
    1011                         self.log.debug("Retrieving %s" % a['value'])
    1012                         get_url(a['value'], certfile, tmpdir)
    1013                     except:
    1014                         t, v, st = sys.exc_info()
    1015                         raise service_error(service_error.internal,
    1016                                 "Error retrieving %s: %s" % (s, v))
    1017                 if a['attribute'] == 'ssh_pubkey':
    1018                     pubkey_base = a['value'].rpartition('/')[2]
    1019                 if a['attribute'] == 'ssh_secretkey':
    1020                     secretkey_base = a['value'].rpartition('/')[2]
    1021                 if a['attribute'] == 'experiment_name':
    1022                     ename = a['value']
    1023 
    1024             # If the userconf service was imported, collect the configuration
    1025             # data.
    1026             for s in services:
    1027                 if s.get("name", "") == 'userconfig' \
    1028                         and s.get('visibility',"") == 'import':
    1029 
    1030                     # Collect ther server and certificate info.
    1031                     u = s.get('server', None)
    1032                     for a in s.get('fedAttr', []):
    1033                         if a.get('attribute',"") == 'cert':
    1034                             cert = a.get('value', None)
    1035                             break
    1036                     else:
    1037                         cert = None
    1038 
    1039                     if cert:
    1040                         # Make a temporary certificate file for get_url.  The
    1041                         # finally clause removes it whether something goes
    1042                         # wrong (including an exception from get_url) or not.
    1043                         try:
    1044                             tfos, tn = tempfile.mkstemp(suffix=".pem")
    1045                             tf = os.fdopen(tfos, 'w')
    1046                             print >>tf, cert
    1047                             tf.close()
    1048                             get_url(u, tn, tmpdir, "userconf")
    1049                         except EnvironmentError, e:
    1050                             raise service_error(service.error.internal,
    1051                                     "Cannot create temp file for " +
    1052                                     "userconfig certificates: %s e")
    1053                         except:
    1054                             t, v, st = sys.exc_info()
    1055                             raise service_error(service_error.internal,
    1056                                     "Error retrieving %s: %s" % (u, v))
    1057                         finally:
    1058                             if tn: os.remove(tn)
    1059                     else:
    1060                         raise service_error(service_error.req,
    1061                                 "No certificate for retreiving userconfig")
    1062                     break
    1063 
    1064             self.state_lock.acquire()
    1065             if self.allocation.has_key(aid):
    1066                 cf, user, ssh_key, cpw = self.allocation[aid]['credentials']
    1067                 self.allocation[aid]['experiment'] = ename
    1068                 self.allocation[aid]['log'] = [ ]
    1069                 # Create a logger that logs to the experiment's state object as
    1070                 # well as to the main log file.
    1071                 alloc_log = logging.getLogger('fedd.access.%s' % ename)
    1072                 h = logging.StreamHandler(
    1073                         list_log.list_log(self.allocation[aid]['log']))
    1074                 # XXX: there should be a global one of these rather than
    1075                 # repeating the code.
    1076                 h.setFormatter(logging.Formatter(
    1077                     "%(asctime)s %(name)s %(message)s",
    1078                             '%d %b %y %H:%M:%S'))
    1079                 alloc_log.addHandler(h)
    1080                 self.write_state()
    1081             else:
    1082                 self.log.error("No allocation for %s!?" % aid)
    1083             self.state_lock.release()
    1084 
     532            self.retrieve_software(topo, certfile, softdir)
     533            self.configure_userconf(services, tmpdir)
     534            ename, pubkey_base, secretkey_base, cf, user, ssh_key, \
     535                cpw, alloc_log = self.initialize_experiment_info(attrs,
     536                        aid, certfile, tmpdir)
    1085537            # XXX: we really need to put the import and connection info
    1086538            # generation off longer.
    1087539            self.import_store_info(certfile, connInfo)
    1088             #self.generate_portal_configs(topo, pubkey_base,
    1089                     #secretkey_base, tmpdir, master, ename, connInfo,
    1090                     #services)
    1091540            rspec = self.generate_rspec(topo, "%s/%s/" \
    1092                     % (self.staging_dir, ename), master, connInfo)
     541                    % (self.staging_dir, ename), connInfo)
    1093542
    1094543            starter = self.start_segment(keyfile=ssh_key,
     
    1097546                    cm_url=self.cm_url)
    1098547            rv = starter(self, aid, user, rspec, pubkey_base, secretkey_base,
    1099                     master, ename,
     548                    ename,
    1100549                    "%s/%s" % (self.staging_dir, ename), tmpdir, cf, cpw,
    1101550                    certfile, topo, connInfo, services)
    1102             # Copy the assigned names into the return topology
    1103             rvtopo = topo.clone()
    1104             for e in rvtopo.elements:
    1105                 if isinstance(e, topdl.Computer) and e.get_attribute('testbed'):
    1106                     myname = e.get_attribute('testbed')
    1107                     break
    1108             else: myname = None
    1109 
    1110             embedding = [ ]
    1111             for n in starter.node:
    1112                 embedding.append({
    1113                     'toponame': n,
    1114                     'physname': ["%s%s" %  (starter.node[n], self.domain)],
    1115                     })
    1116 
     551        except EnvironmentError:
     552            err = service_error(service_error.internal, "%s" % e)
    1117553        except service_error, e:
    1118554            err = e
    1119         except e:
    1120             err = service_error(service_error.internal, str(e))
     555        except:
     556            t, v, st = sys.exc_info()
     557            err = service_error(service_error.internal, "%s: %s" % \
     558                    (v, traceback.extract_tb(st)))
    1121559
    1122560        # Walk up tmpdir, deleting as we go
    1123         if self.cleanup:
    1124             self.log.debug("[StartSegment]: removing %s" % tmpdir)
    1125             for path, dirs, files in os.walk(tmpdir, topdown=False):
    1126                 for f in files:
    1127                     os.remove(os.path.join(path, f))
    1128                 for d in dirs:
    1129                     os.rmdir(os.path.join(path, d))
    1130             os.rmdir(tmpdir)
    1131         else:
    1132             self.log.debug("[StartSegment]: not removing %s" % tmpdir)
     561        if self.cleanup: self.remove_dirs(tmpdir)
     562        else: self.log.debug("[StartSegment]: not removing %s" % tmpdir)
    1133563
    1134564        if rv:
    1135             # Grab the log (this is some anal locking, but better safe than
    1136             # sorry)
    1137             self.state_lock.acquire()
    1138             logv = "".join(self.allocation[aid]['log'])
    1139             # It's possible that the StartSegment call gets retried (!).
    1140             # if the 'started' key is in the allocation, we'll return it rather
    1141             # than redo the setup.
    1142             self.allocation[aid]['started'] = {
    1143                     'allocID': req['allocID'],
    1144                     'allocationLog': logv,
    1145                     'segmentdescription': {
    1146                         'topdldescription': rvtopo.to_dict() },
    1147                     'embedding': embedding,
    1148                     }
    1149             self.write_state()
    1150             self.state_lock.release()
    1151 
    1152             return retval
     565            return self.finalize_experiment(topo, starter, aid, req['allocID'])
    1153566        elif err:
    1154567            raise service_error(service_error.federant,
     
    1207620                scred = None
    1208621            self.state_lock.release()
     622
     623            if not os.access(cf, os.R_OK):
     624                self.log.error(
     625                        "[RenewSlices] cred.file %s unreadable, ignoring" % cf)
     626                continue
    1209627
    1210628            # There's a ProtoGENI slice associated with the segment; renew it.
  • fedd/federation/proxy_protogeni_segment.py

    r623a2c9 r3551ae1  
    139139
    140140    def generate_portal_configs(self, parent, topo, pubkey_base,
    141             secretkey_base, tmpdir, master, leid, connInfo, services, nodes):
     141            secretkey_base, tmpdir, leid, connInfo, services, nodes):
    142142
    143143        def conninfo_to_dict(key, info):
     
    218218        for e in [ e for e in topo.elements \
    219219                if isinstance(e, topdl.Computer) and e.get_attribute('portal')]:
    220             myname = e.name[0]
     220            myname = e.name
    221221            type = e.get_attribute('portal_type')
    222222            testbed = e.get_attribute('testbed')
     
    243243
    244244            cfn = "%s/%s.gw.conf" % (tmpdir, myname.lower())
    245             tunnelconfig = parent.attrs.has_key('TunnelCfg')
     245            tunnelconfig = parent.tunnel_config
    246246            try:
    247247                f = open(cfn, "w")
     
    277277                    # dir.
    278278                    print >>f, "ExperimentID: %s/%s" % (mproj, meid)
    279                     if testbed == master:
    280                         print >>f, "SEERBase: True"
    281279                    f.close()
    282280                except EnvironmentError, e:
     
    370368
    371369        for e in [ e for e in topo.elements if isinstance(e, topdl.Computer)]:
    372             vname = e.name[0]
     370            vname = e.name
    373371            node = nodes.get(vname, {})
    374372            pname = node.get('hostname', None)
     
    471469
    472470
    473     def __call__(self, parent, aid, user, rspec, pubkey, secretkey, master,
     471    def __call__(self, parent, aid, user, rspec, pubkey, secretkey,
    474472            ename, stagingdir, tmpdir, certfile, certpw, export_certfile, topo,
    475473            connInfo, services, timeout=0):
     
    489487
    490488        host = parent.staging_host
     489        if not os.access(certfile, os.R_OK):
     490            self.log.error("[start_segment]: Cannot read certfile: %s" % \
     491                    certfile)
     492            return False
    491493        ctxt = fedd_ssl_context(my_cert=certfile, password=certpw)
    492494        # Local software dir
     
    599601                connInfo)
    600602        self.generate_portal_configs(parent, topo, pubkey, secretkey, tmpdir,
    601                 master, ename, connInfo, services, nodes)
     603                ename, connInfo, services, nodes)
    602604
    603605        # Copy software to the staging machine (done after generation to copy
     
    651653            parent.state_lock.release()
    652654
    653         # The startcmds for portals and standard nodes (the Master Slave
    654         # distinction is going away)
    655         gate_cmd = parent.attrs.get('SlaveConnectorStartCmd', '/bin/true')
    656         node_cmd = parent.attrs.get('SlaveNodeStartCmd', 'bin/true')
    657 
    658655        # Now we have configuration to do for ProtoGENI
    659656        self.configure_nodes(topo, nodes, user, parent.staging_host,
    660                 parent.sshd, parent.sshd_config, gate_cmd, node_cmd,
     657                parent.sshd, parent.sshd_config, parent.portal_startcommand,
     658                parent.node_startcommand,
    661659                pubkey, secretkey, parent.federation_software,
    662660                parent.portal_software, stagingdir, tmpdir)
Note: See TracChangeset for help on using the changeset viewer.