Changeset 7da9da6


Ignore:
Timestamp:
Jul 30, 2008 3:48:02 PM (16 years ago)
Author:
Ted Faber <faber@…>
Branches:
axis_example, compt_changes, info-ops, master, version-1.30, version-2.00, version-3.01, version-3.02
Children:
ef36c1e
Parents:
21a1c30
Message:

split out project creation. Local project creation works

Location:
fedd
Files:
1 added
3 edited

Legend:

Unmodified
Added
Removed
  • fedd/fedd_messages.wsdl

    r21a1c30 r7da9da6  
    2020
    2121  <message name="AllocateProjectRequestMessage">
    22     <part name="AllocateProjectRequestBody" type="xsd1:projectType"/>
     22    <part name="AllocateProjectRequestBody" type="xsd1:projectAllocType"/>
    2323  </message>
    2424
    2525  <message name="AllocateProjectResponseMessage">
    2626    <part name="AllocateProjectResponseBody" type="xsd1:projectType"/>
    27   </message>
    28 
    29   <message name="AllocateProjectFaultMessage">
    30     <part name="AllocateProjectFaultBody" type="xsd1:faultType"/>
    3127  </message>
    3228
     
    3935      <output message="tns:RequestAccessResponseMessage"/>
    4036      <fault name="RequestAccessFault"
    41         message="tns:RequestAccessFaultMessage"/>
     37        message="tns:FaultMessage"/>
    4238    </operation>
    4339
     
    4642      <output message="tns:AllocateProjectResponseMessage"/>
    4743      <fault name="AllocateProjectFault"
    48         message="tns:AllocateProjectFaultMessage"/>
     44        message="tns:FaultMessage"/>
    4945    </operation>
    5046  </portType>
  • fedd/fedd_proj.py

    r21a1c30 r7da9da6  
    1212
    1313import re
    14 import random
    1514import string
    1615import subprocess
     
    2019from fedd_services import *
    2120from fedd_util import *
     21from fedd_allocate_project import *
    2222import parse_detail
     23from service_error import *
    2324
    2425class fedd_proj:
     
    5859                return "access_proj('%s', [])" % self.name
    5960
    60     # This is used to make the service error reporting independent of the
    61     # transport.  The XMLRPC and SOAP dispatchers will convert it into
    62     # transport-specific errors
    63     class service_error(RuntimeError):
    64         access = 1
    65         proxy= 2
    66         req = 3
    67         server_config = 4
    68         internal = 5
    69         code_str = {
    70             access : "Access Denied",
    71             proxy : "Proxy Error",
    72             req : "Badly Formed Request",
    73             server_config: "Server Configuration Error",
    74             internal : "Internal Error"
    75         }
    76         str_code = dict([ (v, k) for k, v in code_str.iteritems() ])
    77         client_errors = ( req )
    78         server_errors = ( access, proxy, server_config, internal)
    79 
    80         def __init__(self, code=None, desc=None, from_string=None):
    81             self.code = code
    82             self.desc = desc
    83             if code == None:
    84                 self.set_code_from_string(from_string)
    85             RuntimeError.__init__(self, desc)
    86 
    87         def code_string(self, code=None):
    88             code = code or self.code
    89             return fedd_proj.service_error.code_str.get(code)
    90        
    91         def set_code_from_string(self, errstr):
    92             self.code = fedd_proj.service_error.str_code.get(errstr,
    93                    fedd_proj. service_error.internal)
    94             return self.code
    95        
    96         def is_client_error(self):
    97             return self.code in fedd_proj.service_error.client_errors
    98 
    99         def is_server_error(self):
    100             return self.code in fedd_proj.service_error.server_errors
    101 
    10261    # Used to report errors parsing the configuration files, not in providing
    10362    # service
     
    12382        self.fedid_default = "user"
    12483        self.restricted = []
     84
     85        # Delete these
    12586        self.wap = '/usr/testbed/sbin/wap'
    12687        self.newproj = '/usr/testbed/sbin/newproj'
     
    13192        if config != None:
    13293            self.read_config(config)
     94        self.allocate_project = \
     95            fedd_allocate_project_local(self.dynamic_projects)
    13396
    13497    def dump_state(self):
     
    150113        print "Restricted: %s" % str(',').join(sorted(self.restricted))
    151114
    152     def get_id(self, id):
    153         """
    154         Utility to get an object from the polymorphic IDType.
    155        
    156         Only fedids and usernames are currently understood.  If neither is
    157         present None is returned.  If both are present (which is a bug) the
    158         fedid is returned.
    159         """
    160         if id == None:
    161             return None
    162         elif getattr(id, "get_element_fedid", None) != None:
    163             return fedid(id.get_element_fedid())
    164         elif getattr(id, "get_element_username", None) != None:
    165             return id.get_element_username()
    166         else:
    167             return None
    168 
    169115    def get_users(self, obj):
    170116        """
     
    177123            return None
    178124
    179     def random_string(self, s, n=3):
    180         """Append n random ASCII characters to s and return the string"""
    181         rv = s
    182         for i in range(0,n):
    183             rv += random.choice(string.ascii_letters)
    184         return rv
    185 
    186     def write_attr_xml(self, file, root, lines):
    187         """
    188         Write an emulab config file for a dynamic project.
    189 
    190         Format is <root><attribute name=lines[0]>lines[1]</attribute></root>
    191         """
    192         # Convert a pair to an attribute line
    193         out_attr = lambda a,v : \
    194                 '<attribute name="%s"><value>%s</value></attribute>' % (a, v)
    195 
    196         f = os.fdopen(file, "w")
    197         f.write("<%s>\n" % root)
    198         f.write("\n".join([out_attr(*l) for l in lines]))
    199         f.write("</%s>\n" % root)
    200         f.close()
    201 
    202 
    203     def dynamic_project(self, found, ssh):
    204         """Create a dynamic project with ssh access"""
    205         user_fields = [
    206                 ("name", "Federation User %s" % found[1]),
    207                 ("email", "%s-fed@isi.deterlab.net" % found[1]),
    208                 ("password", self.random_string("", 8)),
    209                 ("login", found[1]),
    210                 ("address", "4676 Admiralty"),
    211                 ("city", "Marina del Rey"),
    212                 ("state", "CA"),
    213                 ("zip", "90292"),
    214                 ("country", "USA"),
    215                 ("phone", "310-448-9190"),
    216                 ("title", "None"),
    217                 ("affiliation", "USC/ISI")
    218         ]
    219 
    220         proj_fields = [
    221                 ("name", found[0].name),
    222                 ("short description", "dynamic federated project"),
    223                 ("URL", "http://www.isi.edu/~faber"),
    224                 ("funders", "USC/USU"),
    225                 ("long description", "Federation access control"),
    226                 ("public", "1"),
    227                 ("num_pcs", "100"),
    228                 ("linkedtous", "1")
    229         ]
    230 
    231         # tempfiles for the parameter files
    232         uf, userfile = tempfile.mkstemp(prefix="usr", suffix=".xml",
    233                 dir="/tmp")
    234         pf, projfile = tempfile.mkstemp(prefix="proj", suffix=".xml",
    235                 dir="/tmp")
    236 
    237         # A few more dynamic fields
    238         for s in ssh:
    239             user_fields.append(("pubkey", s))
    240         proj_fields.append(("newuser_xml", userfile))
    241 
    242         # Write out the files
    243         self.write_attr_xml(uf, "user", user_fields)
    244         self.write_attr_xml(pf, "project", proj_fields)
    245 
    246         # Generate the commands (only grantnodetype's are dynamic)
    247         cmds = [
    248                 (self.wap, self.newproj, projfile),
    249                 (self.wap, self.mkproj, found[0].name)
    250                 ]
    251         for nt in found[0].node_types:
    252             cmds.append((self.wap, self.grantnodetype, '-p', found[0].name, nt))
    253 
    254         # Create the projects
    255         rc = 0
    256         for cmd in cmds:
    257             if self.dynamic_projects:
    258                 try:
    259                     rc = subprocess.call(cmd)
    260                 except OSerror, e:
    261                     raise fedd_proj.service_error(\
    262                             fedd_proj.service_error.internal,
    263                             "Dynamic project subprocess creation error "+ \
    264                                     "[%s] (%s)" %  (cmd[1], e.strerror))
    265             else:
    266                 print >>sys.stdout, str(" ").join(cmd)
    267 
    268             if rc != 0:
    269                 raise fedd_proj.service_error(\
    270                         fedd_proj.service_error.internal,
    271                         "Dynamic project subprocess error " +\
    272                                 "[%s] (%d)" % (cmd[1], rc))
    273         # Clean up tempfiles
    274         os.unlink(userfile)
    275         os.unlink(projfile)
    276 
    277    
    278125    def strip_unicode(self, obj):
    279126        """Loosly de-unicode an object"""
     
    298145            ctx = fedd_ssl_context(self.cert_file, tc, password=self.cert_pwd)
    299146        except SSL.SSLError:
    300             raise fedd_proj.service_error(fedd_proj.service_error.server_config,
     147            raise service_error(service_error.server_config,
    301148                    "Server certificates misconfigured")
    302149
     
    320167            resp, method = xmlrpclib.loads(resp)
    321168        except xmlrpclib.Fault, f:
    322             se = fedd_proj.service_error(None, f.faultString, f.faultCode)
     169            se = service_error(None, f.faultString, f.faultCode)
    323170            raise se
    324171        except xmlrpclib.Error, e:
    325             raise fedd_proj.service_error(fedd_proj.service_error.proxy,
     172            raise service_error(service_error.proxy,
    326173                    "Remote XMLRPC Fault: %s" % e)
    327174       
     
    329176            return resp[0]['RequestAccessResponseBody']
    330177        else:
    331             raise fedd_proj.service_error(fedd_proj.service_error.proxy,
     178            raise service_error(service_error.proxy,
    332179                    "Bad proxy response")
    333180
     
    346193            ctx = fedd_ssl_context(self.cert_file, tc, password=self.cert_pwd)
    347194        except SSL.SSLError:
    348             raise fedd_proj.service_error(fedd_proj.service_error.server_config,
     195            raise service_error(service_error.server_config,
    349196                    "Server certificates misconfigured")
    350197
     
    361208            resp = port.RequestAccess(msg)
    362209        except ZSI.ParseException, e:
    363             raise fedd_proj.service_error(fedd_proj.service_error.proxy,
     210            raise service_error(service_error.proxy,
    364211                    "Bad format message (XMLRPC??): %s" %
    365212                    str(e))
     
    369216            return r['RequestAccessResponseBody']
    370217        else:
    371             raise fedd_proj.service_error(fedd_proj.service_error.proxy,
     218            raise service_error(service_error.proxy,
    372219                    "Bad proxy response")
    373220
     
    439286                fedids = [ u for u in user if isinstance(u, type(fid))]
    440287                if len(fedids) > 1:
    441                     raise fedd_proj.service_error(service_error.req,
     288                    raise service_error(service_error.req,
    442289                            "User asserting multiple fedids")
    443290                elif len(fedids) == 1 and fedids[0] != fid:
    444                     raise fedd_proj.service_error(service_error.req,
     291                    raise service_error(service_error.req,
    445292                            "User asserting different fedid")
    446293            project = None
     
    448295        elif principal_type == "project":
    449296            if isinstance(project, type(fid)) and fid != project:
    450                 raise fedd_proj.service_error(service_error.req,
     297                raise service_error(service_error.req,
    451298                        "Project asserting different fedid")
    452299            tb = None
    453300
    454301        # Ready to look up access
    455         print "Lookup %s %s %s: " % (tb, project, user)
    456302        found, user_match = self.find_access((tb, project, user))
    457         print "Found: ", found
    458303       
    459304        if found == None:
    460             raise fedd_proj.service_error(fedd_proj.service_error.access,
     305            raise service_error(service_error.access,
    461306                    "Access denied")
    462307
     
    469314                found[0].name = project
    470315            else :
    471                 raise fedd_proj.service_error(\
    472                         fedd_proj.service_error.server_config,
     316                raise service_error(\
     317                        service_error.server_config,
    473318                        "Project matched <same> when no project given")
    474319        elif found[0].name == "<dynamic>":
    475             found[0].name = self.random_string("project", 3)
     320            found[0].name = None
    476321            dyn_proj = True
    477322
     
    479324            if user_match == "<any>":
    480325                if user != None: found = (found[0], user[0])
    481                 else: raise fedd_proj.service_error(\
    482                         fedd_proj.service_error.server_config,
     326                else: raise service_error(\
     327                        service_error.server_config,
    483328                        "Matched <same> on anonymous request")
    484329            else:
    485330                found = (found[0], user_match)
    486331        elif found[1] == "<dynamic>":
    487             found = (found[0], self.random_string("user", 4))
     332            found = (found[0], None)
    488333            dyn_user = True
    489334       
    490335        return found, (dyn_user, dyn_proj)
    491336
    492     def build_response(self, alloc_id, ap, ssh):
     337    def build_response(self, alloc_id, ap):
    493338        """
    494339        Create the SOAP response.
     
    496341        Build the dictionary description of the response and use
    497342        fedd_utils.pack_soap to create the soap message.  NB that alloc_id is
    498         a fedd_services_types.IDType_Holder pulled from the incoming message
     343        a fedd_services_types.IDType_Holder pulled from the incoming message.
     344        ap is the allocate project message returned from a remote project
     345        allocation (even if that allocation was done locally).
    499346        """
    500347        # Because alloc_id is already a fedd_services_types.IDType_Holder,
     
    508355                    'fileServer': self.fileserver,
    509356                    'eventServer': self.eventserver,
    510                     'project': {
    511                         'name': pack_id(ap[0].name),
    512                         'user': [ {
    513                             'userID': pack_id(ap[1]),
    514                             'access' : [ { 'sshPubkey': x } for x in ssh ],
    515                             }
    516                         ]
    517                     }
     357                    'project': ap['project']
    518358                },
    519359            }
     
    529369            req = req['RequestAccessRequestBody']
    530370        else:
    531             raise fedd_proj.service_error(service_error.req, "No request!?")
     371            raise service_error(service_error.req, "No request!?")
    532372
    533373        if req.has_key('destinationTestbed'):
     
    537377            # Request for this fedd
    538378            found, dyn = self.lookup_access(req, fid)
     379            restricted = None
     380            ap = None
    539381
    540382            # Check for access to restricted nodes
    541383            if req.has_key('resources') and req['resources'].has_key('node'):
    542384                resources = req['resources']
    543                 inaccessible = [ t for n in resources['node'] \
    544                                 if n.has_key('hardware') != None \
     385                restricted = [ t for n in resources['node'] \
     386                                if n.has_key('hardware') \
    545387                                    for t in n['hardware'] \
    546                                         if t in self.restricted and \
    547                                                 t not in found[0].node_types]
     388                                        if t in self.restricted ]
     389                inaccessible = [ t for t in restricted \
     390                                    if t not in found[0].node_types]
    548391                if len(inaccessible) > 0:
    549                     raise fedd_proj.service_error(fedd_proj.service_error.access,
     392                    raise service_error(service_error.access,
    550393                            "Access denied (nodetypes %s)" % \
    551394                            str(', ').join(inaccessible))
     
    555398
    556399            if len(ssh) > 0:
    557                 if dyn[1]: self.dynamic_project(found, ssh)
     400                if dyn[1]:
     401                    # Compose the dynamic project request
     402                    # (only dynamic, dynamic currently allowed)
     403                    preq = { 'project' : {\
     404                                    'user': [ \
     405                                    { 'access': { 'sshPubkey': s } } \
     406                                        for s in ssh ] \
     407                                }\
     408                            }
     409                    if restricted != None and len(restricted) > 0:
     410                        preq['resources'] =  [ {'node': { 'hardware' :  [ h ]\
     411                            } } for h in restricted ]
     412                               
     413
     414                    #self.dynamic_project(found, ssh)
     415                    ap = self.allocate_project.dynamic_project(preq)
     416                    # XXX: fill in response values into the real response
    558417                else: pass    # SSH key additions
    559418            else:
    560                 raise fedd_proj.service_error(service_error.req,
     419                raise service_error(service_error.req,
    561420                        "SSH access parameters required")
    562421
    563             resp = self.build_response(req['allocID'], found, ssh)
     422            resp = self.build_response(req['allocID'], ap)
    564423            return resp
    565424        else:
     
    568427                # Proxy the request using SOAP
    569428                return self.proxy_request(dt, req)
    570             except fedd_proj.service_error, e:
    571                 if e.code == fedd_proj.service_error.proxy: p_fault = None
     429            except service_error, e:
     430                if e.code == service_error.proxy: p_fault = None
    572431                else: raise
    573432            except ZSI.FaultException, f:
     
    584443                body = p_fault.get_element_RequestAccessFaultBody()
    585444                if body != None:
    586                     raise fedd_proj.service_error(body.get_element_code(),
     445                    raise service_error(body.get_element_code(),
    587446                                body.get_element_desc());
    588447                else:
    589                     raise fedd_proj.service_error(\
    590                             fedd_proj.service_error.proxy,
     448                    raise service_error(\
     449                            service_error.proxy,
    591450                            "Undefined fault from proxy??");
    592451
     
    595454
    596455        msg = self.RequestAccess(unpack_soap(req), fedid)
    597        
     456
    598457        resp = RequestAccessResponseMessage()
    599458        resp.set_element_RequestAccessResponseBody(
     
    608467            return xmlrpclib.dumps(({ "RequestAccessResponseBody": msg },))
    609468        else:
    610             raise service_error(fedd_proj.service_error.internal,
     469            raise service_error(service_error.internal,
    611470                    "No response generated?!");
    612471
     
    782641            try:
    783642                return getattr(self, fedd_proj.soap_methods[method])(req, fid)
    784             except fedd_proj.service_error, e:
     643            except service_error, e:
    785644                de = ns0.faultType_Def(
    786645                        (ns0.faultType_Def.schema,
     
    800659            try:
    801660                return getattr(self, fedd_proj.xmlrpc_methods[method])(req, fid)
    802             except fedd_proj.service_error, e:
     661            except service_error, e:
    803662                raise xmlrpclib.Fault(e.code_string(), e.desc)
    804663        else:
  • fedd/fedd_types.xsd

    r21a1c30 r7da9da6  
    139139      <xsd:element name="fedAttr" type="tns:fedAttrType" minOccurs="0"
    140140        maxOccurs="unbounded"/>
     141    </xsd:sequence>
     142  </xsd:complexType>
     143
     144  <xsd:complexType name="projectAllocType">
     145    <xsd:annotation>
     146      <xsd:documentation>
     147        The information needed to create a dynamic project
     148      </xsd:documentation>
     149    </xsd:annotation>
     150    <xsd:sequence>
     151      <xsd:element name="project" type="tns:projectType"/>
     152      <xsd:element name="resources" type="tns:resourcesType"
     153        minOccurs="0" maxOccurs="1"/>
    141154    </xsd:sequence>
    142155  </xsd:complexType>
Note: See TracChangeset for help on using the changeset viewer.