Merge branch 'master' into eucalyptus-devel
authorMarco Yuen <marcoy@gmail.com>
Mon, 25 Jul 2011 16:05:31 +0000 (12:05 -0400)
committerMarco Yuen <marcoy@gmail.com>
Mon, 25 Jul 2011 16:05:31 +0000 (12:05 -0400)
Conflicts:
sfa/managers/aggregate_manager_eucalyptus.py

28 files changed:
sfa.spec
sfa/managers/aggregate_manager_eucalyptus.py
sfa/managers/aggregate_manager_pl.py
sfa/managers/eucalyptus/eucalyptus.rnc
sfa/managers/eucalyptus/eucalyptus.rng
sfa/managers/slice_manager_pl.py
sfa/managers/vini/vini.rnc
sfa/managers/vini/vini.rng
sfa/plc/aggregate.py
sfa/plc/api.py
sfa/plc/sfa-import-plc.py
sfa/rspecs/pg_rspec.py
sfa/rspecs/pg_rspec_converter.py
sfa/rspecs/resources/__init__.py [new file with mode: 0644]
sfa/rspecs/resources/ext/__init__.py [new file with mode: 0644]
sfa/rspecs/resources/ext/planetlab.rnc [new file with mode: 0644]
sfa/rspecs/resources/ext/planetlab.xsd [new file with mode: 0644]
sfa/rspecs/rspec_converter.py
sfa/rspecs/rspec_parser.py
sfa/rspecs/sfa_rspec.py
sfa/rspecs/sfa_rspec_converter.py
sfa/trust/credential.py
sfa/trust/gid.py
sfa/trust/rights.py
sfa/trust/trustedroot.py
sfa/util/sfalogging.py [changed mode: 0755->0644]
sfa/util/threadmanager.py
sfa/util/xrn.py

index 521bcf2..6e9aa59 100644 (file)
--- a/sfa.spec
+++ b/sfa.spec
@@ -1,6 +1,6 @@
 %define name sfa
 %define version 1.0
-%define taglevel 26
+%define taglevel 27
 
 %define release %{taglevel}%{?pldistro:.%{pldistro}}%{?date:.%{date}}
 %global python_sitearch        %( python -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)" )
@@ -196,6 +196,17 @@ fi
 [ "$1" -ge "1" ] && service sfa-cm restart || :
 
 %changelog
+* Fri Jul 8 2011 Tony Mack <tmack@cs.princeton.edu> - sfa-1.0-27
+- ProtoGENI v2 RSpec updates.
+- Convert expiration timestamps with timezone info in credentials to utc.
+- Fixed redundant logging issue. 
+- Improved SliceManager and SFI client logging.
+- Support aggregates that don't support the optional 'call_id' argument. 
+- Only call get_trusted_certs() at aggreage interfaces that support the call.
+- CreateSliver() now handles MyPLC slice attributes/tags.
+- Cache now supports persistence.
+- Hide whitelisted nodes.
+
 * Tue Jun 21 2011 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - sfa-1.0-26
 - fixed issues with sup authority signing
 - fixed bugs in remove_slivers and SliverStatus
index e9969f9..5e96854 100644 (file)
@@ -14,13 +14,16 @@ from lxml import etree as ET
 from sqlobject import *
 
 from sfa.util.faults import *
-from sfa.util.xrn import urn_to_hrn
+from sfa.util.xrn import urn_to_hrn, Xrn
 from sfa.util.rspec import RSpec
 from sfa.server.registry import Registries
 from sfa.trust.credential import Credential
 from sfa.plc.api import SfaAPI
 from sfa.util.plxrn import hrn_to_pl_slicename, slicename_to_hrn
 from sfa.util.callids import Callids
+from sfa.util.sfalogging import sfa_logger
+from sfa.rspecs.sfa_rspec import sfa_rspec_version
+from sfa.util.version import version_core
 
 from threading import Thread
 from time import sleep
@@ -215,36 +218,27 @@ def getEucaConnection():
 # @param sliceHRN The hunman readable name of the slice.
 # @return sting()
 #
-def getKeysForSlice(sliceHRN):
-    logger = logging.getLogger('EucaAggregate')
-    try:
-        # convert hrn to slice name
-        plSliceName = hrn_to_pl_slicename(sliceHRN)
-    except IndexError, e:
-        logger.error('Invalid slice name (%s)' % sliceHRN)
+def getKeysForSlice(api, sliceHRN):
+    logger   = logging.getLogger('EucaAggregate')
+    cred     = api.getCredential()
+    registry = api.registries[api.hrn]
+    keys     = []
+
+    # Get the slice record
+    records = registry.Resolve(sliceHRN, cred)
+    if not records:
+        logging.warn('Cannot find any record for slice %s' % sliceHRN)
         return []
 
-    # Get the slice's information
-    sliceData = api.plshell.GetSlices(api.plauth, {'name':plSliceName})
-    if not sliceData:
-        logger.warn('Cannot get any data for slice %s' % plSliceName)
-        return []
+    # Find who can log into this slice
+    persons = records[0]['persons']
 
-    # It should only return a list with len = 1
-    sliceData = sliceData[0]
+    # Extract the keys from persons records
+    for p in persons:
+        sliceUser = registry.Resolve(p, cred)
+        userKeys = sliceUser[0]['keys']
+        keys += userKeys
 
-    keys = []
-    person_ids = sliceData['person_ids']
-    if not person_ids: 
-        logger.warn('No users in slice %s' % sliceHRN)
-        return []
-
-    persons = api.plshell.GetPersons(api.plauth, person_ids)
-    for person in persons:
-        pkeys = api.plshell.GetKeys(api.plauth, person['key_ids'])
-        for key in pkeys:
-            keys.append(key['key'])
     return ''.join(keys)
 
 ##
@@ -434,7 +428,8 @@ def ListResources(api, creds, options, call_id):
     # get hrn of the original caller
     origin_hrn = options.get('origin_hrn', None)
     if not origin_hrn:
-        origin_hrn = Credential(string=creds[0]).get_gid_caller().get_hrn()
+        origin_hrn = Credential(string=creds).get_gid_caller().get_hrn()
+        # origin_hrn = Credential(string=creds[0]).get_gid_caller().get_hrn()
 
     conn = getEucaConnection()
 
@@ -536,6 +531,11 @@ def CreateSliver(api, xrn, creds, xml, users, call_id):
     schemaXML = ET.parse(EUCALYPTUS_RSPEC_SCHEMA)
     rspecValidator = ET.RelaxNG(schemaXML)
     rspecXML = ET.XML(xml)
+    for network in rspecXML.iterfind("./network"):
+        if network.get('id') != cloud['name']:
+            # Throw away everything except my own RSpec
+            # sfa_logger().error("CreateSliver: deleting %s from rspec"%network.get('id'))
+            network.getparent().remove(network)
     if not rspecValidator(rspecXML):
         error = rspecValidator.error_log.last_error
         message = '%s (line %s)' % (error.message, error.line) 
@@ -552,7 +552,7 @@ def CreateSliver(api, xrn, creds, xml, users, call_id):
     pendingRmInst = []
     for sliceInst in s.instances:
         pendingRmInst.append(sliceInst.instance_id)
-    existingInstGroup = rspecXML.findall('.//euca_instances')
+    existingInstGroup = rspecXML.findall(".//euca_instances")
     for instGroup in existingInstGroup:
         for existingInst in instGroup:
             if existingInst.get('id') in pendingRmInst:
@@ -566,10 +566,10 @@ def CreateSliver(api, xrn, creds, xml, users, call_id):
     conn.terminate_instances(pendingRmInst)
 
     # Process new instance requests
-    requests = rspecXML.findall('.//request')
+    requests = rspecXML.findall(".//request")
     if requests:
         # Get all the public keys associate with slice.
-        pubKeys = getKeysForSlice(s.slice_hrn)
+        pubKeys = getKeysForSlice(api, s.slice_hrn)
         logger.debug('Passing the following keys to the instance:\n%s' % pubKeys)
     for req in requests:
         vmTypeElement = req.getparent()
@@ -642,6 +642,19 @@ def updateMeta():
             dbInst.meta.pub_addr = ipData['pub_addr']
             dbInst.meta.state    = 'running'
 
+def GetVersion(api):
+    xrn=Xrn(api.hrn)
+    request_rspec_versions = [dict(sfa_rspec_version)]
+    ad_rspec_versions = [dict(sfa_rspec_version)]
+    version_more = {'interface':'aggregate',
+                    'testbed':'myplc',
+                    'hrn':xrn.get_hrn(),
+                    'request_rspec_versions': request_rspec_versions,
+                    'ad_rspec_versions': ad_rspec_versions,
+                    'default_ad_rspec': dict(sfa_rspec_version)
+                    }
+    return version_core(version_more)
+
 def main():
     init_server()
 
@@ -652,7 +665,11 @@ def main():
 
     #rspec = ListResources('euca', 'planetcloud.pc.test', 'planetcloud.pc.marcoy', 'test_euca')
     #print rspec
-    print getKeysForSlice('gc.gc.test1')
+
+    server_key_file = '/var/lib/sfa/authorities/server.key'
+    server_cert_file = '/var/lib/sfa/authorities/server.cert'
+    api = SfaAPI(key_file = server_key_file, cert_file = server_cert_file, interface='aggregate')
+    print getKeysForSlice(api, 'gc.gc.test1')
 
 if __name__ == "__main__":
     main()
index 0dd236c..7dd0607 100644 (file)
@@ -8,7 +8,7 @@ import re
 from types import StringTypes
 
 from sfa.util.faults import *
-from sfa.util.xrn import get_authority, hrn_to_urn, urn_to_hrn, Xrn
+from sfa.util.xrn import get_authority, hrn_to_urn, urn_to_hrn, Xrn, urn_to_sliver_id
 from sfa.util.plxrn import slicename_to_hrn, hrn_to_pl_slicename, hostname_to_urn
 from sfa.util.rspec import *
 from sfa.util.specdict import *
@@ -117,14 +117,14 @@ def SliverStatus(api, slice_xrn, creds, call_id):
     api.logger.info(hrn)
     slicename = hrn_to_pl_slicename(hrn)
     
-    slices = api.plshell.GetSlices(api.plauth, [slicename], ['node_ids','person_ids','name','expires'])
+    slices = api.plshell.GetSlices(api.plauth, [slicename], ['slice_id', 'node_ids','person_ids','name','expires'])
     if len(slices) == 0:        
         raise Exception("Slice %s not found (used %s as slicename internally)" % (slice_xrn, slicename))
     slice = slices[0]
     
     # report about the local nodes only
     nodes = api.plshell.GetNodes(api.plauth, {'node_id':slice['node_ids'],'peer_id':None},
-                                 ['hostname', 'site_id', 'boot_state', 'last_contact'])
+                                 ['node_id', 'hostname', 'site_id', 'boot_state', 'last_contact'])
     site_ids = [node['site_id'] for node in nodes]
     sites = api.plshell.GetSites(api.plauth, site_ids, ['site_id', 'login_base'])
     sites_dict = dict ( [ (site['site_id'],site['login_base'] ) for site in sites ] )
@@ -133,7 +133,8 @@ def SliverStatus(api, slice_xrn, creds, call_id):
     top_level_status = 'unknown'
     if nodes:
         top_level_status = 'ready'
-    result['geni_urn'] = Xrn(slice_xrn, 'slice').get_urn()
+    slice_urn = Xrn(slice_xrn, 'slice').get_urn()
+    result['geni_urn'] = slice_urn
     result['pl_login'] = slice['name']
     result['pl_expires'] = datetime.datetime.fromtimestamp(slice['expires']).ctime()
     
@@ -145,7 +146,8 @@ def SliverStatus(api, slice_xrn, creds, call_id):
         res['pl_last_contact'] = node['last_contact']
         if node['last_contact'] is not None:
             res['pl_last_contact'] = datetime.datetime.fromtimestamp(node['last_contact']).ctime()
-        res['geni_urn'] = hostname_to_urn(api.hrn, sites_dict[node['site_id']], node['hostname'])
+        sliver_id = urn_to_sliver_id(slice_urn, slice['slice_id'], node['node_id']) 
+        res['geni_urn'] = sliver_id
         if node['boot_state'] == 'boot':
             res['geni_status'] = 'ready'
         else:
@@ -212,9 +214,6 @@ def CreateSliver(api, slice_xrn, creds, rspec_string, users, call_id):
         else:
             existing_slice_attributes.append(slice_tag)  
          
-    #api.logger.debug("requested slice attributes: %s" % str(requested_slice_attributes))
-    #api.logger.debug("removed slice attributes: %s" % str(removed_slice_attributes))
-    #api.logger.debug("existing slice attributes: %s" % str(existing_slice_attributes))
     try:
         if peer:
             api.plshell.UnBindObjectFromPeer(api.plauth, 'slice', slice['slice_id'], peer)
@@ -240,8 +239,8 @@ def CreateSliver(api, slice_xrn, creds, rspec_string, users, call_id):
 
     finally:
         if peer:
-            api.plshell.BindObjectToPeer(api.plauth, 'slice', slice.id, peer, 
-                                         slice.peer_id)
+            api.plshell.BindObjectToPeer(api.plauth, 'slice', slice['slice_id'], peer, 
+                                         slice['peer_id'])
 
     return aggregate.get_rspec(slice_xrn=slice_xrn, version=rspec.version)
 
index bc61ce3..670a01e 100644 (file)
@@ -1,5 +1,7 @@
 start = RSpec
 RSpec = element RSpec {
+    attribute expires { xsd:NMTOKEN },
+    attribute generated { xsd:NMTOKEN },
     attribute type { xsd:NMTOKEN },
     network
 }
index d7a85b4..d8be05e 100644 (file)
@@ -5,10 +5,18 @@
   </start>
   <define name="RSpec">
     <element name="RSpec">
+      <attribute name="expires">
+        <data type="NMTOKEN"/>
+      </attribute>
+      <attribute name="generated">
+        <data type="NMTOKEN"/>
+      </attribute>
       <attribute name="type">
         <data type="NMTOKEN"/>
       </attribute>
-      <ref name="network"/>
+      <oneOrMore>
+        <ref name="network"/>
+      </oneOrMore>
     </element>
   </define>
   <define name="network">
index 2cbc823..f23d4d8 100644 (file)
@@ -44,7 +44,7 @@ def _call_id_supported(api, server):
         code_tag_parts = code_tag.split("-")
 
         version_parts = code_tag_parts[0].split(".")
-        major, minor = version_parts[0], version_parts[1]
+        major, minor = version_parts[0:2]
         rev = code_tag_parts[1]
         if int(major) > 1:
             if int(minor) > 0 or int(rev) > 20:
@@ -84,10 +84,16 @@ def GetVersion(api):
 
 
 def ListResources(api, creds, options, call_id):
-    def _ListResources(server, credential, my_opts, call_id):
+    def _ListResources(server, credential, opts, call_id):
+        
+        my_opts = copy(opts)
         args = [credential, my_opts]
         if _call_id_supported(api, server):
             args.append(call_id)
+        version = api.get_cached_server_version(server)
+        # force ProtoGENI aggregates to give us a v2 RSpec
+        if 'sfa' not in version.keys():
+            my_opts['rspec_version'] = pg_rspec_ad_version 
         try:
             return server.ListResources(*args)
         except Exception, e:
@@ -98,11 +104,9 @@ def ListResources(api, creds, options, call_id):
     # get slice's hrn from options
     xrn = options.get('geni_slice_urn', '')
     (hrn, type) = urn_to_hrn(xrn)
-    my_opts = copy(options)
-    my_opts['geni_compressed'] = False
-    if 'rspec_version' in my_opts:
-        del my_opts['rspec_version']
-
+    if 'geni_compressed' in options:
+        del(options['geni_compressed'])
+    
     # get the rspec's return format from options
     rspec_version = RSpecVersion(options.get('rspec_version'))
     version_string = "rspec_%s" % (rspec_version.get_version_name())
@@ -128,13 +132,13 @@ def ListResources(api, creds, options, call_id):
         # unless the caller is the aggregate's SM
         if caller_hrn == aggregate and aggregate != api.hrn:
             continue
+
         # get the rspec from the aggregate
         server = api.aggregates[aggregate]
-        #threads.run(server.ListResources, credentials, my_opts, call_id)
-        threads.run(_ListResources, server, credentials, my_opts, call_id)
+        threads.run(_ListResources, server, credentials, options, call_id)
 
     results = threads.get_results()
-    rspec_version = RSpecVersion(my_opts.get('rspec_version'))
+    rspec_version = RSpecVersion(options.get('rspec_version'))
     if rspec_version['type'] == pg_rspec_ad_version['type']:
         rspec = PGRSpec()
     else:
@@ -143,7 +147,7 @@ def ListResources(api, creds, options, call_id):
         try:
             rspec.merge(result)
         except:
-            api.logger.info("SM.ListResources: Failed to merge aggregate rspec")
+            api.logger.log_exc("SM.ListResources: Failed to merge aggregate rspec")
 
     # cache the result
     if caching and api.cache and not xrn:
@@ -159,19 +163,16 @@ def CreateSliver(api, xrn, creds, rspec_str, users, call_id):
             # Need to call GetVersion at an aggregate to determine the supported 
             # rspec type/format beofre calling CreateSliver at an Aggregate. 
             server_version = api.get_cached_server_version(server)    
-            if 'sfa' not in aggregate_version and 'geni_api' in aggregate_version:
+            if 'sfa' not in server_version and 'geni_api' in server_version:
                 # sfa aggregtes support both sfa and pg rspecs, no need to convert
                 # if aggregate supports sfa rspecs. otherwise convert to pg rspec
                 rspec = RSpecConverter.to_pg_rspec(rspec)
             args = [xrn, credential, rspec, users]
             if _call_id_supported(api, server):
                 args.append(call_id)
-            try:
-                return server.CreateSliver(*args)
-            except Exception, e:
-                api.logger.warn("CreateSliver failed at %s: %s" %(server.url, str(e)))
+            return server.CreateSliver(*args)
         except: 
-            logger.log_exc('Something wrong in _CreateSliver')
+            logger.log_exc('Something wrong in _CreateSliver with URL %s'%server.url)
 
     if Callids().already_handled(call_id): return ""
     # Validate the RSpec against PlanetLab's schema --disabled for now
@@ -209,7 +210,7 @@ def CreateSliver(api, xrn, creds, rspec_str, users, call_id):
 
 def RenewSliver(api, xrn, creds, expiration_time, call_id):
     def _RenewSliver(server, xrn, creds, expiration_time, call_id):
-        server_version = _get_server_version(api, server)
+        server_version = api.get_cached_server_version(server)
         args =  [xrn, creds, expiration_time, call_id]
         if _call_id_supported(api, server):
             args.append(call_id)
@@ -239,7 +240,7 @@ def RenewSliver(api, xrn, creds, expiration_time, call_id):
 
 def DeleteSliver(api, xrn, creds, call_id):
     def _DeleteSliver(server, xrn, creds, call_id):
-        server_version = _get_server_version(api, server)
+        server_version = api.get_cached_server_version(server)
         args =  [xrn, creds]
         if _call_id_supported(api, server):
             args.append(call_id)
@@ -270,7 +271,7 @@ def DeleteSliver(api, xrn, creds, call_id):
 # first draft at a merging SliverStatus
 def SliverStatus(api, slice_xrn, creds, call_id):
     def _SliverStatus(server, xrn, creds, call_id):
-        server_version = _get_server_version(api, server)
+        server_version = api.get_cached_server_version(server)
         args =  [xrn, creds]
         if _call_id_supported(api, server):
             args.append(call_id)
@@ -312,7 +313,7 @@ caching=True
 #caching=False
 def ListSlices(api, creds, call_id):
     def _ListSlices(server, creds, call_id):
-        server_version = _get_server_version(api, server)
+        server_version = api.get_cached_server_version(api, server)
         args =  [creds]
         if _call_id_supported(api, server):
             args.append(call_id)
index 0be7640..09cf902 100644 (file)
@@ -1,5 +1,7 @@
 start = RSpec
 RSpec = element RSpec { 
+   attribute expires { xsd:NMTOKEN },
+   attribute generated { xsd:NMTOKEN },
    attribute type { xsd:NMTOKEN },
    ( network | request )
 }
index 1545cb5..387c831 100644 (file)
@@ -5,6 +5,12 @@
   </start>
   <define name="RSpec">
     <element name="RSpec">
+      <attribute name="expires">
+        <data type="NMTOKEN"/>
+      </attribute>
+      <attribute name="generated">
+        <data type="NMTOKEN"/>
+      </attribute>
       <attribute name="type">
         <data type="NMTOKEN"/>
       </attribute>
index 76a93ed..bdcbc8a 100644 (file)
@@ -13,6 +13,7 @@ class Aggregate:
     interfaces = {}
     links = {}
     node_tags = {}
+    pl_initscripts = {} 
     prepared=False
     #panos new user options variable
     user_options = {}
@@ -45,6 +46,11 @@ class Aggregate:
             for node_tag in self.api.plshell.GetNodeTags(self.api.plauth):
                 self.node_tags[node_tag['node_tag_id']] = node_tag
 
+    def prepare_pl_initscripts(self, force=False):
+        if not self.pl_initscripts or force:
+            for initscript in self.api.plshell.GetInitScripts(self.api.plauth, {'enabled': True}):
+                self.pl_initscripts[initscript['initscript_id']] = initscript
+
     def prepare(self, force=False):
         if not self.prepared or force:
             self.prepare_sites(force)
@@ -52,6 +58,7 @@ class Aggregate:
             self.prepare_interfaces(force)
             self.prepare_links(force)
             self.prepare_node_tags(force)
+            self.prepare_pl_initscripts()
             # add site/interface info to nodes
             for node_id in self.nodes:
                 node = self.nodes[node_id]
@@ -83,24 +90,40 @@ class Aggregate:
         else:
             rspec = SfaRSpec(type=type, user_options=self.user_options)
 
-
-        rspec.add_nodes(self.nodes.values())
-        rspec.add_interfaces(self.interfaces.values()) 
-        rspec.add_links(self.links.values())
-
+        # get slice details if specified
+        slice = None
         if slice_xrn:
-            # If slicename is specified then resulting rspec is a manifest. 
-            # Add sliver details to rspec and remove 'advertisement' elements
             slice_hrn, _ = urn_to_hrn(slice_xrn)
             slice_name = hrn_to_pl_slicename(slice_hrn)
             slices = self.api.plshell.GetSlices(self.api.plauth, slice_name)
             if slices:
-                slice = slices[0]
-                slivers = []
-                tags = self.api.plshell.GetSliceTags(self.api.plauth, slice['slice_tag_ids'])
-                for node_id in slice['node_ids']:
+                slice = slices[0]            
+
+        # filter out nodes with a whitelist:
+        valid_nodes = [] 
+        for node in self.nodes.values():
+            # only doing this becuase protogeni rspec needs
+            # to advertise available initscripts 
+            node['pl_initscripts'] = self.pl_initscripts
+            if not node['slice_ids_whitelist']:
+                valid_nodes.append(node)
+            elif slice and slice['slice_id'] in node['slice_ids_whitelist']:
+                valid_nodes.append(node)
+    
+        rspec.add_nodes(valid_nodes)
+        rspec.add_interfaces(self.interfaces.values()) 
+        rspec.add_links(self.links.values())
+
+        # add slivers
+        if slice_xrn and slice:
+            slivers = []
+            tags = self.api.plshell.GetSliceTags(self.api.plauth, slice['slice_tag_ids'])
+            for node_id in slice['node_ids']:
+                try:
                     sliver = {}
                     sliver['hostname'] = self.nodes[node_id]['hostname']
+                    sliver['node_id'] = node_id
+                    sliver['slice_id'] = slice['slice_id']    
                     sliver['tags'] = []
                     slivers.append(sliver)
                     for tag in tags:
@@ -112,6 +135,8 @@ class Aggregate:
                             tag_host = self.nodes[tag['node_id']]['hostname']
                             if tag_host == sliver['hostname']:
                                 sliver['tags'].append(tag)
-                rspec.add_slivers(slivers, sliver_urn=slice_xrn)
+                except:
+                    self.api.logger.log_exc('unable to add sliver %s to node %s' % (slice['name'], node_id)) 
+            rspec.add_slivers(slivers, sliver_urn=slice_xrn)
 
         return rspec.toxml(cleanup=True)          
index 200d05c..8d0e806 100644 (file)
@@ -111,16 +111,20 @@ class SfaAPI(BaseAPI):
         self.plauth = {'Username': self.config.SFA_PLC_USER,
                        'AuthMethod': 'password',
                        'AuthString': self.config.SFA_PLC_PASSWORD}
-        try:
-            sys.path.append(os.path.dirname(os.path.realpath("/usr/bin/plcsh")))
-            self.plshell_type = 'direct'
-            import PLC.Shell
-            shell = PLC.Shell.Shell(globals = globals())
-        except:
-            self.plshell_type = 'xmlrpc' 
-            url = self.config.SFA_PLC_URL
-            shell = xmlrpclib.Server(url, verbose = 0, allow_none = True)
+
+        # The native shell (PLC.Shell.Shell) is more efficient than xmlrpc,
+        # but it leaves idle db connections open. use xmlrpc until we can figure
+        # out why PLC.Shell.Shell doesn't close db connection properly     
+        #try:
+        #    sys.path.append(os.path.dirname(os.path.realpath("/usr/bin/plcsh")))
+        #    self.plshell_type = 'direct'
+        #    import PLC.Shell
+        #    shell = PLC.Shell.Shell(globals = globals())
+        #except:
         
+        self.plshell_type = 'xmlrpc' 
+        url = self.config.SFA_PLC_URL
+        shell = xmlrpclib.Server(url, verbose = 0, allow_none = True)
         return shell
 
     def getCredential(self):
@@ -188,7 +192,7 @@ class SfaAPI(BaseAPI):
             auth_hrn = hrn
         auth_info = self.auth.get_auth_info(auth_hrn)
         table = self.SfaTable()
-        records = table.findObjects(hrn)
+        records = table.findObjects({'hrn': hrn, 'type': 'authority+sa'})
         if not records:
             raise RecordNotFound
         record = records[0]
index 45386ea..3dd12d1 100755 (executable)
@@ -28,7 +28,6 @@ from sfa.trust.trustedroot import *
 from sfa.trust.hierarchy import *
 from sfa.util.xrn import Xrn
 from sfa.plc.api import *
-from sfa.util.sfalogging import logger
 from sfa.trust.gid import create_uuid
 from sfa.plc.sfaImport import sfaImport
 
@@ -147,7 +146,7 @@ def main():
     # start importing 
     for site in sites:
         site_hrn = interface_hrn + "." + site['login_base']
-        logger.info("Importing site: %s" % site_hrn)
+        sfaImporter.logger.info("Importing site: %s" % site_hrn)
 
         # import if hrn is not in list of existing hrns or if the hrn exists
         # but its not a site record
index 6ee30db..f7f00dd 100755 (executable)
@@ -32,7 +32,7 @@ pg_rspec_request_version = RSpecVersion(_request_version)
 class PGRSpec(RSpec):
     xml = None
     header = '<?xml version="1.0"?>\n'
-    template = '<rspec xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.protogeni.net/resources/rspec/2" xsi:schemaLocation="http://www.protogeni.net/resources/rspec/2 http://www.protogeni.net/resources/rspec/2/%(rspec_type)s.xsd"/>'
+    template = '<rspec xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.protogeni.net/resources/rspec/2" xsi:schemaLocation="http://www.protogeni.net/resources/rspec/2 http://www.protogeni.net/resources/rspec/2/%(rspec_type)s.xsd" xmlns:flack="http://www.protogeni.net/resources/rspec/ext/flack/1" xmlns:planetlab="http://www.planet-lab.org/resources/ext/planetlab/1" />'
 
     def __init__(self, rspec="", namespaces={}, type=None):
         if not type:
@@ -49,7 +49,10 @@ class PGRSpec(RSpec):
         self.template = self.template % {'rspec_type': rspec_type}
 
         if not namespaces:
-            self.namespaces = {'rspecv2': self.version['namespace']}
+            self.namespaces = {'rspecv2': self.version['namespace'],
+                               'flack': 'http://www.protogeni.net/resources/rspec/ext/flack/1',
+                               'planetlab': 'http://www.planet-lab.org/resources/ext/planetlab/1' }
+
         else:
             self.namespaces = namespaces 
 
@@ -65,16 +68,23 @@ class PGRSpec(RSpec):
        
     def get_network(self):
         network = None 
-        nodes = self.xml.xpath('//rspecv2:node[@component_manager_uuid][1]', namespaces=self.namespaces)
+        nodes = self.xml.xpath('//rspecv2:node[@component_manager_id][1]', namespaces=self.namespaces)
         if nodes:
-            network  = nodes[0].get('component_manager_uuid')
+            network  = nodes[0].get('component_manager_id')
         return network
 
     def get_networks(self):
-        networks = self.xml.xpath('//rspecv2:node[@component_manager_uuid]/@component_manager_uuid', namespaces=self.namespaces)
+        networks = self.xml.xpath('//rspecv2:node[@component_manager_id]/@component_manager_id', namespaces=self.namespaces)
         return set(networks)
 
-    def get_node_elements(self):
+    def get_node_element(self, hostname, network=None):
+        nodes = self.xml.xpath('//rspecv2:node[@component_id[contains(., "%s")]] | node[@component_id[contains(., "%s")]]' % (hostname, hostname), namespaces=self.namespaces)
+        if isinstance(nodes,list) and nodes:
+            return nodes[0]
+        else:
+            return None
+
+    def get_node_elements(self, network=None):
         nodes = self.xml.xpath('//rspecv2:node | //node', namespaces=self.namespaces)
         return nodes
 
@@ -94,15 +104,44 @@ class PGRSpec(RSpec):
 
     def get_nodes_without_slivers(self, network=None):
         return []
+
+    def get_sliver_attributes(self, hostname, network=None):
+        node = self.get_node_element(hostname, network)
+        sliver = node.xpath('./rspecv2:sliver_type', namespaces=self.namespaces)
+        if sliver is not None and isinstance(sliver, list):
+            sliver = sliver[0]
+        return self.attributes_list(sliver)
    
     def get_slice_attributes(self, network=None):
-        return []
+        slice_attributes = []
+        nodes_with_slivers = self.get_nodes_with_slivers(network)
+        # TODO: default sliver attributes in the PG rspec?
+        default_ns_prefix = self.namespaces['rspecv2']
+        for node in nodes_with_slivers:
+            sliver_attributes = self.get_sliver_attributes(node, network)
+            for sliver_attribute in sliver_attributes:
+                name=str(sliver_attribute[0]) 
+                text =str(sliver_attribute[1])
+                attribs = sliver_attribute[2]
+                # we currently only suppor the <initscript> and <flack> attributes 
+                if  'info' in name:
+                    attribute = {'name': 'flack_info', 'value': str(attribs), 'node_id': node}
+                    slice_attributes.append(attribute) 
+                elif 'initscript' in name: 
+                    if attribs is not None and 'name' in attribs:
+                        value = attribs['name']
+                    else:
+                        value = text
+                    attribute = {'name': 'initscript', 'value': value, 'node_id': node}
+                    slice_attributes.append(attribute) 
+
+        return slice_attributes
 
     def attributes_list(self, elem):
         opts = []
         if elem is not None:
             for e in elem:
-                opts.append((e.tag, e.text))
+                opts.append((e.tag, e.text, e.attrib))
         return opts
 
     def get_default_sliver_attributes(self, network=None):
@@ -133,6 +172,11 @@ class PGRSpec(RSpec):
             node_type_tag = etree.SubElement(node_tag, 'hardware_type', name='pc')
             available_tag = etree.SubElement(node_tag, 'available', now='true')
             sliver_type_tag = etree.SubElement(node_tag, 'sliver_type', name='plab-vnode')
+            
+            pl_initscripts = node.get('pl_initscripts', {})
+            for pl_initscript in pl_initscripts.values():
+                etree.SubElement(sliver_type_tag, '{%s}initscript' % self.namespaces['planetlab'], name=pl_initscript['name'])
+
             # protogeni uses the <sliver_type> tag to identify the types of
             # vms available at the node. 
             # only add location tag if longitude and latitude are not null
@@ -149,18 +193,39 @@ class PGRSpec(RSpec):
         # all nodes hould already be present in the rspec. Remove all 
         # nodes that done have slivers
         slivers = self._process_slivers(slivers)
-        sliver_hosts = [sliver['hostname'] for sliver in slivers]
+        slivers_dict = {}
+        for sliver in slivers:
+            slivers_dict[sliver['hostname']] = sliver
         nodes = self.get_node_elements()
         for node in nodes:
             urn = node.get('component_id')
             hostname = xrn_to_hostname(urn)
-            if hostname not in sliver_hosts:
+            if hostname not in slivers_dict:
                 parent = node.getparent()
                 parent.remove(node)
             else:
+                sliver_info = slivers_dict[hostname]
                 node.set('client_id', hostname)
                 if sliver_urn:
-                    node.set('sliver_id', sliver_urn)
+                    slice_id = sliver_info.get('slice_id', -1)
+                    node_id = sliver_info.get('node_id', -1)
+                    sliver_id = urn_to_sliver_id(sliver_urn, slice_id, node_id)
+                    node.set('sliver_id', sliver_id)
+
+                # remove existing sliver_type tags,it needs to be recreated
+                sliver_elem = node.xpath('./rspecv2:sliver_type | ./sliver_type', namespaces=self.namespaces)
+                if sliver_elem and isinstance(sliver_elem, list):
+                    sliver_elem = sliver_elem[0]
+                    node.remove(sliver_elem)
+                    
+                sliver_elem = etree.SubElement(node, 'sliver_type', name='plab-vnode')
+                for tag in sliver_info['tags']:
+                    if tag['tagname'] == 'flack_info':
+                        e = etree.SubElement(sliver_elem, '{%s}info' % self.namespaces['flack'], attrib=eval(tag['value']))
+                    elif tag['tagname'] == 'initscript':
+                        e = etree.SubElement(sliver_elem, '{%s}initscript' % self.namespaces['planetlab'], attrib={'name': tag['value']})
+                            
+                              
      
     def add_default_sliver_attribute(self, name, value, network=None):
         pass
index e9a34eb..4686e4c 100755 (executable)
@@ -51,8 +51,11 @@ class PGRSpecConverter:
         nodes_with_slivers = pg_rspec.get_nodes_with_slivers()
         i = 1
         for pg_node_element in pg_nodes_elements:
-            node_element = sfa_rspec.add_element('node', {'id': 'n'+str(i)}, parent=network_element)
-            urn = pg_node_element.xpath('@component_uuid | @component_id')
+            attribs = dict(pg_node_element.attrib.items()) 
+            attribs['id'] = 'n'+str(i)
+            
+            node_element = sfa_rspec.add_element('node', attribs, parent=network_element)
+            urn = pg_node_element.xpath('@component_id', namespaces=pg_rspec.namespaces)
             if urn:
                 urn = urn[0]
                 hostname = Xrn.urn_split(urn)[-1]
diff --git a/sfa/rspecs/resources/__init__.py b/sfa/rspecs/resources/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/sfa/rspecs/resources/ext/__init__.py b/sfa/rspecs/resources/ext/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/sfa/rspecs/resources/ext/planetlab.rnc b/sfa/rspecs/resources/ext/planetlab.rnc
new file mode 100644 (file)
index 0000000..f1ff971
--- /dev/null
@@ -0,0 +1,13 @@
+#
+## Extension for the "initscript" type for RSpecV2 on PlanetLab
+## Version 1
+##
+
+default namespace = "http://www.planet-lab.org/resources/ext/initscript/1"
+
+Node = element initscript {
+   attribute name { text }
+}
+
+start = Node
+
diff --git a/sfa/rspecs/resources/ext/planetlab.xsd b/sfa/rspecs/resources/ext/planetlab.xsd
new file mode 100644 (file)
index 0000000..cbbaf5b
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+   Extension for the "initscript" type for RSpecV2 on PlanetLab
+   Version 1
+
+-->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
+elementFormDefault="qualified" 
+targetNamespace="http://www.planet-lab.org/resources/ext/planetlab/1" 
+xmlns:planetlab="http://www.planet-lab.org/resources/ext/planetlab/1">
+   <xs:element name="initscript">
+     <xs:complexType>
+       <xs:attribute name="name" use="required"/>
+     </xs:complexType>
+   </xs:element>
+</xs:schema>
index 89f03a4..6f96d4f 100755 (executable)
@@ -17,7 +17,7 @@ class RSpecConverter:
         elif rspec.version['type'] == pg_rspec_ad_version['type']:
             return PGRSpecConverter.to_sfa_rspec(in_rspec)
         else:
-             return in_rspec 
+            return in_rspec 
 
     @staticmethod 
     def to_pg_rspec(in_rspec):
index 8e3bced..b29329b 100755 (executable)
@@ -12,11 +12,13 @@ def parse_rspec(in_rspec):
     if rspec.xml.xpath('//network'):
         #out_rspec = SfaRSpec(in_rspec)
         out_rspec = SfaRSpec()
+        out_rspec.type = 'SFA'
         out_rspec.xml = rspec.xml
     else:
         #out_rspec = PGRSpec(in_rspec)
         # TODO: determine if this is an ad or request
         out_rspec = PGRSpec()
+        out_rspec.type = 'ProtoGENI'
         out_rspec.xml = rspec.xml
     return out_rspec
 
index 5eb34ed..5d8ef07 100755 (executable)
@@ -65,6 +65,7 @@ class SfaRSpec(RSpec):
 
         nodes = [node.strip() for node in nodes]
         return nodes     
+
     def get_nodes_without_slivers(self, network=None): 
         xpath_nodes_without_slivers = '//node[not(sliver)]/hostname/text()'
         xpath_nodes_without_slivers_in_network = '//network[@name="%s"]//node[not(sliver)]/hostname/text()' 
@@ -210,7 +211,7 @@ class SfaRSpec(RSpec):
                      
             node_tag = etree.SubElement(network_tag, 'node')
             if 'network' in node:
-                node_tag.set('component_manager_id', network)
+                node_tag.set('component_manager_id', hrn_to_urn(network, 'authority+sa'))
             if 'urn' in node:
                 node_tag.set('component_id', node['urn']) 
             if 'site_urn' in node:
@@ -316,15 +317,22 @@ class SfaRSpec(RSpec):
         Merge contents for specified rspec with current rspec 
         """
 
+        from sfa.rspecs.rspec_parser import parse_rspec
+        rspec = parse_rspec(in_rspec)
+        if rspec.type.lower() == 'protogeni':
+            from sfa.rspecs.rspec_converter import RSpecConverter
+            in_rspec = RSpecConverter.to_sfa_rspec(in_rspec)
+            
         # just copy over all networks
         current_networks = self.get_networks()
         rspec = SfaRSpec(rspec=in_rspec)
         networks = rspec.get_network_elements()
         for network in networks:
             current_network = network.get('name')
-            if not current_network in current_networks:
+            if current_network and current_network not in current_networks:
                 self.xml.append(network)
                 current_networks.append(current_network)
+            
         
          
 
index 096f422..972835f 100755 (executable)
@@ -45,7 +45,7 @@ class SfaRSpecConverter:
                 location = sfa_node_element.find('location')
                 if location != None:
                     location_attrs = {}      
-                    location_attrs['country'] = locatiton.get('country', 'unknown')
+                    location_attrs['country'] =  location.get('country', 'unknown')
                     location_attrs['latitude'] = location.get('latitiue', 'None')
                     location_attrs['longitude'] = location.get('longitude', 'None')
                     pg_rspec.add_element('location', location_attrs, parent=node_element)
index bd7e7f1..0f5ae15 100644 (file)
@@ -39,7 +39,7 @@ from sfa.util.sfalogging import logger
 from sfa.util.sfatime import utcparse
 from sfa.trust.certificate import Keypair
 from sfa.trust.credential_legacy import CredentialLegacy
-from sfa.trust.rights import Right, Rights
+from sfa.trust.rights import Right, Rights, determine_rights
 from sfa.trust.gid import GID
 from sfa.util.xrn import urn_to_hrn
 
@@ -662,7 +662,7 @@ class Credential(object):
                 # Convert * into the default privileges for the credential's type
                 # Each inherits the delegatability from the * above
                 _ , type = urn_to_hrn(self.gidObject.get_urn())
-                rl = rlist.determine_rights(type, self.gidObject.get_urn())
+                rl = determine_rights(type, self.gidObject.get_urn())
                 for r in rl.rights:
                     r.delegate = deleg
                     rlist.add(r)
@@ -965,6 +965,6 @@ class Credential(object):
 
         if self.parent and dump_parents:
             result += "\nPARENT"
-            result += self.parent.dump(True)
+            result += self.parent.dump_string(True)
 
         return result
index 7650d11..b881a1f 100644 (file)
@@ -180,7 +180,7 @@ class GID(Certificate):
         print self.dump_string(*args,**kwargs)
 
     def dump_string(self, indent=0, dump_parents=False):
-        result="GID\n"
+        result=" "*(indent-2) + "GID\n"
         result += " "*indent + "hrn:" + str(self.get_hrn()) +"\n"
         result += " "*indent + "urn:" + str(self.get_urn()) +"\n"
         result += " "*indent + "uuid:" + str(self.get_uuid()) + "\n"
index 14749cb..db88123 100644 (file)
@@ -60,7 +60,7 @@ def determine_rights(type, name):
     elif type in ["sa", "authority+sa"]:
         rl.add("authority")
         rl.add("sa")
-    elif type in ["ma", "authority+ma", "cm", "authority+cm"]:
+    elif type in ["ma", "authority+ma", "cm", "authority+cm", "sm", "authority+sm"]:
         rl.add("authority")
         rl.add("ma")
     elif type == "authority":
@@ -246,47 +246,3 @@ class Rights:
                 return False
         return True
 
-
-
-    ##
-    # Determine the rights that an object should have. The rights are entirely
-    # dependent on the type of the object. For example, users automatically
-    # get "refresh", "resolve", and "info".
-    #
-    # @param type the type of the object (user | sa | ma | slice | node)
-    # @param name human readable name of the object (not used at this time)
-    #
-    # @return Rights object containing rights
-
-    def determine_rights(self, type, name):
-        rl = Rights()
-
-        # rights seem to be somewhat redundant with the type of the credential.
-        # For example, a "sa" credential implies the authority right, because
-        # a sa credential cannot be issued to a user who is not an owner of
-        # the authority
-
-        if type == "user":
-            rl.add("refresh")
-            rl.add("resolve")
-            rl.add("info")
-        elif type in ["sa", "authority+sa"]:
-            rl.add("authority")
-            rl.add("sa")
-        elif type in ["ma", "authority+ma", "cm", "authority+cm"]:
-            rl.add("authority")
-            rl.add("ma")
-        elif type == "authority":
-            rl.add("authority")
-            rl.add("sa")
-            rl.add("ma")
-        elif type == "slice":
-            rl.add("refresh")
-            rl.add("embed")
-            rl.add("bind")
-            rl.add("control")
-            rl.add("info")
-        elif type == "component":
-            rl.add("operator")
-
-        return rl
index ec8d2f0..2cd4f3b 100644 (file)
@@ -1,44 +1,36 @@
-### $Id$
-### $URL$
+import os.path
+import glob
 
-import os
-
-from sfa.trust.gid import *
+from sfa.trust.gid import GID
 
 class TrustedRootList:
     def __init__(self, dir):
         self.basedir = dir
-        
-        # create the directory to hold the files
-        try:
+        # create the directory to hold the files, if not existing
+        if not os.path.isdir (self.basedir):
             os.makedirs(self.basedir)
-        # if the path already exists then pass
-        except OSError, (errno, strerr):
-            if errno == 17:
-                pass
 
     def add_gid(self, gid):
         fn = os.path.join(self.basedir, gid.get_hrn() + ".gid")
-
         gid.save_to_file(fn)
 
     def get_list(self):
         gid_list = []
-        file_list = os.listdir(self.basedir)
-        for gid_file in file_list:
-            fn = os.path.join(self.basedir, gid_file)
-            if os.path.isfile(fn):
-                gid = GID(filename = fn)
+        pattern=os.path.join(self.basedir,"*.gid")
+        gid_files = glob.glob(pattern)
+        for gid_file in gid_files:
+            # ignore non-files
+            if os.path.isfile(gid_file):
+                gid = GID(filename = gid_file)
                 gid_list.append(gid)
         return gid_list
 
     def get_file_list(self):
         gid_file_list = []
-        
-        file_list = os.listdir(self.basedir)
-        for gid_file in file_list:
-            fn = os.path.join(self.basedir, gid_file)
-            if os.path.isfile(fn):
-                gid_file_list.append(fn)
-
+        pattern=os.path.join(self.basedir,"*.gid")
+        gid_files = glob.glob(pattern)
+        for gid_file in gid_files:
+            # ignore non-files
+            if os.path.isfile(gid_file):
+                gid_file_list.append(gid_file)        
         return gid_file_list
old mode 100755 (executable)
new mode 100644 (file)
index 3991d33..5dd17d0
@@ -28,7 +28,16 @@ class _SfaLogger:
             # This is usually a permissions error becaue the file is
             # owned by root, but httpd is trying to access it.
             tmplogfile=os.getenv("TMPDIR", "/tmp") + os.path.sep + os.path.basename(logfile)
-            handler=logging.handlers.RotatingFileHandler(tmplogfile,maxBytes=1000000, backupCount=5) 
+            # In strange uses, 2 users on same machine might use same code,
+            # meaning they would clobber each others files
+            # We could (a) rename the tmplogfile, or (b)
+            # just log to the console in that case.
+            # Here we default to the console.
+            if os.path.exists(tmplogfile) and not os.access(tmplogfile,os.W_OK):
+                loggername = loggername + "-console"
+                handler = logging.StreamHandler()
+            else:
+                handler=logging.handlers.RotatingFileHandler(tmplogfile,maxBytes=1000000, backupCount=5) 
         handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
         self.logger=logging.getLogger(loggername)
         self.logger.setLevel(level)
@@ -71,6 +80,10 @@ class _SfaLogger:
         
     def warn(self, msg):
         self.logger.warn(msg)
+
+    # some code is using logger.warn(), some is using logger.warning()
+    def warning(self, msg):
+        self.logger.warning(msg)
    
     def error(self, msg):
         self.logger.error(msg)    
index 331f847..5f80670 100755 (executable)
@@ -2,6 +2,7 @@ import threading
 import traceback
 import time
 from Queue import Queue
+from sfa.util.sfalogging import logger
 
 def ThreadedMethod(callable, results, errors):
     """
@@ -15,6 +16,7 @@ def ThreadedMethod(callable, results, errors):
                 try:
                     results.put(callable(*args, **kwds))
                 except Exception, e:
+                    logger.log_exc('ThreadManager: Error in thread: ')
                     errors.put(traceback.format_exc())
                     
         thread = ThreadInstance()
index 752e7a9..c166400 100644 (file)
@@ -8,6 +8,10 @@ def get_authority(hrn): return Xrn(hrn).get_authority_hrn()
 def urn_to_hrn(urn): xrn=Xrn(urn); return (xrn.hrn, xrn.type)
 def hrn_to_urn(hrn,type): return Xrn(hrn, type=type).urn
 
+def urn_to_sliver_id(urn, slice_id, node_id, index=0):
+    urn = urn.replace('+slice+', '+sliver+')    
+    return ":".join([urn, str(slice_id), str(node_id), str(index)])
+
 class Xrn:
 
     ########## basic tools on HRNs