Merge branch 'upstreammaster'
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Wed, 30 Nov 2011 20:34:02 +0000 (21:34 +0100)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Wed, 30 Nov 2011 20:34:02 +0000 (21:34 +0100)
90 files changed:
INSTALL.txt
Makefile
README.txt [deleted file]
config/default_config.xml
config/sfa_component_config
cron.d/readme [new file with mode: 0644]
cron.d/sfa.cron [moved from sfa/cron.d/sfa.cron with 100% similarity]
init.d/sfa [moved from sfa/init.d/sfa with 89% similarity]
init.d/sfa-cm [moved from sfa/init.d/sfa-cm with 100% similarity]
rspec/model/Registry.ecore [deleted file]
rspec/model/planetlab.ecore [deleted file]
rspec/model/planetlab.ecore_diagram [deleted file]
rspec/model/planetlab.genmodel [deleted file]
rspec/model/planetlab.xsd [deleted file]
rspec/sample_rspec.xml [deleted file]
setup.py
sfa.spec
sfa/client/return_value.py [new file with mode: 0644]
sfa/client/sfadump.py
sfa/client/sfi.py
sfa/generic/__init__.py
sfa/importer/sfa-import-plc.py
sfa/importer/sfa-nuke-plc.py
sfa/importer/sfaImport.py
sfa/managers/aggregate_manager.py
sfa/managers/driver.py [new file with mode: 0644]
sfa/managers/registry_manager.py
sfa/managers/slice_manager.py
sfa/methods/CreateGid.py
sfa/methods/CreateSliver.py
sfa/methods/DeleteSliver.py
sfa/methods/GetCredential.py
sfa/methods/GetGids.py
sfa/methods/GetSelfCredential.py
sfa/methods/GetTicket.py
sfa/methods/GetVersion.py
sfa/methods/List.py
sfa/methods/ListResources.py
sfa/methods/ListSlices.py
sfa/methods/RedeemTicket.py
sfa/methods/Register.py
sfa/methods/Remove.py
sfa/methods/RenewSliver.py
sfa/methods/Resolve.py
sfa/methods/ResolveGENI.py
sfa/methods/Shutdown.py
sfa/methods/SliverStatus.py
sfa/methods/Start.py
sfa/methods/Stop.py
sfa/methods/Update.py
sfa/methods/UpdateSliver.py
sfa/methods/__init__.py
sfa/methods/get_key.py [deleted file]
sfa/methods/get_key_from_incoming_ip.py [new file with mode: 0644]
sfa/methods/get_trusted_certs.py
sfa/methods/reset_slice.py
sfa/plc/plcomponentdriver.py
sfa/plc/pldriver.py
sfa/plc/plshell.py
sfa/plc/remoteshell.py [deleted file]
sfa/rspecs/baseversion.py
sfa/rspecs/elements/versions/pgv2Link.py
sfa/rspecs/elements/versions/pgv2Node.py
sfa/rspecs/elements/versions/pgv2Services.py
sfa/rspecs/elements/versions/sfav1Node.py
sfa/rspecs/elements/versions/sfav1Sliver.py
sfa/rspecs/pg_rspec_converter.py
sfa/rspecs/rspec.py
sfa/rspecs/version_manager.py
sfa/rspecs/versions/pgv2.py
sfa/rspecs/versions/sfav1.py
sfa/server/sfa-ca.py
sfa/server/sfa-clean-peer-records.py
sfa/server/sfa-start.py
sfa/server/sfa_component_setup.py
sfa/server/sfaapi.py
sfa/server/xmlrpcapi.py
sfa/storage/PostgreSQL.py [moved from sfa/util/PostgreSQL.py with 100% similarity]
sfa/storage/__init__.py [new file with mode: 0644]
sfa/storage/filter.py [moved from sfa/util/filter.py with 98% similarity]
sfa/storage/parameter.py [moved from sfa/util/parameter.py with 100% similarity]
sfa/storage/record.py [moved from sfa/util/record.py with 99% similarity]
sfa/storage/row.py [moved from sfa/util/row.py with 100% similarity]
sfa/storage/sfa.sql [new file with mode: 0644]
sfa/storage/table.py [moved from sfa/util/table.py with 81% similarity]
sfa/util/config.py
sfa/util/faults.py
sfa/util/method.py
tests/testRecord.py
wsdl/sfa2wsdl.py

index b93abae..074d1fb 100644 (file)
@@ -1,146 +1,4 @@
-This installation note assumes that you have installed and configured MyPLC in the usual manner, and you have set up your yum repo like for a MyPLC install.
+Please refer to the trac page below for installing and using this software
 
-Once you have completed the server configuration, a brief introduction to the SFA user tools is here:
-    http://svn.planet-lab.org/wiki/SFAGuide
-
------
-1) Install the SFA packages:
-
-# yum install sfa-plc sfa-client
-
-Note that the above command installs both sfa server (sfa-plc) and sfa client packages along with necessary dependency packages. Depending on the requirements, you may choose to install the appropriate one (server, client or both) for you. For e.g. to set up your own SFA server on top of your MyPLC, you need sfa-plc. On the other hand, if you plan to use an existing SFA server, you would typically need the sfa-client only.
--------
-2) Note down the PLC_ROOT_USER, PLC_ROOT_PASSWORD, PLC_DB_USER and PLC_DB_PASSWORD of your MyPLC installation:
-
-# plc-config-tty 
-Enter command (u for usual changes, w to save, ? for help) s PLC_ROOT_USER
-PLC_ROOT_USER = root@test.onelab.eu
-Enter command (u for usual changes, w to save, ? for help) s PLC_ROOT_PASSWORD
-PLC_ROOT_PASSWORD = test++
-Enter command (u for usual changes, w to save, ? for help) s PLC_DB_USER
-PLC_DB_USER = pgsqluser
-Enter command (u for usual changes, w to save, ? for help) s PLC_DB_PASSWORD
-PLC_DB_PASSWORD = 4a333aba-a322-41b1-9c05-90b4f34d1332
-
-These four configuration parameters are required for SFA server configuration
--------
-3) Configure and start SFA servers: 
-
-(a) # sfa-config-tty
-
- set SFA_PLC_USER              to     PLC_ROOT_USER 
- set SFA_PLC_PASSWORD          to     PLC_ROOT_PASSWORD
- set SFA_DB_USER               to     PLC_DB_USER
- set SFA_DB_PASSWORD   to     PLC_DB_PASSWORD
-write and quit
-
-*NOTE* at this point you get a warning b/c the authorities hierarchy has not been created yet; ignore
-
-(b) # sfa-import-plc.py 
-
-(o/p will look like this)
-Import: creating top level authorities
-Hierarchy: creating authority: plc
-plc : 
-Import: creating table for authority plc
-NOTICE:  table "sfa$plc" does not exist, skipping
-  inserting authority record for plc
-Import: adding plc to trusted list
-Import_Site: importing site plc.internet2
-Hierarchy: creating authority: plc.internet2
-  inserting authority record for plc.internet2
-Import_Site: importing site plc.pl
-Hierarchy: creating authority: plc.pl
-  inserting authority record for plc.pl
-Import: importing person plc.pl.root
-Import: creating table for authority plc.pl
-NOTICE:  table "sfa$plc$pl" does not exist, skipping
-
-(c)  run sfa-config-tty again and select q to come out of the config command
-This will initialize /etc/sfa/authorities/server.key from /etc/sfa/authorities/plc/plc.pkey 
-
-(d) # service sfa start
-This will start Registry, Slice Manager and Aggregate Manager. Your ps command output would look like:
-
-# ps -ef | grep python
-root     24944     1  0 May11 ?        00:00:00 /usr/bin/python /usr/bin/sfa-start.py -r -d
-root     24957     1  0 May11 ?        00:00:00 /usr/bin/python /usr/bin/sfa-start.py -a -d
-root     24970     1  0 May11 ?        00:00:00 /usr/bin/python /usr/bin/sfa-start.py -s -d
--------
-4) Configure SFA client:
-
- (a) # mkdir ~/.sfi 
- (b)copy your private RSA key to ~/.sfi/username.pkey Replace username with your actual account name.  NOTE: DSA KEYS WILL NOT WORK
- (c) # cp  /etc/sfa/sfi_config ~/.sfi/
- (d) edit ~/.sfi/sfi_config. A sample configuration looks like:
-
-       SFI_AUTH='plc.pl'
-       SFI_USER='plc.pl.root'
-       SFI_REGISTRY='http://vplc25.inria.fr:12345/'
-       SFI_SM='http://vplc25.inria.fr:12347/' 
-
-------
-5) Testing:
-
-At this stage you should be able to run sfi command. Some sample outputs are:
-
- (a) # sfi.py list plc.pl
-     plc.pl.netflow (slice)
-     plc.pl.sirius (slice)
-     plc.pl.root (user)
-     plc.pl.pif (node)
-
- (b) # sfi.py show plc.pl.pif
-     gid:
-          hrn: plc.pl.pif
-         uuid: 99878316891261700702442883738232624912
-     hrn: plc.pl.pif
-     type: node
-     node_type: regular
-     hostname: pif.inria.fr
- (c) # sfi.py show plc.pl.root
-       gid:
-          hrn: plc.pl.root
-         uuid: 67306954103472941609600457537601239401
-     hrn: plc.pl.root
-     type: user
-     last_name: Administrator
-     phone: None
-     key: plc.pl.root#user
-     first_name: Default
-     email: root@vplc25.inria.fr
-
- (d) # sfi.py slices
-     plc.pl.netflow
-     plc.pl.sirius
-
- (e) # sfi.py resources
-<?xml version="1.0" ?>
-<RSpec duration="3600" start_time="1246736949"><networks><NetSpec duration="3600" name="plc" start_time="1246736950"><nodes><NodeSpec cpu_min="" cpu_pct="" cpu_share="" disk_max="" duration="" init_params="" name="pif.inria.fr" start_time="" type=""><net_if><IfSpec addr="138.96.250.224" init_params="" ip_spoof="" max_kbyte="" max_rate="" min_rate="" name="True" type="ipv4"/></net_if></NodeSpec></nodes></NetSpec></networks></RSpec>
-------
-
-6) Federation configuration:
-
-(a) Follow the same procedure to install and configure second MyPLC with SFA server.
-(b) On each PLC, edit the /etc/sfa/registries.xml file
-
-    set addr to ip or hostname of federated (remote) peer
-    set port to sfa service port on federated (remote) peer
-    set hrn to human readable name of federated (remote) peer interface
-Sample configuration:
-
-<registries>
-       <registry addr="vplc26.inria.fr" hrn="ple" port="12345"/>
-</registries>
-
-(c) Likewise, edit the /etc/sfa/aggregates.xml
-Sampel configuration
-
-<aggregates>
-       <aggregate addr="vplc26.inria.fr" hrn="ple" port="12346"/>
-</aggregates>
-
-(d) trade trusted root gid's (seen on /etc/sfa/trusted_roots)
-we have to copy the gid of first SFA server to the /etc/sfa/trusted_roots directory of second one and vice-versa. 
+http://svn.planet-lab.org/wiki/SFATutorial#SFATutorial
 
index 701c329..6d770b4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -90,7 +90,7 @@ force:
 
 ##########
 tags:  
-       find . -type f | egrep -v '/\.git/|/\.svn/|TAGS|~$$|\.(py[co]|doc|html|pdf|png|svg|out|bak|xml|dg)$$' | xargs etags
+       find . -type f | egrep -v '/\.git/|/\.svn/|TAGS|AA-|~$$|\.(py[co]|doc|html|pdf|png|svg|out|bak|xml|dg)$$' | xargs etags
 .PHONY: tags
 
 signatures:
@@ -141,7 +141,7 @@ else
        +$(RSYNC) ./sfa/ $(SSHURL)/usr/lib\*/python2.\*/site-packages/sfa/
        +$(RSYNC) ./tests/ $(SSHURL)/root/tests-sfa
        +$(RSYNC)  $(BINS) $(SSHURL)/usr/bin/
-       +$(RSYNC) ./sfa/init.d/sfa  $(SSHURL)/etc/init.d/
+       +$(RSYNC) ./init.d/sfa  $(SSHURL)/etc/init.d/
        +$(RSYNC) ./config/default_config.xml $(SSHURL)/etc/sfa/
        $(SSHCOMMAND) exec service sfa restart
 endif
diff --git a/README.txt b/README.txt
deleted file mode 100644 (file)
index 42255d4..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-This module (sfa) is installed as part of MyPLC, available as
-part of the PlanetLab development effort. For more information on
-accessing, installing, developing and deploying PlanetLab software,
-visit http://svn.planet-lab.org.
-
-For a brief introduction to the SFA user tools, please visit:
-    http://svn.planet-lab.org/wiki/SFAGuide
index 10471bc..99c5d37 100644 (file)
@@ -33,7 +33,7 @@ Thierry Parmentelat
           <description>The human readable name for this interface.</description>
         </variable>
 
-        <variable id="aggregate_api_version" type="string">
+        <variable id="aggregate_api_version" type="int">
           <name>Aggregate Manager API Version</name>
           <value>1</value>
           <description>The Aggregate API version</description>
@@ -85,13 +85,6 @@ Thierry Parmentelat
          registry.</description>
        </variable>
 
-       <variable id="type" type="string">
-         <name>Registry type</name>
-         <value>pl</value>
-         <description>The type of backend server for this
-         registry. Some registries may not be myplc.</description>
-       </variable>
-
        <variable id="host" type="hostname">
          <name>Hostname</name>
          <value>localhost</value>
@@ -129,13 +122,6 @@ Thierry Parmentelat
          slice manager.</description>
        </variable>
 
-       <variable id="type" type="string">
-         <name>Slice Manager type</name>
-         <value>pl</value>
-         <description>The type of backend server for this
-         slice manager. Not all slice managers are myplc.</description>
-       </variable>
-
        <variable id="host" type="hostname">
          <name>Hostname</name>
          <value>localhost</value>
@@ -165,13 +151,6 @@ Thierry Parmentelat
          aggregate manager.</description>
        </variable>
 
-       <variable id="type" type="string">
-         <name>Aggregate type</name>
-         <value>pl</value>
-         <description>The type of backend server for this
-         aggregate. Some aggregates may not be myplc.</description>
-       </variable>
-    
     <variable id="rspec_schema" type="string">
       <name>RSpec Schema</name>
       <value>/etc/sfa/pl.rng</value>
index d51c93b..1bb57c8 100644 (file)
@@ -16,11 +16,6 @@ SFA_API_DEBUG=1
 # Enable the registry interface 
 SFA_REGISTRY_ENABLED=0
 
-#
-# The type of backend server for this registry
-# Some registries may not be myplc 
-SFA_REGISTRY_TYPE='pl'
-
 # Root Auth
 # The hrn of the registry's root auth
 SFA_REGISTRY_ROOT_AUTH="plc"
@@ -32,6 +27,8 @@ SFA_REGISTRY_ROOT_AUTH="plc"
 # xxx could be determined from hrn above
 SFA_REGISTRY_LEVEL1_AUTH=""
 
+SFA_GENERIC_FLAVOUR='pl'
+
 # Hostname
 # The fully qualified hostname of the registry server
 SFA_REGISTRY_HOST="localhost"
@@ -47,12 +44,6 @@ SFA_REGISTRY_PORT=12345
 ## Enable the aggregate inteface.
 SFA_AGGREGATE_ENABLED=0
 
-# Aggregate Type
-#
-# The type of backend server for this aggregate
-# Some aggregates may not be myplc 
-SFA_AGGREGATE_TYPE='pl'
-
 #
 #
 ## Hostname
@@ -70,14 +61,6 @@ SFA_AGGREGATE_PORT=12346
 # Enable the slice manager  
 SFA_SM_ENABLED=0
 
-# Slice Manager type
-#
-## The type of backend server for this slice manager
-## The slice manager doesnt rely on a specific backend server so 
-## you probably will never need to change this type unless you 
-## need to reimplement the slice manager
-SFA_SM_TYPE='pl' 
-
 # Host
 ## The fully qualified hostname or IP address of the slice manager server
 SFA_SM_HOST="localhost"
diff --git a/cron.d/readme b/cron.d/readme
new file mode 100644 (file)
index 0000000..53d10a1
--- /dev/null
@@ -0,0 +1 @@
+As of nov 2011 this is not packaged, use as a template for your installation
similarity index 100%
rename from sfa/cron.d/sfa.cron
rename to cron.d/sfa.cron
similarity index 89%
rename from sfa/init.d/sfa
rename to init.d/sfa
index 7247339..3e733ee 100755 (executable)
@@ -85,10 +85,10 @@ function reload () {
 
     # Convert configuration to various formats
     if [ -n "$force" -o $sfa_whole_config -nt /etc/sfa/sfa_config ] ; then
-       plc-config --shell $sfa_whole_config >/etc/sfa/sfa_config
+       plc-config --shell $sfa_whole_config > /etc/sfa/sfa_config
     fi
     if [ -n "$force" -o $sfa_whole_config -nt /etc/sfa/sfa_config.py ] ; then
-       plc-config --python $sfa_whole_config >/etc/sfa/sfa_config.py
+       plc-config --python $sfa_whole_config > /etc/sfa/sfa_config.py
     fi
 #    if [ -n "$force" -o $sfa_whole_config -nt /etc/sfa/php/sfa_config.php ] ; then
 #      mkdir -p /etc/sfa/php
@@ -101,6 +101,10 @@ function reload () {
     # (or there is no myplc at all) this should be turned off
     # as the component manager is not operational yet we skip this for now
     #gen-sfa-cm-config.py        
+
+    # reload the shell version
+    [ -f /etc/sfa/sfa_config ] && . /etc/sfa/sfa_config
+
 }
 
 ### initialize DB (don't chkconfig postgresql on)
@@ -170,7 +174,7 @@ function db_start () {
        ######## compute a password if needed
        if [ -z "$SFA_DB_PASSWORD" ] ; then
            SFA_DB_PASSWORD=$(uuidgen)
-           plc-config --category=sfa_db --variable=password --value="$SFA_DB_PASSWORD" --save=$sfa_local_config $sfa_local_config
+           plc-config --category=sfa_db --variable=password --value="$SFA_DB_PASSWORD" --save=$sfa_local_config $sfa_local_config >& /dev/null
            reload force
        fi
 
@@ -182,8 +186,8 @@ function db_start () {
        PLC_DB_USER=$(plc-config --category=plc_db --variable=user)
        PLC_DB_PASSWORD=$(plc-config --category=plc_db --variable=password)
        # store this as the SFA user/password 
-       plc-config --category=sfa_db --variable=user --value=$PLC_DB_USER --save=$sfa_local_config $sfa_local_config
-       plc-config --category=sfa_db --variable=password --value=$PLC_DB_PASSWORD --save=$sfa_local_config $sfa_local_config
+       plc-config --category=sfa_db --variable=user --value=$PLC_DB_USER --save=$sfa_local_config $sfa_local_config >& /dev/null
+       plc-config --category=sfa_db --variable=password --value=$PLC_DB_PASSWORD --save=$sfa_local_config $sfa_local_config >& /dev/null
        reload force
     fi
 
@@ -199,17 +203,19 @@ function db_start () {
     ######## make sure we have the user and db created
     # user
     if ! psql -U $SFA_DB_USER -c "" template1 >/dev/null 2>&1 ; then
-       psql -U postgres -c "CREATE USER $SFA_DB_USER PASSWORD '$SFA_DB_PASSWORD'" template1
+       psql -U postgres -c "CREATE USER $SFA_DB_USER PASSWORD '$SFA_DB_PASSWORD'" template1 >& /dev/null
     else
-       psql -U postgres -c "ALTER USER $SFA_DB_USER WITH PASSWORD '$SFA_DB_PASSWORD'" template1
+       psql -U postgres -c "ALTER USER $SFA_DB_USER WITH PASSWORD '$SFA_DB_PASSWORD'" template1 >& /dev/null
     fi
     check
     
     # db
     if ! psql -U $SFA_DB_USER -c "" $SFA_DB_NAME >/dev/null 2>&1 ; then
        createdb -U postgres --template=template0 --encoding=UNICODE --owner=$SFA_DB_USER $SFA_DB_NAME
-        # xxx in case we'd like to ship the db schema separately
-        #psql -U $SFA_DB_USER -f /etc/sfa/or/someplace/else/sfa.sql $SFA_DB_NAME
+       check
+        # install db schema
+        psql -U $SFA_DB_USER -f /usr/share/sfa/sfa.sql $SFA_DB_NAME
+       check
     fi
     check
 
@@ -243,21 +249,14 @@ function start() {
     # install peer certs
     action $"SFA installing peer certs" daemon /usr/bin/sfa-start.py -t -d $OPTIONS 
 
-    if [ "$SFA_REGISTRY_ENABLED" -eq 1 ]; then
-        action $"SFA Registry" daemon /usr/bin/sfa-start.py -r -d $OPTIONS
-    fi
-
-    if [ "$SFA_AGGREGATE_ENABLED" -eq 1 ]; then
-        action $"SFA Aggregate" daemon /usr/bin/sfa-start.py -a -d $OPTIONS
-    fi
+    [ "$SFA_REGISTRY_ENABLED" == 1 ] && action $"SFA Registry" daemon /usr/bin/sfa-start.py -r -d $OPTIONS
+    
+    [ "$SFA_AGGREGATE_ENABLED" == 1 ] && action $"SFA Aggregate" daemon /usr/bin/sfa-start.py -a -d $OPTIONS
         
-    if [ "$SFA_SM_ENABLED" -eq 1 ]; then
-        action "SFA SliceMgr" daemon /usr/bin/sfa-start.py -s -d $OPTIONS
-    fi
+    [ "$SFA_SM_ENABLED" == 1 ] && action "SFA SliceMgr" daemon /usr/bin/sfa-start.py -s -d $OPTIONS
 
-    if [ "$SFA_FLASHPOLICY_ENABLED" -eq 1 ]; then
+    [ "$SFA_FLASHPOLICY_ENABLED" == 1 ] && \
         action "Flash Policy Server" daemon /usr/bin/sfa_flashpolicy.py --file="$SFA_FLASHPOLICY_CONFIG_FILE" --port=$SFA_FLASHPOLICY_PORT -d
-    fi
 
     touch /var/lock/subsys/sfa-start.py
 
similarity index 100%
rename from sfa/init.d/sfa-cm
rename to init.d/sfa-cm
diff --git a/rspec/model/Registry.ecore b/rspec/model/Registry.ecore
deleted file mode 100644 (file)
index ae7ecac..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ecore:EPackage xmi:version="2.0"
-    xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="Registry"
-    nsURI="http://www.planet-lab.org/Registry" nsPrefix="Registry">
-  <eClassifiers xsi:type="ecore:EClass" name="UserRecord" eSuperTypes="#//RegistryRecord">
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="email" ordered="false"
-        lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
-        iD="true"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="first_name" ordered="false"
-        lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
-        iD="true"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="last_name" ordered="false"
-        lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
-        iD="true"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="phone" ordered="false"
-        lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
-        iD="true"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="key" ordered="false" lowerBound="1"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString" iD="true"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="slice" upperBound="-1"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString" defaultValueLiteral=""/>
-  </eClassifiers>
-  <eClassifiers xsi:type="ecore:EClass" name="SliceRecord" eSuperTypes="#//RegistryRecord">
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" ordered="false" lowerBound="1"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString" iD="true"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="url" ordered="false" lowerBound="1"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString" iD="true"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="expires" ordered="false"
-        lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDate"
-        iD="true"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="researcher" lowerBound="1"
-        upperBound="-1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="description" ordered="false"
-        lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
-        iD="true"/>
-  </eClassifiers>
-  <eClassifiers xsi:type="ecore:EClass" name="NodeRecord" eSuperTypes="#//RegistryRecord">
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="hostname" lowerBound="1"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString" defaultValueLiteral=""/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="node_type" lowerBound="1"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString" defaultValueLiteral="&quot;user&quot;"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="latitude" ordered="false"
-        lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"
-        iD="true"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="longitude" ordered="false"
-        lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"
-        iD="true"/>
-  </eClassifiers>
-  <eClassifiers xsi:type="ecore:EClass" name="Authority" eSuperTypes="#//RegistryRecord">
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" ordered="false" lowerBound="1"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString" iD="true"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="last_updated" ordered="false"
-        lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDate"
-        iD="true"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="url" ordered="false" lowerBound="1"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString" iD="true"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="researcher" upperBound="-1"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="operator" lowerBound="1"
-        upperBound="-1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="PI" lowerBound="1" upperBound="-1"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
-  </eClassifiers>
-  <eClassifiers xsi:type="ecore:EClass" name="RegistryRecord">
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="hrn" ordered="false" lowerBound="1"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString" iD="true"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="gid" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="type" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
-        defaultValueLiteral=""/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="created" ordered="false"
-        lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDate"
-        iD="true"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="last_updated" ordered="false"
-        lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDate"
-        iD="true"/>
-  </eClassifiers>
-</ecore:EPackage>
diff --git a/rspec/model/planetlab.ecore b/rspec/model/planetlab.ecore
deleted file mode 100644 (file)
index 68dd1a7..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ecore:EPackage xmi:version="2.0"
-    xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="planetlab"
-    nsURI="http://www.planet-lab.org" nsPrefix="pl">
-  <eClassifiers xsi:type="ecore:EClass" name="RSpec">
-    <eStructuralFeatures xsi:type="ecore:EReference" name="networks" lowerBound="1"
-        upperBound="-1" eType="#//NetSpec"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="start_time" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDate"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="duration" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDate"/>
-  </eClassifiers>
-  <eClassifiers xsi:type="ecore:EClass" name="NetSpec">
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
-    <eStructuralFeatures xsi:type="ecore:EReference" name="nodes" lowerBound="1" upperBound="-1"
-        eType="#//NodeSpec"/>
-    <eStructuralFeatures xsi:type="ecore:EReference" name="links" upperBound="-1"
-        eType="#//LinkSpec" containment="true"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="start_time" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDate"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="duration" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDate"/>
-  </eClassifiers>
-  <eClassifiers xsi:type="ecore:EClass" name="NodeSpec">
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" lowerBound="1" upperBound="1000"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="type" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
-        defaultValueLiteral="&quot;&quot;"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="init_params" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EByteArray"
-        defaultValueLiteral=""/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="cpu_min" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"
-        defaultValueLiteral="0"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="cpu_share" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"
-        defaultValueLiteral="0"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="cpu_pct" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"
-        defaultValueLiteral="0"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="disk_max" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"
-        defaultValueLiteral="0"/>
-    <eStructuralFeatures xsi:type="ecore:EReference" name="net_if" lowerBound="1"
-        upperBound="-1" eType="#//IfSpec"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="start_time" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDate"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="duration" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDate"/>
-  </eClassifiers>
-  <eClassifiers xsi:type="ecore:EClass" name="LinkSpec">
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="type" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
-        changeable="false" defaultValueLiteral="&quot;&quot;"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="init_params" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EByteArray"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="bw" upperBound="-1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"
-        defaultValueLiteral="0"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="min_alloc" upperBound="-2"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt" defaultValueLiteral="0"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="max_alloc" upperBound="-1"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt" defaultValueLiteral="0"/>
-    <eStructuralFeatures xsi:type="ecore:EReference" name="endpoint" lowerBound="1"
-        upperBound="-1" eType="#//IfSpec" changeable="false"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="start_time" upperBound="-2"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDate"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="duration" upperBound="-2"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDate"/>
-  </eClassifiers>
-  <eClassifiers xsi:type="ecore:EClass" name="IfSpec">
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="addr" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="type" upperBound="-2" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
-        changeable="false" defaultValueLiteral=""/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="init_params" upperBound="-2"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EByteArray"
-        defaultValueLiteral=""/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="min_rate" upperBound="-2"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt" defaultValueLiteral="0"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="max_rate" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"
-        defaultValueLiteral="12207"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="max_kbyte" upperBound="-1"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt" defaultValueLiteral="5452595"
-        unsettable="true"/>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="ip_spoof" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"
-        defaultValueLiteral="false"/>
-  </eClassifiers>
-  <eClassifiers xsi:type="ecore:EClass" name="SwitchSpec" eSuperTypes="#//NodeSpec">
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="fib_max" upperBound="-2"
-        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt" defaultValueLiteral="0"/>
-  </eClassifiers>
-</ecore:EPackage>
diff --git a/rspec/model/planetlab.ecore_diagram b/rspec/model/planetlab.ecore_diagram
deleted file mode 100644 (file)
index df5642b..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<notation:Diagram xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:notation="http://www.eclipse.org/gmf/runtime/1.0.1/notation" xmi:id="_kVhkUCK_Ed2y9bl2PJcv2g" type="Ecore" measurementUnit="Pixel">
-  <children xmi:type="notation:Node" xmi:id="_kWAFcCK_Ed2y9bl2PJcv2g" type="2001">
-    <children xmi:type="notation:Node" xmi:id="_kWAFcyK_Ed2y9bl2PJcv2g" type="5001"/>
-    <children xmi:type="notation:Node" xmi:id="_kWAFdCK_Ed2y9bl2PJcv2g" type="7001">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWAFdSK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWAFdiK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWAFdyK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <children xmi:type="notation:Node" xmi:id="_kWAsgCK_Ed2y9bl2PJcv2g" type="7002">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWAsgSK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWAsgiK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWAsgyK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <children xmi:type="notation:Node" xmi:id="_kWAshCK_Ed2y9bl2PJcv2g" type="7003">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWAshSK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWAshiK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWAshyK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <styles xmi:type="notation:ShapeStyle" xmi:id="_kWAFcSK_Ed2y9bl2PJcv2g" fontName="Sans"/>
-    <element xmi:type="ecore:EClass" href="planetlab.ecore#//Network"/>
-    <layoutConstraint xmi:type="notation:Bounds" xmi:id="_kWAFciK_Ed2y9bl2PJcv2g" x="114" y="55"/>
-  </children>
-  <children xmi:type="notation:Node" xmi:id="_kWAsiCK_Ed2y9bl2PJcv2g" type="2001">
-    <children xmi:type="notation:Node" xmi:id="_kWAsiyK_Ed2y9bl2PJcv2g" type="5001"/>
-    <children xmi:type="notation:Node" xmi:id="_kWAsjCK_Ed2y9bl2PJcv2g" type="7001">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWAsjSK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWAsjiK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWAsjyK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <children xmi:type="notation:Node" xmi:id="_kWAskCK_Ed2y9bl2PJcv2g" type="7002">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWAskSK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWAskiK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWAskyK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <children xmi:type="notation:Node" xmi:id="_kWBTkCK_Ed2y9bl2PJcv2g" type="7003">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWBTkSK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWBTkiK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWBTkyK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <styles xmi:type="notation:ShapeStyle" xmi:id="_kWAsiSK_Ed2y9bl2PJcv2g" fontName="Sans"/>
-    <element xmi:type="ecore:EClass" href="planetlab.ecore#//PLNode"/>
-    <layoutConstraint xmi:type="notation:Bounds" xmi:id="_kWAsiiK_Ed2y9bl2PJcv2g" x="242" y="167"/>
-  </children>
-  <children xmi:type="notation:Node" xmi:id="_kWBTlCK_Ed2y9bl2PJcv2g" type="2001">
-    <children xmi:type="notation:Node" xmi:id="_kWBTlyK_Ed2y9bl2PJcv2g" type="5001"/>
-    <children xmi:type="notation:Node" xmi:id="_kWBTmCK_Ed2y9bl2PJcv2g" type="7001">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWBTmSK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWBTmiK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWBTmyK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <children xmi:type="notation:Node" xmi:id="_kWBTnCK_Ed2y9bl2PJcv2g" type="7002">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWBTnSK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWBTniK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWBTnyK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <children xmi:type="notation:Node" xmi:id="_kWBToCK_Ed2y9bl2PJcv2g" type="7003">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWBToSK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWBToiK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWBToyK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <styles xmi:type="notation:ShapeStyle" xmi:id="_kWBTlSK_Ed2y9bl2PJcv2g" fontName="Sans"/>
-    <element xmi:type="ecore:EClass" href="planetlab.ecore#//Link"/>
-    <layoutConstraint xmi:type="notation:Bounds" xmi:id="_kWBTliK_Ed2y9bl2PJcv2g" x="55" y="167"/>
-  </children>
-  <children xmi:type="notation:Node" xmi:id="_kWB6oCK_Ed2y9bl2PJcv2g" type="2001">
-    <children xmi:type="notation:Node" xmi:id="_kWB6oyK_Ed2y9bl2PJcv2g" type="5001"/>
-    <children xmi:type="notation:Node" xmi:id="_kWB6pCK_Ed2y9bl2PJcv2g" type="7001">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWB6pSK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWB6piK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWB6pyK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <children xmi:type="notation:Node" xmi:id="_kWB6qCK_Ed2y9bl2PJcv2g" type="7002">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWB6qSK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWB6qiK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWB6qyK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <children xmi:type="notation:Node" xmi:id="_kWB6rCK_Ed2y9bl2PJcv2g" type="7003">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWB6rSK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWB6riK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWB6ryK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <styles xmi:type="notation:ShapeStyle" xmi:id="_kWB6oSK_Ed2y9bl2PJcv2g" fontName="Sans"/>
-    <element xmi:type="ecore:EClass" href="planetlab.ecore#//Endpoint"/>
-    <layoutConstraint xmi:type="notation:Bounds" xmi:id="_kWB6oiK_Ed2y9bl2PJcv2g" x="60" y="350"/>
-  </children>
-  <children xmi:type="notation:Node" xmi:id="_kWChsCK_Ed2y9bl2PJcv2g" type="2001">
-    <children xmi:type="notation:Node" xmi:id="_kWChsyK_Ed2y9bl2PJcv2g" type="5001"/>
-    <children xmi:type="notation:Node" xmi:id="_kWChtCK_Ed2y9bl2PJcv2g" type="7001">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWChtSK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWChtiK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWChtyK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <children xmi:type="notation:Node" xmi:id="_kWChuCK_Ed2y9bl2PJcv2g" type="7002">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWChuSK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWChuiK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWChuyK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <children xmi:type="notation:Node" xmi:id="_kWChvCK_Ed2y9bl2PJcv2g" type="7003">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWChvSK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWChviK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWChvyK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <styles xmi:type="notation:ShapeStyle" xmi:id="_kWChsSK_Ed2y9bl2PJcv2g" fontName="Sans"/>
-    <element xmi:type="ecore:EClass" href="planetlab.ecore#//VININode"/>
-    <layoutConstraint xmi:type="notation:Bounds" xmi:id="_kWChsiK_Ed2y9bl2PJcv2g" x="410" y="55"/>
-  </children>
-  <children xmi:type="notation:Node" xmi:id="_kWChwCK_Ed2y9bl2PJcv2g" type="2001">
-    <children xmi:type="notation:Node" xmi:id="_kWDIwCK_Ed2y9bl2PJcv2g" type="5001"/>
-    <children xmi:type="notation:Node" xmi:id="_kWDIwSK_Ed2y9bl2PJcv2g" type="7001">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWDIwiK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWDIwyK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWDIxCK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <children xmi:type="notation:Node" xmi:id="_kWDIxSK_Ed2y9bl2PJcv2g" type="7002">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWDIxiK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWDIxyK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWDIyCK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <children xmi:type="notation:Node" xmi:id="_kWDIySK_Ed2y9bl2PJcv2g" type="7003">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWDIyiK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWDIyyK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWDIzCK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <styles xmi:type="notation:ShapeStyle" xmi:id="_kWChwSK_Ed2y9bl2PJcv2g" fontName="Sans"/>
-    <element xmi:type="ecore:EClass" href="planetlab.ecore#//WirelessNode"/>
-    <layoutConstraint xmi:type="notation:Bounds" xmi:id="_kWChwiK_Ed2y9bl2PJcv2g" x="245" y="55"/>
-  </children>
-  <children xmi:type="notation:Node" xmi:id="_kWDIzSK_Ed2y9bl2PJcv2g" type="2005">
-    <children xmi:type="notation:Node" xmi:id="_kWDv0CK_Ed2y9bl2PJcv2g" type="5005"/>
-    <children xmi:type="notation:Node" xmi:id="_kWDv0SK_Ed2y9bl2PJcv2g" type="7011">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWDv0iK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWDv0yK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWDv1CK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <children xmi:type="notation:Node" xmi:id="_kWDv1SK_Ed2y9bl2PJcv2g" type="7012">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWDv1iK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWDv1yK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWDv2CK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <styles xmi:type="notation:ShapeStyle" xmi:id="_kWDIziK_Ed2y9bl2PJcv2g" fontName="Sans"/>
-    <element xmi:type="ecore:EEnum" href="planetlab.ecore#//Address"/>
-    <layoutConstraint xmi:type="notation:Bounds" xmi:id="_kWDIzyK_Ed2y9bl2PJcv2g" x="546" y="55"/>
-  </children>
-  <children xmi:type="notation:Node" xmi:id="_kWDv2SK_Ed2y9bl2PJcv2g" type="2001">
-    <children xmi:type="notation:Node" xmi:id="_kWDv3CK_Ed2y9bl2PJcv2g" type="5001"/>
-    <children xmi:type="notation:Node" xmi:id="_kWDv3SK_Ed2y9bl2PJcv2g" type="7001">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWDv3iK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWEW4CK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWEW4SK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <children xmi:type="notation:Node" xmi:id="_kWEW4iK_Ed2y9bl2PJcv2g" type="7002">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWEW4yK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWEW5CK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWEW5SK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <children xmi:type="notation:Node" xmi:id="_kWEW5iK_Ed2y9bl2PJcv2g" type="7003">
-      <styles xmi:type="notation:DrawerStyle" xmi:id="_kWEW5yK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:SortingStyle" xmi:id="_kWEW6CK_Ed2y9bl2PJcv2g"/>
-      <styles xmi:type="notation:FilteringStyle" xmi:id="_kWEW6SK_Ed2y9bl2PJcv2g"/>
-    </children>
-    <styles xmi:type="notation:ShapeStyle" xmi:id="_kWDv2iK_Ed2y9bl2PJcv2g" fontName="Sans"/>
-    <element xmi:type="ecore:EClass" href="planetlab.ecore#//Interface"/>
-    <layoutConstraint xmi:type="notation:Bounds" xmi:id="_kWDv2yK_Ed2y9bl2PJcv2g" x="412" y="167"/>
-  </children>
-  <styles xmi:type="notation:DiagramStyle" xmi:id="_kVhkUSK_Ed2y9bl2PJcv2g"/>
-  <element xmi:type="ecore:EPackage" href="planetlab.ecore#/"/>
-  <edges xmi:type="notation:Edge" xmi:id="_kWVcoCK_Ed2y9bl2PJcv2g" type="4002" source="_kWAFcCK_Ed2y9bl2PJcv2g" target="_kWAsiCK_Ed2y9bl2PJcv2g">
-    <children xmi:type="notation:Node" xmi:id="_kWWDsSK_Ed2y9bl2PJcv2g" type="6001">
-      <layoutConstraint xmi:type="notation:Location" xmi:id="_kWWDsiK_Ed2y9bl2PJcv2g" x="2" y="-19"/>
-    </children>
-    <children xmi:type="notation:Node" xmi:id="_kWWDsyK_Ed2y9bl2PJcv2g" type="6003">
-      <layoutConstraint xmi:type="notation:Location" xmi:id="_kWWDtCK_Ed2y9bl2PJcv2g" x="-18" y="5"/>
-    </children>
-    <styles xmi:type="notation:ConnectorStyle" xmi:id="_kWVcoSK_Ed2y9bl2PJcv2g"/>
-    <styles xmi:type="notation:FontStyle" xmi:id="_kWVcoiK_Ed2y9bl2PJcv2g" fontName="Sans"/>
-    <element xmi:type="ecore:EReference" href="planetlab.ecore#//Network/nodes"/>
-    <bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_kWWDsCK_Ed2y9bl2PJcv2g" points="[0, 26, -148, -121]$[148, 86, 0, -61]"/>
-  </edges>
-  <edges xmi:type="notation:Edge" xmi:id="_kWXR0CK_Ed2y9bl2PJcv2g" type="4003" source="_kWAFcCK_Ed2y9bl2PJcv2g" target="_kWBTlCK_Ed2y9bl2PJcv2g">
-    <children xmi:type="notation:Node" xmi:id="_kWX44CK_Ed2y9bl2PJcv2g" type="6002">
-      <layoutConstraint xmi:type="notation:Location" xmi:id="_kWX44SK_Ed2y9bl2PJcv2g" x="4" y="16"/>
-    </children>
-    <children xmi:type="notation:Node" xmi:id="_kWX44iK_Ed2y9bl2PJcv2g" type="6004">
-      <layoutConstraint xmi:type="notation:Location" xmi:id="_kWX44yK_Ed2y9bl2PJcv2g" x="2" y="28"/>
-    </children>
-    <styles xmi:type="notation:ConnectorStyle" xmi:id="_kWXR0SK_Ed2y9bl2PJcv2g"/>
-    <styles xmi:type="notation:FontStyle" xmi:id="_kWXR0iK_Ed2y9bl2PJcv2g" fontName="Sans"/>
-    <element xmi:type="ecore:EReference" href="planetlab.ecore#//Network/links"/>
-    <bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_kWXR0yK_Ed2y9bl2PJcv2g" points="[0, 26, 31, -121]$[-31, 86, 0, -61]"/>
-  </edges>
-  <edges xmi:type="notation:Edge" xmi:id="_kWZHACK_Ed2y9bl2PJcv2g" type="4002" source="_kWBTlCK_Ed2y9bl2PJcv2g" target="_kWB6oCK_Ed2y9bl2PJcv2g">
-    <children xmi:type="notation:Node" xmi:id="_kWZHBCK_Ed2y9bl2PJcv2g" type="6001">
-      <layoutConstraint xmi:type="notation:Location" xmi:id="_kWZHBSK_Ed2y9bl2PJcv2g" y="40"/>
-    </children>
-    <children xmi:type="notation:Node" xmi:id="_kWZHBiK_Ed2y9bl2PJcv2g" type="6003">
-      <layoutConstraint xmi:type="notation:Location" xmi:id="_kWZHByK_Ed2y9bl2PJcv2g" x="-17" y="28"/>
-    </children>
-    <styles xmi:type="notation:ConnectorStyle" xmi:id="_kWZHASK_Ed2y9bl2PJcv2g"/>
-    <styles xmi:type="notation:FontStyle" xmi:id="_kWZHAiK_Ed2y9bl2PJcv2g" fontName="Sans"/>
-    <element xmi:type="ecore:EReference" href="planetlab.ecore#//Link/endpoints"/>
-    <bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_kWZHAyK_Ed2y9bl2PJcv2g" points="[0, 62, 0, -97]$[0, 122, 0, -37]"/>
-  </edges>
-  <edges xmi:type="notation:Edge" xmi:id="_kWf0sCK_Ed2y9bl2PJcv2g" type="4003" source="_kWChsCK_Ed2y9bl2PJcv2g" target="_kWDv2SK_Ed2y9bl2PJcv2g">
-    <children xmi:type="notation:Node" xmi:id="_kWhC0CK_Ed2y9bl2PJcv2g" type="6002">
-      <layoutConstraint xmi:type="notation:Location" xmi:id="_kWhC0SK_Ed2y9bl2PJcv2g" x="-4" y="-41"/>
-    </children>
-    <children xmi:type="notation:Node" xmi:id="_kW2aACK_Ed2y9bl2PJcv2g" type="6004">
-      <layoutConstraint xmi:type="notation:Location" xmi:id="_kW2aASK_Ed2y9bl2PJcv2g" x="-3" y="-27"/>
-    </children>
-    <styles xmi:type="notation:ConnectorStyle" xmi:id="_kWf0sSK_Ed2y9bl2PJcv2g"/>
-    <styles xmi:type="notation:FontStyle" xmi:id="_kWf0siK_Ed2y9bl2PJcv2g" fontName="Sans"/>
-    <element xmi:type="ecore:EReference" href="planetlab.ecore#//VININode/interfaces"/>
-    <bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_kWf0syK_Ed2y9bl2PJcv2g" points="[0, 26, -35, -121]$[35, 86, 0, -61]"/>
-  </edges>
-  <edges xmi:type="notation:Edge" xmi:id="_kW8goCK_Ed2y9bl2PJcv2g" type="4004" source="_kWChsCK_Ed2y9bl2PJcv2g" target="_kWAsiCK_Ed2y9bl2PJcv2g">
-    <styles xmi:type="notation:ConnectorStyle" xmi:id="_kW8goSK_Ed2y9bl2PJcv2g"/>
-    <styles xmi:type="notation:FontStyle" xmi:id="_kW8goiK_Ed2y9bl2PJcv2g" fontName="Sans"/>
-    <element xsi:nil="true"/>
-    <bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_kW8goyK_Ed2y9bl2PJcv2g" points="[0, 26, 151, -121]$[-151, 86, 0, -61]"/>
-  </edges>
-  <edges xmi:type="notation:Edge" xmi:id="_kW9uwCK_Ed2y9bl2PJcv2g" type="4004" source="_kWChwCK_Ed2y9bl2PJcv2g" target="_kWAsiCK_Ed2y9bl2PJcv2g">
-    <styles xmi:type="notation:ConnectorStyle" xmi:id="_kW9uwSK_Ed2y9bl2PJcv2g"/>
-    <styles xmi:type="notation:FontStyle" xmi:id="_kW9uwiK_Ed2y9bl2PJcv2g" fontName="Sans"/>
-    <element xsi:nil="true"/>
-    <bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_kW9uwyK_Ed2y9bl2PJcv2g" points="[0, 26, 0, -121]$[0, 86, 0, -61]"/>
-  </edges>
-</notation:Diagram>
diff --git a/rspec/model/planetlab.genmodel b/rspec/model/planetlab.genmodel
deleted file mode 100644 (file)
index ce59a87..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<genmodel:GenModel xmi:version="2.0"
-    xmlns:xmi="http://www.omg.org/XMI" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"
-    xmlns:genmodel="http://www.eclipse.org/emf/2002/GenModel" modelDirectory="/PlanetLab/src"
-    editDirectory="/PlanetLab.edit/src" editorDirectory="/PlanetLab.editor/src" modelPluginID="PlanetLab"
-    modelName="Planetlab" editPluginClass="planetlab.planetlab.provider.PlanetlabEditPlugin"
-    editorPluginClass="planetlab.planetlab.presentation.PlanetlabEditorPlugin" codeFormatting="true"
-    copyrightFields="false">
-  <foreignModel>planetlab.ecore</foreignModel>
-  <genPackages prefix="Planetlab" basePackage="planetlab" disposableProviderFactory="true"
-      ecorePackage="planetlab.ecore#/">
-    <genEnums typeSafeEnumCompatible="false" ecoreEnum="planetlab.ecore#//Address"/>
-    <genClasses ecoreClass="planetlab.ecore#//Network">
-      <genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference planetlab.ecore#//Network/nodes"/>
-      <genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference planetlab.ecore#//Network/links"/>
-    </genClasses>
-    <genClasses ecoreClass="planetlab.ecore#//PLNode">
-      <genFeatures createChild="false" ecoreFeature="ecore:EAttribute planetlab.ecore#//PLNode/cpu_min"/>
-      <genFeatures createChild="false" ecoreFeature="ecore:EAttribute planetlab.ecore#//PLNode/cpu_share"/>
-      <genFeatures createChild="false" ecoreFeature="ecore:EAttribute planetlab.ecore#//PLNode/net_min_rate"/>
-    </genClasses>
-    <genClasses ecoreClass="planetlab.ecore#//Link">
-      <genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference planetlab.ecore#//Link/endpoints"/>
-      <genFeatures createChild="false" ecoreFeature="ecore:EAttribute planetlab.ecore#//Link/min_bandwidth"/>
-      <genFeatures createChild="false" ecoreFeature="ecore:EAttribute planetlab.ecore#//Link/max_bandwidth"/>
-      <genFeatures createChild="false" ecoreFeature="ecore:EAttribute planetlab.ecore#//Link/link_kind"/>
-    </genClasses>
-    <genClasses ecoreClass="planetlab.ecore#//Endpoint">
-      <genFeatures createChild="false" ecoreFeature="ecore:EAttribute planetlab.ecore#//Endpoint/addresses"/>
-      <genFeatures createChild="false" ecoreFeature="ecore:EAttribute planetlab.ecore#//Endpoint/endpoint_kind"/>
-    </genClasses>
-    <genClasses ecoreClass="planetlab.ecore#//VININode">
-      <genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference planetlab.ecore#//VININode/interfaces"/>
-    </genClasses>
-    <genClasses ecoreClass="planetlab.ecore#//WirelessNode"/>
-    <genClasses ecoreClass="planetlab.ecore#//Interface">
-      <genFeatures createChild="false" ecoreFeature="ecore:EAttribute planetlab.ecore#//Interface/min_bandwidth"/>
-      <genFeatures createChild="false" ecoreFeature="ecore:EAttribute planetlab.ecore#//Interface/max_bandwidth"/>
-      <genFeatures createChild="false" ecoreFeature="ecore:EAttribute planetlab.ecore#//Interface/interface_kind"/>
-      <genFeatures createChild="false" ecoreFeature="ecore:EAttribute planetlab.ecore#//Interface/interface_address"/>
-      <genFeatures createChild="false" ecoreFeature="ecore:EAttribute planetlab.ecore#//Interface/interface_name"/>
-    </genClasses>
-  </genPackages>
-</genmodel:GenModel>
diff --git a/rspec/model/planetlab.xsd b/rspec/model/planetlab.xsd
deleted file mode 100644 (file)
index c607602..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<xsd:schema xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:pl="http://www.planet-lab.org" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ecore:nsPrefix="pl" ecore:package="planetlab.planetlab" targetNamespace="http://www.planet-lab.org">
-  <xsd:import namespace="http://www.eclipse.org/emf/2002/Ecore" schemaLocation="platform:/plugin/org.eclipse.emf.ecore/model/Ecore.xsd"/>
-  <xsd:element ecore:ignore="true" name="RSpec" type="pl:RSpec"/>
-  <xsd:element ecore:ignore="true" name="NetSpec" type="pl:NetSpec"/>
-  <xsd:element ecore:ignore="true" name="NodeSpec" type="pl:NodeSpec"/>
-  <xsd:element ecore:ignore="true" name="LinkSpec" type="pl:LinkSpec"/>
-  <xsd:element ecore:ignore="true" name="IfSpec" type="pl:IfSpec"/>
-  <xsd:element ecore:ignore="true" name="SwitchSpec" type="pl:SwitchSpec"/>
-  <xsd:complexType name="RSpec">
-    <xsd:attribute ecore:reference="pl:NetSpec" name="networks" use="required">
-      <xsd:simpleType>
-        <xsd:list itemType="xsd:anyURI"/>
-      </xsd:simpleType>
-    </xsd:attribute>
-    <xsd:attribute ecore:name="start_time" name="start_time" type="ecore:EDate"/>
-    <xsd:attribute name="duration" type="ecore:EDate"/>
-  </xsd:complexType>
-  <xsd:complexType name="NetSpec">
-    <xsd:sequence>
-      <xsd:element ecore:resolveProxies="true" maxOccurs="unbounded" minOccurs="0" name="links" type="pl:LinkSpec"/>
-    </xsd:sequence>
-    <xsd:attribute name="name" type="ecore:EString"/>
-    <xsd:attribute ecore:reference="pl:NodeSpec" name="nodes" use="required">
-      <xsd:simpleType>
-        <xsd:list itemType="xsd:anyURI"/>
-      </xsd:simpleType>
-    </xsd:attribute>
-    <xsd:attribute ecore:name="start_time" name="start_time" type="ecore:EDate"/>
-    <xsd:attribute name="duration" type="ecore:EDate"/>
-  </xsd:complexType>
-  <xsd:complexType name="NodeSpec">
-    <xsd:sequence>
-      <xsd:element ecore:unique="true" maxOccurs="1000" name="name" nillable="true" type="ecore:EString"/>
-    </xsd:sequence>
-    <xsd:attribute default="&quot;&quot;" ecore:unsettable="false" name="type" type="ecore:EString"/>
-    <xsd:attribute default="" ecore:name="init_params" ecore:unsettable="false" name="init_params" type="ecore:EByteArray"/>
-    <xsd:attribute default="0" ecore:name="cpu_min" ecore:unsettable="false" name="cpu_min" type="ecore:EInt"/>
-    <xsd:attribute default="0" ecore:name="cpu_share" ecore:unsettable="false" name="cpu_share" type="ecore:EInt"/>
-    <xsd:attribute default="0" ecore:name="cpu_pct" ecore:unsettable="false" name="cpu_pct" type="ecore:EInt"/>
-    <xsd:attribute default="0" ecore:name="disk_max" ecore:unsettable="false" name="disk_max" type="ecore:EInt"/>
-    <xsd:attribute ecore:name="net_if" ecore:reference="pl:IfSpec" name="net_if" use="required">
-      <xsd:simpleType>
-        <xsd:list itemType="xsd:anyURI"/>
-      </xsd:simpleType>
-    </xsd:attribute>
-    <xsd:attribute ecore:name="start_time" name="start_time" type="ecore:EDate"/>
-    <xsd:attribute name="duration" type="ecore:EDate"/>
-  </xsd:complexType>
-  <xsd:complexType name="LinkSpec">
-    <xsd:sequence>
-      <xsd:element default="0" ecore:unique="true" maxOccurs="unbounded" minOccurs="0" name="bw" type="ecore:EInt"/>
-      <xsd:element default="0" ecore:name="max_alloc" ecore:unique="true" maxOccurs="unbounded" minOccurs="0" name="max_alloc" type="ecore:EInt"/>
-    </xsd:sequence>
-    <xsd:attribute default="&quot;&quot;" ecore:changeable="false" ecore:unsettable="false" name="type" type="ecore:EString"/>
-    <xsd:attribute ecore:name="init_params" name="init_params" type="ecore:EByteArray"/>
-    <xsd:attribute default="0" ecore:name="min_alloc" ecore:unsettable="false" name="min_alloc" type="ecore:EInt"/>
-    <xsd:attribute ecore:changeable="false" ecore:reference="pl:IfSpec" name="endpoint" use="required">
-      <xsd:simpleType>
-        <xsd:list itemType="xsd:anyURI"/>
-      </xsd:simpleType>
-    </xsd:attribute>
-    <xsd:attribute ecore:name="start_time" name="start_time" type="ecore:EDate"/>
-    <xsd:attribute name="duration" type="ecore:EDate"/>
-  </xsd:complexType>
-  <xsd:complexType name="IfSpec">
-    <xsd:sequence>
-      <xsd:element default="5452595" ecore:name="max_kbyte" ecore:unique="true" ecore:unsettable="true" maxOccurs="unbounded" minOccurs="0" name="max_kbyte" type="ecore:EInt"/>
-    </xsd:sequence>
-    <xsd:attribute name="name" type="ecore:EString"/>
-    <xsd:attribute name="addr" type="ecore:EString"/>
-    <xsd:attribute default="" ecore:changeable="false" ecore:unsettable="false" name="type" type="ecore:EString"/>
-    <xsd:attribute default="" ecore:name="init_params" ecore:unsettable="false" name="init_params" type="ecore:EByteArray"/>
-    <xsd:attribute default="0" ecore:name="min_rate" ecore:unsettable="false" name="min_rate" type="ecore:EInt"/>
-    <xsd:attribute default="12207" ecore:name="max_rate" ecore:unsettable="false" name="max_rate" type="ecore:EInt"/>
-    <xsd:attribute default="false" ecore:name="ip_spoof" ecore:unsettable="false" name="ip_spoof" type="ecore:EBoolean"/>
-  </xsd:complexType>
-  <xsd:complexType name="SwitchSpec">
-    <xsd:complexContent>
-      <xsd:extension base="pl:NodeSpec">
-        <xsd:attribute default="0" ecore:name="fib_max" ecore:unsettable="false" name="fib_max" type="ecore:EInt"/>
-      </xsd:extension>
-    </xsd:complexContent>
-  </xsd:complexType>
-</xsd:schema>
diff --git a/rspec/sample_rspec.xml b/rspec/sample_rspec.xml
deleted file mode 100644 (file)
index 886fc8a..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<RSpec start_time="1235696400" duration="2419200">
-       <networks>
-               <NetSpec name="planetlab.us" start_time="1235696400" duration="2419200">
-                       <nodes>
-                               <NodeSpec name="planetlab-1.cs.princeton.edu" type="" init_params="" cpu_min="" cpu_share="" cpu_pct="" disk_max="" start_time="" duration="">
-                                       <net_if>
-                                               <IfSpec name="128.112.139.71" addr="128.112.139.71" type="ipv4" init_params="" min_rate="0" max_rate="10000000" max_kbyte="" ip_spoof="" />
-                                       </net_if>
-                               </NodeSpec>
-                               <NodeSpec name="planetlab-2.cs.princeton.edu" type="" init_params="" cpu_min="" cpu_share="" cpu_pct="" disk_max="" start_time="" duration="">
-                                       <net_if>
-                                               <IfSpec name="128.112.139.72" addr="128.112.139.72" type="ipv4" init_params="" min_rate="0" max_rate="10000000" max_kbyte="" ip_spoof="" />
-                                               <IfSpec name="128.112.139.120" addr="128.112.139.120" type="proxy" init_params="" min_rate="0" max_rate="" max_kbyte="" ip_spoof="" />
-                                               <IfSpec name="128.112.139.119" addr="128.112.139.119" type="proxy" init_params="" min_rate="0" max_rate="" max_kbyte="" ip_spoof="" />
-                                       </net_if>
-                               </NodeSpec>
-                       </nodes>
-               </NetSpec>
-               <NetSpec name="planetlab.eu" start_time="" duration="">
-                       <nodes>
-                               <NodeSpec name="onelab03.onelab.eu" type="" init_params="" cpu_min="" cpu_share="" cpu_pct="" disk_max="" start_time="" duration="">
-                                       <net_if>
-                                               <IfSpec name="128.112.139.321" addr="128.112.139.321" type="ipv4" init_params="" min_rate="0" max_rate="10000000" max_kbyte="" ip_spoof="" />
-                                       </net_if>
-                               </NodeSpec>
-                       </nodes>
-               </NetSpec>
-       </networks>
-</RSpec>
index 0c02f32..9f68e18 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -37,6 +37,7 @@ bins = [
 package_dirs = [
     'sfa', 
     'sfa/trust',
+    'sfa/storage',
     'sfa/util', 
     'sfa/client',
     'sfa/server',
@@ -55,6 +56,8 @@ package_dirs = [
     ]
 
 
+initscripts = [ 'sfa', 'sfa-cm' ]
+
 data_files = [('/etc/sfa/', [ 'config/aggregates.xml',
                               'config/registries.xml',
                               'config/default_config.xml',
@@ -70,7 +73,9 @@ data_files = [('/etc/sfa/', [ 'config/aggregates.xml',
                             ]),
               ('/etc/sfatables/matches/', glob('sfatables/matches/*.xml')),
               ('/etc/sfatables/targets/', glob('sfatables/targets/*.xml')),
-              ('/etc/init.d/', ['sfa/init.d/sfa', 'sfa/init.d/sfa-cm'])]
+              ('/etc/init.d/', [ "init.d/%s"%x for x in initscripts ]),
+              ('/usr/share/sfa/', [ 'sfa/storage/sfa.sql' ] ),
+              ]
 
 # add sfatables processors as data_files
 processor_files = [f for f in glob('sfatables/processors/*') if os.path.isfile(f)]
@@ -81,15 +86,13 @@ for d in processor_subdirs:
     d_files = [f for f in glob(d + '/*') if os.path.isfile(f)]
     data_files.append((etc_dir, processor_files))
 
-initscripts = [ '/etc/init.d/sfa', '/etc/init.d/sfa-cm' ]
-
 if sys.argv[1] in ['uninstall', 'remove', 'delete', 'clean']:
     python_path = sys.path
     site_packages_path = [ os.path.join(p,'sfa') for p in python_path if p.endswith('site-packages')]
     site_packages_path += [ os.path.join(p,'sfatables') for p in python_path if p.endswith('site-packages')]
     remove_dirs = ['/etc/sfa/', '/etc/sfatables'] + site_packages_path
     remove_bins = [ '/usr/bin/' + os.path.basename(bin) for bin in bins ]
-    remove_files = remove_bins + initscripts
+    remove_files = remove_bins + [ "/etc/init.d/%s"%x for x in initscripts ]
 
     # remove files   
     for filepath in remove_files:
index 57cebec..a938cc0 100644 (file)
--- a/sfa.spec
+++ b/sfa.spec
@@ -1,6 +1,6 @@
 %define name sfa
-%define version 1.1
-%define taglevel 5
+%define version 2.0
+%define taglevel 1
 
 %define release %{taglevel}%{?pldistro:.%{pldistro}}%{?date:.%{date}}
 %global python_sitearch        %( python -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)" )
@@ -14,6 +14,8 @@ License: GPL
 Group: Applications/System
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
 
+# xxx TODO : package cron.d/
+
 Vendor: PlanetLab
 Packager: PlanetLab Central <support@planet-lab.org>
 Distribution: PlanetLab %{plrelease}
@@ -123,6 +125,8 @@ make VERSIONTAG="%{version}-%{taglevel}" SCMURL="%{SCMURL}"
 rm -rf $RPM_BUILD_ROOT
 make VERSIONTAG="%{version}-%{taglevel}" SCMURL="%{SCMURL}" install DESTDIR="$RPM_BUILD_ROOT"
 rm -rf $RPM_BUILD_ROOT/%{python_sitelib}/*egg-info
+# this gets duplicated
+rm -rf $RPM_BUILD_ROOT/%{python_sitelib}/sfa/storage/sfa.sql
 
 %clean
 rm -rf $RPM_BUILD_ROOT
@@ -138,6 +142,7 @@ rm -rf $RPM_BUILD_ROOT
 %config /etc/sfa/default_config.xml
 %config (noreplace) /etc/sfa/aggregates.xml
 %config (noreplace) /etc/sfa/registries.xml
+/usr/share/sfa/sfa.sql
 /var/www/html/wsdl/*.wsdl
 
 %files plc
@@ -207,6 +212,23 @@ fi
 [ "$1" -ge "1" ] && service sfa-cm restart || :
 
 %changelog
+* Wed Nov 30 2011 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - sfa-2.0-1
+- cleaned up all references to SFA_*_TYPE in config
+- enable cache at the aggregate by default
+- registry now uses the driver in a sensible way (see managers/driver.py)
+- slice manager supports sfav1/pgv2 neighbours
+- get_key renamed into get_key_from_incoming_ip
+- new sfa.storage module for record/table and all db-related stuff
+- db schema in sfa.storage.sfa.sql
+- init.d and cron.d move one step up
+- cleaned up rspec/ directory
+- add deps to pyopenssl and myplc-config
+- start support for new API (return value)
+- plc.remoteshell removed, use plshell instead
+- plshell uses a 'capability' auth method whenever possible
+- various tweaks in rspec elements
+- made dependency on sfatables softer
+
 * Thu Nov 24 2011 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - sfa-1.1-5
 - sfa should now be started *before* the initial import
 - sfa to use its own database (default sfa) - can run without myplc
diff --git a/sfa/client/return_value.py b/sfa/client/return_value.py
new file mode 100644 (file)
index 0000000..034dcd8
--- /dev/null
@@ -0,0 +1,22 @@
+
+class ReturnValue(dict):
+    
+
+    @staticmethod
+    def get_code(return_value):
+        return ReturnValue.get_key_value('code', return_value) 
+
+    @staticmethod
+    def get_value(return_value):
+        return ReturnValue.get_key_value('value', return_value) 
+
+    @staticmethod
+    def get_output(return_value):
+        return ReturnValue.get_key_value('output', return_value) 
+
+    @staticmethod
+    def get_key_value(key, return_value):
+        if isinstance(return_value, dict) and return_value.has_key(key):
+            return return_value.get(key)
+        else:
+            return return_value              
index 52a9105..c45f771 100755 (executable)
@@ -8,11 +8,13 @@ import xmlrpclib
 from types import StringTypes, ListType
 from optparse import OptionParser
 
+from sfa.util.sfalogging import logger
+
 from sfa.trust.certificate import Certificate
 from sfa.trust.credential import Credential
 from sfa.trust.gid import GID
-from sfa.util.record import SfaRecord
-from sfa.util.sfalogging import logger
+
+from sfa.storage.record import SfaRecord
 
 def determine_sfa_filekind(fn):
 
index 9ed3c84..132a84c 100755 (executable)
@@ -4,6 +4,7 @@
 
 import sys
 sys.path.append('.')
+
 import os, os.path
 import tempfile
 import socket
@@ -13,21 +14,27 @@ import pickle
 from lxml import etree
 from StringIO import StringIO
 from optparse import OptionParser
-from sfa.client.client_helper import pg_users_arg, sfa_users_arg
-from sfa.util.sfalogging import sfi_logger
+
 from sfa.trust.certificate import Keypair, Certificate
 from sfa.trust.gid import GID
 from sfa.trust.credential import Credential
 from sfa.trust.sfaticket import SfaTicket
-from sfa.util.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
-from sfa.rspecs.rspec import RSpec
-from sfa.rspecs.rspec_converter import RSpecConverter
+
+from sfa.util.sfalogging import sfi_logger
 from sfa.util.xrn import get_leaf, get_authority, hrn_to_urn
-import sfa.client.xmlrpcprotocol as xmlrpcprotocol
 from sfa.util.config import Config
 from sfa.util.version import version_core
 from sfa.util.cache import Cache
+
+from sfa.storage.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
+
+from sfa.rspecs.rspec import RSpec
+from sfa.rspecs.rspec_converter import RSpecConverter
 from sfa.rspecs.version_manager import VersionManager
+from sfa.client.return_value import ReturnValue
+
+import sfa.client.xmlrpcprotocol as xmlrpcprotocol
+from sfa.client.client_helper import pg_users_arg, sfa_users_arg
 
 AGGREGATE_PORT=12346
 CM_PORT=12346
@@ -417,15 +424,15 @@ class Sfi:
 
         if cache:
             version = cache.get(cache_key)
-            
+
         if not version: 
-            version = server.GetVersion()
+            result = server.GetVersion()
+            version= ReturnValue.get_value(result)
             # cache version for 24 hours
             cache.add(cache_key, version, ttl= 60*60*24)
             self.logger.info("Updating cache file %s" % cache_file)
             cache.save_to_file(cache_file)
 
-
         return version   
         
 
@@ -912,7 +919,8 @@ class Sfi:
                 server=self.registry
             else:
                 server = self.server_proxy_from_opts(opts)
-            version=server.GetVersion()
+            result = server.GetVersion()
+            version = ReturnValue.get_value(result)
         for (k,v) in version.iteritems():
             print "%-20s: %s"%(k,v)
         if opts.file:
@@ -933,8 +941,9 @@ class Sfi:
         if self.server_supports_options_arg(server):
             options = {'call_id': unique_call_id()}
             call_args.append(options)
-        results = server.ListSlices(*call_args)
-        display_list(results)
+        result = server.ListSlices(*call_args)
+        value = ReturnValue.get_value(result)
+        display_list(value)
         return
     
     # show rspec for named slice
@@ -964,18 +973,20 @@ class Sfi:
             server_version = self.get_cached_server_version(server)
             if 'sfa' in server_version:
                 # just request the version the client wants 
-                options['rspec_version'] = version_manager.get_version(opts.rspec_version).to_dict()
+                options['geni_rspec_version'] = version_manager.get_version(opts.rspec_version).to_dict()
             else:
                 # this must be a protogeni aggregate. We should request a v2 ad rspec
                 # regardless of what the client user requested 
-                options['rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict()     
-
+                options['geni_rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict()     
+        options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'}
         call_args = [creds, options]
         result = server.ListResources(*call_args)
+        value = ReturnValue.get_value(result)
         if opts.file is None:
-            display_rspec(result, opts.format)
+            display_rspec(value, opts.format)
         else:
-            save_rspec_to_file(result, opts.file)
+            save_rspec_to_file(value, opts.file)
         return
 
     # created named slice with given rspec
@@ -1027,11 +1038,12 @@ class Sfi:
             options = {'call_id': unique_call_id()}
             call_args.append(options)
         result = server.CreateSliver(*call_args)
+        value = ReturnValue.get_value(result)
         if opts.file is None:
-            print result
+            print value
         else:
-            save_rspec_to_file (result, opts.file)
-        return result
+            save_rspec_to_file (value, opts.file)
+        return value
 
     # get a ticket for the specified slice
     def get_ticket(self, opts, args):
@@ -1153,7 +1165,9 @@ class Sfi:
         if self.server_supports_options_arg(server):
             options = {'call_id': unique_call_id()}
             call_args.append(options)
-        return server.RenewSliver(*call_args)
+        result =  server.RenewSliver(*call_args)
+        value = ReturnValue.get_value(result)
+        return value
 
 
     def status(self, opts, args):
@@ -1170,9 +1184,10 @@ class Sfi:
             options = {'call_id': unique_call_id()}
             call_args.append(options)
         result = server.SliverStatus(*call_args)
-        print result
+        value = ReturnValue.get_value(result)
+        print value
         if opts.file:
-            save_variable_to_file(result, opts.file, opts.fileformat)
+            save_variable_to_file(value, opts.file, opts.fileformat)
 
 
     def shutdown(self, opts, args):
index 0f9043b..363f3dd 100644 (file)
@@ -46,7 +46,7 @@ class Generic:
     # see pl.py for an example
     # some descendant of SfaApi
     def api_class (self) : pass
-    # in practical terms these are modules for now
+    # the python classes to use to build up the context
     def registry_class (self) : pass
     def slicemgr_class (self) : pass
     def aggregate_class (self) : pass
@@ -64,9 +64,10 @@ class Generic:
         driver = self.make_driver (api.config, api.interface)
         ### arrange stuff together
         # add a manager wrapper
-        manager = ManagerWrapper(manager,api.interface)
-        api.manager=manager
+        manager_wrap = ManagerWrapper(manager,api.interface)
+        api.manager=manager_wrap
         # insert driver in manager
+        logger.info("Setting manager.driver, manager=%s"%manager)
         manager.driver=driver
         # add it in api as well for convenience
         api.driver=driver
index 15a5bc6..4594534 100755 (executable)
@@ -18,12 +18,13 @@ import os
 import getopt
 import sys
 
-from sfa.util.table import SfaTable
 from sfa.util.xrn import get_leaf, get_authority
 from sfa.util.plxrn import hostname_to_hrn, slicename_to_hrn, email_to_hrn, hrn_to_pl_slicename
 from sfa.util.config import Config
 from sfa.util.xrn import Xrn
 
+from sfa.storage.table import SfaTable
+
 from sfa.importer.sfaImport import sfaImport
 
 def process_options():
@@ -70,9 +71,9 @@ def main():
     interface_hrn = config.SFA_INTERFACE_HRN
     keys_filename = config.config_path + os.sep + 'person_keys.py' 
     sfaImporter = sfaImport()
-    if config.SFA_API_DEBUG: sfaImporter.logger.setLevelDebug()
+    logger=sfaImporter.logger
+    if config.SFA_API_DEBUG: logger.setLevelDebug()
     shell = sfaImporter.shell
-    plc_auth = sfaImporter.plc_auth 
     
     # initialize registry db table
     table = SfaTable()
@@ -86,11 +87,11 @@ def main():
     sfaImporter.create_sm_client_record()
 
     # create interface records
-    sfaImporter.logger.info("Import: creating interface records")
+    logger.info("Import: creating interface records")
     sfaImporter.create_interface_records()
 
     # add local root authority's cert  to trusted list
-    sfaImporter.logger.info("Import: adding " + interface_hrn + " to trusted list")
+    logger.info("Import: adding " + interface_hrn + " to trusted list")
     authority = sfaImporter.AuthHierarchy.get_auth_info(interface_hrn)
     sfaImporter.TrustedRoots.add_gid(authority.get_gid_object())
 
@@ -112,13 +113,13 @@ def main():
         existing_hrns.append(result['hrn']) 
             
     # Get all plc sites
-    sites = shell.GetSites(plc_auth, {'peer_id': None})
+    sites = shell.GetSites({'peer_id': None})
     sites_dict = {}
     for site in sites:
         sites_dict[site['login_base']] = site 
     
     # Get all plc users
-    persons = shell.GetPersons(plc_auth, {'peer_id': None, 'enabled': True}, 
+    persons = shell.GetPersons({'peer_id': None, 'enabled': True}, 
                                ['person_id', 'email', 'key_ids', 'site_ids'])
     persons_dict = {}
     for person in persons:
@@ -126,7 +127,7 @@ def main():
         key_ids.extend(person['key_ids'])
 
     # Get all public keys
-    keys = shell.GetKeys(plc_auth, {'peer_id': None, 'key_id': key_ids})
+    keys = shell.GetKeys( {'peer_id': None, 'key_id': key_ids})
     keys_dict = {}
     for key in keys:
         keys_dict[key['key_id']] = key['key']
@@ -140,20 +141,20 @@ def main():
         person_keys[person['person_id']] = pubkeys
 
     # Get all plc nodes  
-    nodes = shell.GetNodes(plc_auth, {'peer_id': None}, ['node_id', 'hostname', 'site_id'])
+    nodes = shell.GetNodes( {'peer_id': None}, ['node_id', 'hostname', 'site_id'])
     nodes_dict = {}
     for node in nodes:
         nodes_dict[node['node_id']] = node
 
     # Get all plc slices
-    slices = shell.GetSlices(plc_auth, {'peer_id': None}, ['slice_id', 'name'])
+    slices = shell.GetSlices( {'peer_id': None}, ['slice_id', 'name'])
     slices_dict = {}
     for slice in slices:
         slices_dict[slice['slice_id']] = slice
     # start importing 
     for site in sites:
         site_hrn = _get_site_hrn(interface_hrn, site)
-        sfaImporter.logger.info("Importing site: %s" % site_hrn)
+        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
@@ -272,7 +273,7 @@ def main():
             sfaImporter.delete_record(record_hrn, type) 
                                    
     # save pub keys
-    sfaImporter.logger.info('Import: saving current pub keys')
+    logger.info('Import: saving current pub keys')
     save_keys(keys_filename, person_keys)                
         
 if __name__ == "__main__":
index be7b0c1..5450a20 100755 (executable)
@@ -11,9 +11,10 @@ import sys
 import os
 from optparse import OptionParser
 
-from sfa.util.table import SfaTable
 from sfa.util.sfalogging import logger
 
+from sfa.storage.table import SfaTable
+
 def main():
    usage="%prog: trash the registry DB (the 'sfa' table in the 'planetlab5' database)"
    parser = OptionParser(usage=usage)
index 568fce8..3f054ba 100644 (file)
@@ -9,17 +9,18 @@
 ##
 
 from sfa.util.sfalogging import _SfaLogger
-
-from sfa.util.record import SfaRecord
-from sfa.util.table import SfaTable
 from sfa.util.xrn import get_authority, hrn_to_urn
 from sfa.util.plxrn import email_to_hrn
 from sfa.util.config import Config
+
 from sfa.trust.certificate import convert_public_key, Keypair
 from sfa.trust.trustedroots import TrustedRoots
 from sfa.trust.hierarchy import Hierarchy
 from sfa.trust.gid import create_uuid
 
+from sfa.storage.record import SfaRecord
+from sfa.storage.table import SfaTable
+
 
 def _un_unicode(str):
    if isinstance(str, unicode):
@@ -52,17 +53,12 @@ class sfaImport:
        self.AuthHierarchy = Hierarchy()
        self.config = Config()
        self.TrustedRoots = TrustedRoots(Config.get_trustedroots_dir(self.config))
-       self.plc_auth = self.config.get_plc_auth()
        self.root_auth = self.config.SFA_REGISTRY_ROOT_AUTH
         
-       # connect to planetlab
-       self.shell = None
-       if "Url" in self.plc_auth:
-          from sfa.plc.remoteshell import RemoteShell
-          self.shell = RemoteShell(self.logger)
-       else:
-          import PLC.Shell
-          self.shell = PLC.Shell.Shell(globals = globals())        
+       # should use a driver instead...
+       from sfa.plc.plshell import PlShell
+       # how to connect to planetlab 
+       self.shell = PlShell (self.config)
 
     def create_top_level_auth_records(self, hrn):
         """
@@ -145,7 +141,7 @@ class sfaImport:
             key_ids = person["key_ids"]
             # get the user's private key from the SSH keys they have uploaded
             # to planetlab
-            keys = self.shell.GetKeys(self.plc_auth, key_ids)
+            keys = self.shell.GetKeys(key_ids)
             key = keys[0]['key']
             pkey = None
             try:
index 56d6008..2fbdf3d 100644 (file)
@@ -25,8 +25,8 @@ class AggregateManager:
 
     def __init__ (self):
         # xxx Thierry : caching at the aggregate level sounds wrong...
-        #self.caching=True
-        self.caching=False
+        self.caching=True
+        #self.caching=False
     
     def GetVersion(self, api, options={}):
     
@@ -40,7 +40,7 @@ class AggregateManager:
                 request_rspec_versions.append(rspec_version.to_dict()) 
         xrn=Xrn(api.hrn)
         version_more = {'interface':'aggregate',
-                        'sfa': 1,
+                        'sfa': 2,
                         'geni_api': api.config.SFA_AGGREGATE_API_VERSION,
                         'testbed':'myplc',
                         'hrn':xrn.get_hrn(),
@@ -304,8 +304,8 @@ class AggregateManager:
     
         version_manager = VersionManager()
         # get the rspec's return format from options
-        rspec_version = version_manager.get_version(options.get('rspec_version'))
-        version_string = "rspec_%s" % (rspec_version.to_string())
+        rspec_version = version_manager.get_version(options.get('geni_rspec_version'))
+        version_string = "rspec_%s" % (rspec_version)
     
         #panos adding the info option to the caching key (can be improved)
         if options.get('info'):
diff --git a/sfa/managers/driver.py b/sfa/managers/driver.py
new file mode 100644 (file)
index 0000000..7d4b5b2
--- /dev/null
@@ -0,0 +1,52 @@
+# 
+# an attempt to document what a driver class should provide, 
+# and implement reasonable defaults
+#
+
+class Driver:
+    
+    def __init__ (self): pass
+
+    # redefine this if you want to check again records 
+    # when running GetCredential
+    # This is to reflect the 'enabled' user field in planetlab testbeds
+    # expected retcod boolean
+    def is_enabled (self, record) : 
+        return True
+
+    # the following is used in Resolve (registry) when run in full mode
+    #     after looking up the sfa db, we wish to be able to display
+    #     testbed-specific info as well
+    # this at minima should fill in the 'researcher' field for slice records
+    def augment_records_with_testbed_info (self, sfa_records):
+        return sfa_records
+
+    # incoming record, as provided by the client to the Register API call
+    # expected retcod 'pointer'
+    # 'pointer' is typically an int db id, that makes sense in the testbed environment
+    # -1 if this feature is not relevant 
+    # here type will be 'authority'
+    def register (self, sfa_record, hrn, pub_key) : 
+        return -1
+
+    # incoming record is the existing sfa_record
+    # expected retcod boolean, error message logged if result is False
+    def remove (self, sfa_record): 
+        return True
+
+    # incoming are the sfa_record:
+    # (*) old_sfa_record is what we have in the db for that hrn
+    # (*) new_sfa_record is what was passed in the Update call
+    # expected retcod boolean, error message logged if result is False
+    # NOTE 1. about keys
+    # this is confusing because a user may have several ssh keys in 
+    # the planetlab database, but we need to pick one to generate its cert
+    # so as much as in principle we should be able to use new_sfa_record['keys']
+    # the manager code actually picks one (the first one), and it seems safer
+    # to pass it along rather than depending on the driver code to do the same
+    #
+    # NOTE 2. about keys
+    # when changing the ssh key through this method the gid gets changed too
+    # should anything be passed back to the caller in this case ?
+    def update (self, old_sfa_record, new_sfa_record, hrn, new_key): 
+        return True
index 941e4b0..93d2ea8 100644 (file)
@@ -1,20 +1,26 @@
 import types
 import time 
+# for get_key_from_incoming_ip
+import tempfile
+import os
+import commands
 
 from sfa.util.faults import RecordNotFound, AccountNotEnabled, PermissionError, MissingAuthority, \
-    UnknownSfaType, ExistingRecord
+    UnknownSfaType, ExistingRecord, NonExistingRecord
 from sfa.util.prefixTree import prefixTree
-from sfa.util.record import SfaRecord
-from sfa.util.table import SfaTable
-from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn, urn_to_hrn
+from sfa.util.xrn import Xrn, get_authority, hrn_to_urn, urn_to_hrn
 from sfa.util.plxrn import hrn_to_pl_login_base
 from sfa.util.version import version_core
+from sfa.util.sfalogging import logger
 
 from sfa.trust.gid import GID 
 from sfa.trust.credential import Credential
 from sfa.trust.certificate import Certificate, Keypair, convert_public_key
 from sfa.trust.gid import create_uuid
 
+from sfa.storage.record import SfaRecord
+from sfa.storage.table import SfaTable
+
 class RegistryManager:
 
     def __init__ (self): pass
@@ -50,9 +56,8 @@ class RegistryManager:
     
         # verify_cancreate_credential requires that the member lists
         # (researchers, pis, etc) be filled in
-        api.driver.fill_record_info(record, api.aggregates)
-        if record['type']=='user':
-           if not record['enabled']:
+        self.driver.augment_records_with_testbed_info (record)
+        if not self.driver.is_enabled (record):
               raise AccountNotEnabled(": PlanetLab account %s is not enabled. Please contact your site PI" %(record['email']))
     
         # get the callers gid
@@ -91,13 +96,14 @@ class RegistryManager:
     
     def Resolve(self, api, xrns, type=None, full=True):
     
-        # load all known registry names into a prefix tree and attempt to find
-        # the longest matching prefix
         if not isinstance(xrns, types.ListType):
+            xrns = [xrns]
+            # try to infer type if not set and we get a single input
             if not type:
                 type = Xrn(xrns).get_type()
-            xrns = [xrns]
         hrns = [urn_to_hrn(xrn)[0] for xrn in xrns] 
+        # load all known registry names into a prefix tree and attempt to find
+        # the longest matching prefix
         # create a dict where key is a registry hrn and its value is a
         # hrns at that registry (determined by the known prefix tree).  
         xrn_dict = {}
@@ -124,27 +130,41 @@ class RegistryManager:
             if registry_hrn != api.hrn:
                 credential = api.getCredential()
                 interface = api.registries[registry_hrn]
-                server = api.server_proxy(interface, credential)
-                peer_records = server.Resolve(xrns, credential)
+                server_proxy = api.server_proxy(interface, credential)
+                peer_records = server_proxy.Resolve(xrns, credential)
                 records.extend([SfaRecord(dict=record).as_dict() for record in peer_records])
     
         # try resolving the remaining unfound records at the local registry
-        remaining_hrns = set(hrns).difference([record['hrn'] for record in records])
-        # convert set to list
-        remaining_hrns = [hrn for hrn in remaining_hrns] 
+        local_hrns = list ( set(hrns).difference([record['hrn'] for record in records]) )
+        # 
         table = SfaTable()
-        local_records = table.findObjects({'hrn': remaining_hrns})
+        local_records = table.findObjects({'hrn': local_hrns})
+        
         if full:
-            api.driver.fill_record_info(local_records, api.aggregates)
+            # in full mode we get as much info as we can, which involves contacting the 
+            # testbed for getting implementation details about the record
+            self.driver.augment_records_with_testbed_info(local_records)
+            # also we fill the 'url' field for known authorities
+            # used to be in the driver code, sounds like a poorman thing though
+            def solve_neighbour_url (record):
+                if not record['type'].startswith('authority'): return 
+                hrn=record['hrn']
+                for neighbour_dict in [ api.aggregates, api.registries ]:
+                    if hrn in neighbour_dict:
+                        record['url']=neighbour_dict[hrn].get_url()
+                        return 
+            [ solve_neighbour_url (record) for record in local_records ]
+                    
+        
         
         # convert local record objects to dicts
         records.extend([dict(record) for record in local_records])
-        if not records:
-            raise RecordNotFound(str(hrns))
-    
         if type:
             records = filter(lambda rec: rec['type'] in [type], records)
     
+        if not records:
+            raise RecordNotFound(str(hrns))
+    
         return records
     
     def List(self, api, xrn, origin_hrn=None):
@@ -167,8 +187,8 @@ class RegistryManager:
         if registry_hrn != api.hrn:
             credential = api.getCredential()
             interface = api.registries[registry_hrn]
-            server = api.server_proxy(interface, credential)
-            record_list = server.List(xrn, credential)
+            server_proxy = api.server_proxy(interface, credential)
+            record_list = server_proxy.List(xrn, credential)
             records = [SfaRecord(dict=record).as_dict() for record in record_list]
         
         # if we still have not found the record yet, try the local registry
@@ -193,7 +213,33 @@ class RegistryManager:
             pkey = certificate.get_pubkey()    
         gid = api.auth.hierarchy.create_gid(xrn, create_uuid(), pkey) 
         return gid.save_to_string(save_parents=True)
+    
+    ####################
+    # utility for handling relationships among the SFA objects 
+    # given that the SFA db does not handle this sort of relationsships
+    # it will rely on side-effects in the testbed to keep this persistent
+    
+    # subject_record describes the subject of the relationships
+    # ref_record contains the target values for the various relationships we need to manage
+    # (to begin with, this is just the slice x person relationship)
+    def update_relations (self, subject_record, ref_record):
+        type=subject_record['type']
+        if type=='slice':
+            self.update_relation(subject_record, 'researcher', ref_record.get('researcher'), 'user')
         
+    # field_key is the name of one field in the record, typically 'researcher' for a 'slice' record
+    # hrns is the list of hrns that should be linked to the subject from now on
+    # target_type would be e.g. 'user' in the 'slice' x 'researcher' example
+    def update_relation (self, sfa_record, field_key, hrns, target_type):
+        # locate the linked objects in our db
+        subject_type=sfa_record['type']
+        subject_id=sfa_record['pointer']
+        table = SfaTable()
+        link_sfa_records = table.find ({'type':target_type, 'hrn': hrns})
+        link_ids = [ rec.get('pointer') for rec in link_sfa_records ]
+        self.driver.update_relation (subject_type, target_type, subject_id, link_ids)
+        
+
     def Register(self, api, record):
     
         hrn, type = record['hrn'], record['type']
@@ -210,19 +256,17 @@ class RegistryManager:
            
         record = SfaRecord(dict = record)
         record['authority'] = get_authority(record['hrn'])
-        type = record['type']
-        hrn = record['hrn']
         auth_info = api.auth.get_auth_info(record['authority'])
         pub_key = None
         # make sure record has a gid
         if 'gid' not in record:
             uuid = create_uuid()
             pkey = Keypair(create=True)
-            if 'key' in record and record['key']:
-                if isinstance(record['key'], types.ListType):
-                    pub_key = record['key'][0]
-                else:
-                    pub_key = record['key']
+            if 'keys' in record and record['keys']:
+                pub_key=record['keys']
+                # use only first key in record
+                if isinstance(record['keys'], types.ListType):
+                    pub_key = record['keys'][0]
                 pkey = convert_public_key(pub_key)
     
             gid_object = api.auth.hierarchy.create_gid(urn, uuid, pkey)
@@ -238,68 +282,18 @@ class RegistryManager:
             # get the GID from the newly created authority
             gid = auth_info.get_gid_object()
             record.set_gid(gid.save_to_string(save_parents=True))
-            pl_record = api.driver.sfa_fields_to_pl_fields(type, hrn, record)
-            sites = api.driver.GetSites([pl_record['login_base']])
-            if not sites:
-                pointer = api.driver.AddSite(pl_record)
-            else:
-                pointer = sites[0]['site_id']
-    
-            record.set_pointer(pointer)
-            record['pointer'] = pointer
-    
-        elif (type == "slice"):
-            acceptable_fields=['url', 'instantiation', 'name', 'description']
-            pl_record = api.driver.sfa_fields_to_pl_fields(type, hrn, record)
-            for key in pl_record.keys():
-                if key not in acceptable_fields:
-                    pl_record.pop(key)
-            slices = api.driver.GetSlices([pl_record['name']])
-            if not slices:
-                 pointer = api.driver.AddSlice(pl_record)
-            else:
-                 pointer = slices[0]['slice_id']
-            record.set_pointer(pointer)
-            record['pointer'] = pointer
-    
-        elif  (type == "user"):
-            persons = api.driver.GetPersons([record['email']])
-            if not persons:
-                pointer = api.driver.AddPerson(dict(record))
-            else:
-                pointer = persons[0]['person_id']
-    
-            if 'enabled' in record and record['enabled']:
-                api.driver.UpdatePerson(pointer, {'enabled': record['enabled']})
-            # add this persons to the site only if he is being added for the first
-            # time by sfa and doesont already exist in plc
-            if not persons or not persons[0]['site_ids']:
-                login_base = get_leaf(record['authority'])
-                api.driver.AddPersonToSite(pointer, login_base)
-    
-            # What roles should this user have?
-            api.driver.AddRoleToPerson('user', pointer)
-            # Add the user's key
-            if pub_key:
-                api.driver.AddPersonKey(pointer, {'key_type' : 'ssh', 'key' : pub_key})
-    
-        elif (type == "node"):
-            pl_record = api.driver.sfa_fields_to_pl_fields(type, hrn, record)
-            login_base = hrn_to_pl_login_base(record['authority'])
-            nodes = api.driver.GetNodes([pl_record['hostname']])
-            if not nodes:
-                pointer = api.driver.AddNode(login_base, pl_record)
-            else:
-                pointer = nodes[0]['node_id']
-    
-        record['pointer'] = pointer
+
+        # update testbed-specific data f needed
+        logger.info("Getting driver from manager=%s"%self)
+        pointer = self.driver.register (record, hrn, pub_key)
+
         record.set_pointer(pointer)
         record_id = table.insert(record)
         record['record_id'] = record_id
     
         # update membership for researchers, pis, owners, operators
-        api.driver.update_membership(None, record)
-    
+        self.update_relations (record, record)
+        
         return record.get_gid_object().save_to_string(save_parents=True)
     
     def Update(self, api, record_dict):
@@ -315,75 +309,39 @@ class RegistryManager:
         record = records[0]
         record['last_updated'] = time.gmtime()
     
-        # Update_membership needs the membership lists in the existing record
-        # filled in, so it can see if members were added or removed
-        api.driver.fill_record_info(record, api.aggregates)
-    
+        # validate the type
+        if type not in ['authority', 'slice', 'node', 'user']:
+            raise UnknownSfaType(type) 
+
         # Use the pointer from the existing record, not the one that the user
         # gave us. This prevents the user from inserting a forged pointer
         pointer = record['pointer']
-        # update the PLC information that was specified with the record
-    
-        if (type == "authority"):
-            api.driver.UpdateSite(pointer, new_record)
-    
-        elif type == "slice":
-            pl_record=api.driver.sfa_fields_to_pl_fields(type, hrn, new_record)
-            if 'name' in pl_record:
-                pl_record.pop('name')
-                api.driver.UpdateSlice(pointer, pl_record)
-    
-        elif type == "user":
-            # SMBAKER: UpdatePerson only allows a limited set of fields to be
-            #    updated. Ideally we should have a more generic way of doing
-            #    this. I copied the field names from UpdatePerson.py...
-            update_fields = {}
-            all_fields = new_record
-            for key in all_fields.keys():
-                if key in ['first_name', 'last_name', 'title', 'email',
-                           'password', 'phone', 'url', 'bio', 'accepted_aup',
-                           'enabled']:
-                    update_fields[key] = all_fields[key]
-            api.driver.UpdatePerson(pointer, update_fields)
-    
-            if 'key' in new_record and new_record['key']:
-                # must check this key against the previous one if it exists
-                persons = api.driver.GetPersons([pointer], ['key_ids'])
-                person = persons[0]
-                keys = person['key_ids']
-                keys = api.driver.GetKeys(person['key_ids'])
-                key_exists = False
-                if isinstance(new_record['key'], types.ListType):
-                    new_key = new_record['key'][0]
-                else:
-                    new_key = new_record['key']
-                
-                # Delete all stale keys
-                for key in keys:
-                    if new_record['key'] != key['key']:
-                        api.driver.DeleteKey(key['key_id'])
-                    else:
-                        key_exists = True
-                if not key_exists:
-                    api.driver.AddPersonKey(pointer, {'key_type': 'ssh', 'key': new_key})
-    
-                # update the openssl key and gid
-                pkey = convert_public_key(new_key)
-                uuid = create_uuid()
-                gid_object = api.auth.hierarchy.create_gid(urn, uuid, pkey)
-                gid = gid_object.save_to_string(save_parents=True)
-                record['gid'] = gid
-                record = SfaRecord(dict=record)
-                table.update(record)
-    
-        elif type == "node":
-            api.driver.UpdateNode(pointer, new_record)
     
-        else:
-            raise UnknownSfaType(type)
+        # is the a change in keys ?
+        new_key=None
+        if type=='user':
+            if 'keys' in new_record and new_record['keys']:
+                new_key=new_record['keys']
+                if isinstance (new_key,types.ListType):
+                    new_key=new_key[0]
+
+        # update the PLC information that was specified with the record
+        if not self.driver.update (record, new_record, hrn, new_key):
+            logger.warning("driver.update failed")
     
+        # take new_key into account
+        if new_key:
+            # update the openssl key and gid
+            pkey = convert_public_key(new_key)
+            uuid = create_uuid()
+            gid_object = api.auth.hierarchy.create_gid(urn, uuid, pkey)
+            gid = gid_object.save_to_string(save_parents=True)
+            record['gid'] = gid
+            record = SfaRecord(dict=record)
+            table.update(record)
+        
         # update membership for researchers, pis, owners, operators
-        api.driver.update_membership(record, new_record)
+        self.update_relations (record, new_record)
         
         return 1 
     
@@ -401,7 +359,10 @@ class RegistryManager:
         if not records: raise RecordNotFound(hrn)
         record = records[0]
         type = record['type']
-    
+        
+        if type not in ['slice', 'user', 'node', 'authority'] :
+            raise UnknownSfaType(type)
+
         credential = api.getCredential()
         registries = api.registries
     
@@ -414,24 +375,77 @@ class RegistryManager:
                         result=registries[registry].remove_peer_object(credential, record, origin_hrn)
                     except:
                         pass
-        if type == "user":
-            persons = api.driver.GetPersons(record['pointer'])
-            # only delete this person if he has site ids. if he doesnt, it probably means
-            # he was just removed from a site, not actually deleted
-            if persons and persons[0]['site_ids']:
-                api.driver.DeletePerson(record['pointer'])
-        elif type == "slice":
-            if api.driver.GetSlices(record['pointer']):
-                api.driver.DeleteSlice(record['pointer'])
-        elif type == "node":
-            if api.driver.GetNodes(record['pointer']):
-                api.driver.DeleteNode(record['pointer'])
-        elif type == "authority":
-            if api.driver.GetSites(record['pointer']):
-                api.driver.DeleteSite(record['pointer'])
-        else:
-            raise UnknownSfaType(type)
-    
+
+        # call testbed callback first
+        # IIUC this is done on the local testbed TOO because of the refreshpeer link
+        if not self.driver.remove(record):
+            logger.warning("driver.remove failed")
+
+        # delete from sfa db
         table.remove(record)
     
         return 1
+
+    # This is a PLC-specific thing...
+    def get_key_from_incoming_ip (self, api):
+        # verify that the callers's ip address exist in the db and is an interface
+        # for a node in the db
+        (ip, port) = api.remote_addr
+        interfaces = self.driver.GetInterfaces({'ip': ip}, ['node_id'])
+        if not interfaces:
+            raise NonExistingRecord("no such ip %(ip)s" % locals())
+        nodes = self.driver.GetNodes([interfaces[0]['node_id']], ['node_id', 'hostname'])
+        if not nodes:
+            raise NonExistingRecord("no such node using ip %(ip)s" % locals())
+        node = nodes[0]
+       
+        # look up the sfa record
+        table = SfaTable()
+        records = table.findObjects({'type': 'node', 'pointer': node['node_id']})
+        if not records:
+            raise RecordNotFound("pointer:" + str(node['node_id']))  
+        record = records[0]
+        
+        # generate a new keypair and gid
+        uuid = create_uuid()
+        pkey = Keypair(create=True)
+        urn = hrn_to_urn(record['hrn'], record['type'])
+        gid_object = api.auth.hierarchy.create_gid(urn, uuid, pkey)
+        gid = gid_object.save_to_string(save_parents=True)
+        record['gid'] = gid
+        record.set_gid(gid)
+
+        # update the record
+        table.update(record)
+  
+        # attempt the scp the key
+        # and gid onto the node
+        # this will only work for planetlab based components
+        (kfd, key_filename) = tempfile.mkstemp() 
+        (gfd, gid_filename) = tempfile.mkstemp() 
+        pkey.save_to_file(key_filename)
+        gid_object.save_to_file(gid_filename, save_parents=True)
+        host = node['hostname']
+        key_dest="/etc/sfa/node.key"
+        gid_dest="/etc/sfa/node.gid" 
+        scp = "/usr/bin/scp" 
+        #identity = "/etc/planetlab/root_ssh_key.rsa"
+        identity = "/etc/sfa/root_ssh_key"
+        scp_options=" -i %(identity)s " % locals()
+        scp_options+="-o StrictHostKeyChecking=no " % locals()
+        scp_key_command="%(scp)s %(scp_options)s %(key_filename)s root@%(host)s:%(key_dest)s" %\
+                         locals()
+        scp_gid_command="%(scp)s %(scp_options)s %(gid_filename)s root@%(host)s:%(gid_dest)s" %\
+                         locals()    
+
+        all_commands = [scp_key_command, scp_gid_command]
+        
+        for command in all_commands:
+            (status, output) = commands.getstatusoutput(command)
+            if status:
+                raise Exception, output
+
+        for filename in [key_filename, gid_filename]:
+            os.unlink(filename)
+
+        return 1 
index 7c58a68..2fce139 100644 (file)
@@ -12,20 +12,18 @@ from sfa.util.sfalogging import logger
 from sfa.util.xrn import Xrn, urn_to_hrn
 from sfa.util.version import version_core
 from sfa.util.callids import Callids
-
 from sfa.server.threadmanager import ThreadManager
-
 from sfa.rspecs.rspec_converter import RSpecConverter
 from sfa.rspecs.version_manager import VersionManager
 from sfa.rspecs.rspec import RSpec 
 from sfa.client.client_helper import sfa_to_pg_users_arg
+from sfa.client.return_value import ReturnValue
 
 class SliceManager:
     def __init__ (self):
     #    self.caching=False
         self.caching=True
         
-    
     def _options_supported(self, api, server):
         """
         Returns true if server support the optional call_id arg, false otherwise.
@@ -124,7 +122,9 @@ class SliceManager:
             try:
                 version = api.get_cached_server_version(server)
                 # force ProtoGENI aggregates to give us a v2 RSpec
-                if 'sfa' not in version.keys():
+                if 'sfa' in version.keys():
+                    my_opts['rspec_version'] = version_manager.get_version('SFA 1').to_dict()
+                else:
                     my_opts['rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict()
                 rspec = server.ListResources(*args)
                 return {"aggregate": aggregate, "rspec": rspec, "elapsed": time.time()-tStart, "status": "success"}
@@ -142,7 +142,7 @@ class SliceManager:
     
         # get the rspec's return format from options
         rspec_version = version_manager.get_version(options.get('rspec_version'))
-        version_string = "rspec_%s" % (rspec_version.to_string())
+        version_string = "rspec_%s" % (rspec_version)
     
         # look in cache first
         if self.caching and api.cache and not xrn:
@@ -182,7 +182,7 @@ class SliceManager:
             self.add_slicemgr_stat(rspec, "ListResources", result["aggregate"], result["elapsed"], result["status"], result.get("exc_info",None))
             if result["status"]=="success":
                 try:
-                    rspec.version.merge(result["rspec"])
+                    rspec.version.merge(ReturnValue.get_value(result["rspec"]))
                 except:
                     api.logger.log_exc("SM.ListResources: Failed to merge aggregate rspec")
     
@@ -261,7 +261,7 @@ class SliceManager:
             self.add_slicemgr_stat(result_rspec, "CreateSliver", result["aggregate"], result["elapsed"], result["status"], result.get("exc_info",None))
             if result["status"]=="success":
                 try:
-                    result_rspec.version.merge(result["rspec"])
+                    result_rspec.version.merge(ReturnValue.get_value(result["rspec"]))
                 except:
                     api.logger.log_exc("SM.CreateSliver: Failed to merge aggregate rspec")
         return result_rspec.toxml()
@@ -296,7 +296,8 @@ class SliceManager:
             server = api.server_proxy(interface, cred)
             threads.run(_RenewSliver, server, xrn, [cred], expiration_time, call_id)
         # 'and' the results
-        return reduce (lambda x,y: x and y, threads.get_results() , True)
+        results = [ReturnValue.get_value(result) for result in threads.get_results()]
+        return reduce (lambda x,y: x and y, results , True)
     
     def DeleteSliver(self, api, xrn, creds, options={}):
         def _DeleteSliver(server, xrn, creds, options={}):
@@ -350,7 +351,7 @@ class SliceManager:
             interface = api.aggregates[aggregate]
             server = api.server_proxy(interface, cred)
             threads.run (_SliverStatus, server, slice_xrn, [cred], call_id)
-        results = threads.get_results()
+        results = [ReturnValue.get_value(result) for result in threads.get_results()]
     
         # get rid of any void result - e.g. when call_id was hit where by convention we return {}
         results = [ result for result in results if result and result['geni_resources']]
@@ -410,7 +411,7 @@ class SliceManager:
             threads.run(_ListSlices, server, [cred], options)
     
         # combime results
-        results = threads.get_results()
+        results = [ReturnValue.get_value(result) for result in threads.get_results()]
         slices = []
         for result in results:
             slices.extend(result)
index db69acd..eb001a1 100644 (file)
@@ -1,7 +1,8 @@
 
 from sfa.util.xrn import urn_to_hrn
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter, Mixed
+
+from sfa.storage.parameter import Parameter, Mixed
 from sfa.trust.credential import Credential
 
 class CreateGid(Method):
index 218986e..fb1a292 100644 (file)
@@ -1,9 +1,12 @@
 from sfa.util.faults import SfaInvalidArgument
 from sfa.util.xrn import urn_to_hrn
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter, Mixed
 from sfa.util.sfatablesRuntime import run_sfatables
+
 from sfa.trust.credential import Credential
+
+from sfa.storage.parameter import Parameter, Mixed
+
 from sfa.rspecs.rspec import RSpec
 
 class CreateSliver(Method):
index fe07b6a..6be2bc4 100644 (file)
@@ -1,6 +1,6 @@
 from sfa.util.xrn import urn_to_hrn
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter, Mixed
+from sfa.storage.parameter import Parameter, Mixed
 from sfa.trust.auth import Auth
 from sfa.trust.credential import Credential
 
index d966dd3..50525c2 100644 (file)
@@ -1,8 +1,10 @@
 from sfa.util.xrn import urn_to_hrn
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter, Mixed
+
 from sfa.trust.credential import Credential
 
+from sfa.storage.parameter import Parameter, Mixed
+
 class GetCredential(Method):
     """
     Retrive a credential for an object
index 5c1470b..f67f5d4 100644 (file)
@@ -1,8 +1,10 @@
 from sfa.util.faults import RecordNotFound
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter, Mixed
+
 from sfa.trust.credential import Credential
 
+from sfa.storage.parameter import Parameter, Mixed
+
 class GetGids(Method):
     """
     Get a list of record information (hrn, gid and type) for 
index efad180..fd87ca0 100644 (file)
@@ -2,10 +2,12 @@
 from sfa.util.faults import RecordNotFound, ConnectionKeyGIDMismatch
 from sfa.util.xrn import urn_to_hrn
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter, Mixed
-from sfa.util.record import SfaRecord
+
 from sfa.trust.certificate import Certificate
 
+from sfa.storage.parameter import Parameter, Mixed
+from sfa.storage.record import SfaRecord
+
 class GetSelfCredential(Method):
     """
     Retrive a credential for an object
index b1d8f87..2223e37 100644 (file)
@@ -1,10 +1,11 @@
 from sfa.util.xrn import urn_to_hrn
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter, Mixed
 from sfa.util.sfatablesRuntime import run_sfatables
 
 from sfa.trust.credential import Credential
 
+from sfa.storage.parameter import Parameter, Mixed
+
 class GetTicket(Method):
     """
     Retrieve a ticket. This operation is currently implemented on PLC
index 801b339..9dc586f 100644 (file)
@@ -1,5 +1,6 @@
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter
+
+from sfa.storage.parameter import Parameter
 
 
 class GetVersion(Method):
index 55dd7dd..bbd3e47 100644 (file)
@@ -1,10 +1,12 @@
 
 from sfa.util.xrn import urn_to_hrn
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter, Mixed
-from sfa.util.record import SfaRecord
+
 from sfa.trust.credential import Credential
 
+from sfa.storage.parameter import Parameter, Mixed
+from sfa.storage.record import SfaRecord
+
 class List(Method):
     """
     List the records in an authority. 
index 6b1e785..328ddb2 100644 (file)
@@ -2,9 +2,11 @@ import zlib
 
 from sfa.util.xrn import urn_to_hrn
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter, Mixed
-from sfa.trust.credential import Credential
 from sfa.util.sfatablesRuntime import run_sfatables
+from sfa.util.faults import SfaInvalidArgument
+from sfa.trust.credential import Credential
+
+from sfa.storage.parameter import Parameter, Mixed
 
 class ListResources(Method):
     """
@@ -23,7 +25,11 @@ class ListResources(Method):
 
     def call(self, creds, options={}):
         self.api.logger.info("interface: %s\tmethod-name: %s" % (self.api.interface, self.name))
-        
+       
+        # client must specify a version
+        if not options.get('geni_rspec_version'):
+            raise SfaInvalidArgument('Must specify an rspec version option. geni_rspec_version cannot be null')
         # get slice's hrn from options    
         xrn = options.get('geni_slice_urn', '')
         (hrn, _) = urn_to_hrn(xrn)
index eed408f..e14c9b6 100644 (file)
@@ -1,7 +1,9 @@
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter, Mixed
+
 from sfa.trust.credential import Credential
  
+from sfa.storage.parameter import Parameter, Mixed
+
 class ListSlices(Method):
     """
     List the slices instantiated at this interface       
index c6a75e2..522ff12 100644 (file)
@@ -1,5 +1,6 @@
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter, Mixed
+
+from sfa.storage.parameter import Parameter, Mixed
 
 class RedeemTicket(Method):
     """
index 2d9cbfd..87f9a0f 100644 (file)
@@ -1,7 +1,9 @@
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter, Mixed
+
 from sfa.trust.credential import Credential
 
+from sfa.storage.parameter import Parameter, Mixed
+
 class Register(Method):
     """
     Register an object with the registry. In addition to being stored in the
index 1804fd9..ee650f1 100644 (file)
@@ -1,8 +1,10 @@
 from sfa.util.xrn import Xrn
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter, Mixed
+
 from sfa.trust.credential import Credential
 
+from sfa.storage.parameter import Parameter, Mixed
+
 class Remove(Method):
     """
     Remove an object from the registry. If the object represents a PLC object,
index 48d6493..a380d99 100644 (file)
@@ -3,10 +3,12 @@ import datetime
 from sfa.util.faults import InsufficientRights
 from sfa.util.xrn import urn_to_hrn
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter
-from sfa.trust.credential import Credential
 from sfa.util.sfatime import utcparse
 
+from sfa.trust.credential import Credential
+
+from sfa.storage.parameter import Parameter
+
 class RenewSliver(Method):
     """
     Renews the resources in a sliver, extending the lifetime of the slice.    
index 094500f..9a6dd47 100644 (file)
@@ -2,9 +2,11 @@ import types
 
 from sfa.util.xrn import Xrn, urn_to_hrn
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter, Mixed
+
 from sfa.trust.credential import Credential
-from sfa.util.record import SfaRecord
+
+from sfa.storage.parameter import Parameter, Mixed
+from sfa.storage.record import SfaRecord
 
 class Resolve(Method):
     """
index 7c9cc14..e32bf6d 100644 (file)
@@ -1,5 +1,6 @@
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter
+
+from sfa.storage.parameter import Parameter
 
 class ResolveGENI(Method):
     """
index 9788608..273b991 100644 (file)
@@ -1,4 +1,5 @@
-from sfa.util.parameter import Parameter
+from sfa.storage.parameter import Parameter
+
 from sfa.methods.Stop import Stop
 
 class Shutdown(Stop):
index 2a0ac5d..f722c7c 100644 (file)
@@ -1,6 +1,7 @@
 from sfa.util.xrn import urn_to_hrn
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter, Mixed
+
+from sfa.storage.parameter import Parameter, Mixed
 
 class SliverStatus(Method):
     """
index 7f8aefd..1412222 100644 (file)
@@ -1,8 +1,10 @@
 from sfa.util.xrn import urn_to_hrn
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter, Mixed
+
 from sfa.trust.credential import Credential
 
+from sfa.storage.parameter import Parameter, Mixed
+
 class Start(Method):
     """
     Start the specified slice      
index 48974ab..0d80282 100644 (file)
@@ -1,8 +1,10 @@
 from sfa.util.xrn import urn_to_hrn
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter, Mixed
+
 from sfa.trust.credential import Credential
  
+from sfa.storage.parameter import Parameter, Mixed
+
 class Stop(Method):
     """
     Stop the specified slice      
index 7643302..e0b1003 100644 (file)
@@ -1,7 +1,9 @@
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter
+
 from sfa.trust.credential import Credential
 
+from sfa.storage.parameter import Parameter
+
 class Update(Method):
     """
     Update an object in the registry. Currently, this only updates the
index 245b207..3302b56 100644 (file)
@@ -1,4 +1,5 @@
-from sfa.util.parameter import Parameter, Mixed
+from sfa.storage.parameter import Parameter, Mixed
+
 from sfa.methods.CreateSliver import CreateSliver
 
 class UpdateSliver(CreateSliver):
index 0e47df6..8f35200 100644 (file)
@@ -23,7 +23,7 @@ Start
 Stop
 Update
 UpdateSliver
-get_key
+get_key_from_incoming_ip
 get_trusted_certs
 reset_slice
 """.split()
diff --git a/sfa/methods/get_key.py b/sfa/methods/get_key.py
deleted file mode 100644 (file)
index 1195d53..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-import os
-import tempfile
-import commands
-from sfa.util.faults import NonExistingRecord, RecordNotFound
-from sfa.util.xrn import hrn_to_urn
-from sfa.util.method import Method
-from sfa.util.parameter import Parameter
-from sfa.util.table import SfaTable
-from sfa.trust.certificate import Keypair
-from sfa.trust.gid import create_uuid
-
-class get_key(Method):
-    """
-    Generate a new keypair and gid for requesting caller (component).     
-    @return 1 If successful  
-    """
-
-    interfaces = ['registry']
-    
-    accepts = []
-
-    returns = Parameter(int, "1 if successful, faults otherwise")
-    
-    def call(self):
-        # verify that the callers's ip address exist in the db and is an interface
-        # for a node in the db
-        (ip, port) = self.api.remote_addr
-        interfaces = self.api.driver.GetInterfaces({'ip': ip}, ['node_id'])
-        if not interfaces:
-            raise NonExistingRecord("no such ip %(ip)s" % locals())
-        nodes = self.api.driver.GetNodes([interfaces[0]['node_id']], ['node_id', 'hostname'])
-        if not nodes:
-            raise NonExistingRecord("no such node using ip %(ip)s" % locals())
-        node = nodes[0]
-       
-        # look up the sfa record
-        table = SfaTable()
-        records = table.findObjects({'type': 'node', 'pointer': node['node_id']})
-        if not records:
-            raise RecordNotFound("pointer:" + str(node['node_id']))  
-        record = records[0]
-        
-        # generate a new keypair and gid
-        uuid = create_uuid()
-        pkey = Keypair(create=True)
-        urn = hrn_to_urn(record['hrn'], record['type'])
-        gid_object = self.api.auth.hierarchy.create_gid(urn, uuid, pkey)
-        gid = gid_object.save_to_string(save_parents=True)
-        record['gid'] = gid
-        record.set_gid(gid)
-
-        # update the record
-        table.update(record)
-  
-        # attempt the scp the key
-        # and gid onto the node
-        # this will only work for planetlab based components
-        (kfd, key_filename) = tempfile.mkstemp() 
-        (gfd, gid_filename) = tempfile.mkstemp() 
-        pkey.save_to_file(key_filename)
-        gid_object.save_to_file(gid_filename, save_parents=True)
-        host = node['hostname']
-        key_dest="/etc/sfa/node.key"
-        gid_dest="/etc/sfa/node.gid" 
-        scp = "/usr/bin/scp" 
-        #identity = "/etc/planetlab/root_ssh_key.rsa"
-        identity = "/etc/sfa/root_ssh_key"
-        scp_options=" -i %(identity)s " % locals()
-        scp_options+="-o StrictHostKeyChecking=no " % locals()
-        scp_key_command="%(scp)s %(scp_options)s %(key_filename)s root@%(host)s:%(key_dest)s" %\
-                         locals()
-        scp_gid_command="%(scp)s %(scp_options)s %(gid_filename)s root@%(host)s:%(gid_dest)s" %\
-                         locals()    
-
-        all_commands = [scp_key_command, scp_gid_command]
-        
-        for command in all_commands:
-            (status, output) = commands.getstatusoutput(command)
-            if status:
-                raise Exception, output
-
-        for filename in [key_filename, gid_filename]:
-            os.unlink(filename)
-
-        return 1 
diff --git a/sfa/methods/get_key_from_incoming_ip.py b/sfa/methods/get_key_from_incoming_ip.py
new file mode 100644 (file)
index 0000000..5887f99
--- /dev/null
@@ -0,0 +1,24 @@
+from sfa.util.method import Method
+from sfa.util.sfalogging import logger
+
+from sfa.storage.parameter import Parameter
+
+class get_key_from_incoming_ip(Method):
+    """
+    Generate a new keypair and gid for requesting caller (component/node).     
+    This is a myplc-specific API call used by component manager
+    @return 1 If successful  
+    """
+
+    interfaces = ['registry']
+    
+    accepts = []
+
+    returns = Parameter(int, "1 if successful, faults otherwise")
+    
+    def call(self):
+        if hasattr(self.api.manager,'get_key_from_incoming_ip'):
+            return self.api.manager.get_key_from_incoming_ip (api)
+        else:
+            logger.warning("get_key_from_incoming_ip not supported by registry manager")
+            return 0
index 460ab4d..7a4e1c5 100644 (file)
@@ -1,9 +1,9 @@
-#from sfa.util.faults import *
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter, Mixed
+
 from sfa.trust.auth import Auth
 from sfa.trust.credential import Credential
 
+from sfa.storage.parameter import Parameter, Mixed
 
 class get_trusted_certs(Method):
     """
index 387981d..c3975ff 100644 (file)
@@ -1,6 +1,7 @@
 from sfa.util.xrn import urn_to_hrn
 from sfa.util.method import Method
-from sfa.util.parameter import Parameter, Mixed
+
+from sfa.storage.parameter import Parameter, Mixed
 
 class reset_slice(Method):
     """
index c991bd6..07a655c 100644 (file)
@@ -51,7 +51,7 @@ class PlComponentDriver:
         cert.save_to_file(certfile)
         registry = self.get_registry()
         # the registry will scp the key onto the node
-        registry.get_key()        
+        registry.get_key_from_incoming_ip()        
 
     # override the method in SfaApi
     def getCredential(self):
index af3b213..d5d5bf9 100644 (file)
@@ -1,12 +1,16 @@
 #
-from sfa.util.faults import MissingSfaInfo
+from sfa.util.faults import MissingSfaInfo, UnknownSfaType
 from sfa.util.sfalogging import logger
-from sfa.util.table import SfaTable
 from sfa.util.defaultdict import defaultdict
-
-from sfa.util.xrn import hrn_to_urn
+from sfa.util.xrn import hrn_to_urn, get_leaf
 from sfa.util.plxrn import slicename_to_hrn, hostname_to_hrn, hrn_to_pl_slicename, hrn_to_pl_login_base
 
+# one would think the driver should not need to mess with the SFA db, but..
+from sfa.storage.table import SfaTable
+
+# the driver interface, mostly provides default behaviours
+from sfa.managers.driver import Driver
+
 from sfa.plc.plshell import PlShell
 
 def list_to_dict(recs, key):
@@ -14,87 +18,237 @@ def list_to_dict(recs, key):
     convert a list of dictionaries into a dictionary keyed on the 
     specified dictionary key 
     """
-    keys = [rec[key] for rec in recs]
-    return dict(zip(keys, recs))
+    return dict ( [ (rec[key],rec) for rec in recs ] )
 
-class PlDriver (PlShell):
+#
+# PlShell is just an xmlrpc serverproxy where methods
+# can be sent as-is; it takes care of authentication
+# from the global config
+# 
+# so we inherit PlShell just so one can do driver.GetNodes
+# which would not make much sense in the context of other testbeds
+# so ultimately PlDriver should drop the PlShell inheritance
+# and would have a driver.shell reference to a PlShell instead
+# 
+class PlDriver (Driver, PlShell):
 
     def __init__ (self, config):
         PlShell.__init__ (self, config)
  
         self.hrn = config.SFA_INTERFACE_HRN
-        # xxx thgen fixme - use SfaTable hardwired for now 
-        # will need to extend generic to support multiple storage systems
-        #self.SfaTable = SfaTable
-        # Initialize the PLC shell only if SFA wraps a myPLC
-        rspec_type = config.get_aggregate_type()
-        assert (rspec_type == 'pl' or rspec_type == 'vini' or \
-                    rspec_type == 'eucalyptus' or rspec_type == 'max')
+
+    ########## disabled users 
+    def is_enabled (self, record):
+        # the incoming record was augmented already, so 'enabled' should be set
+        if record['type'] == 'user':
+            return record['enabled']
+        # only users can be disabled
+        return True
+
+    def augment_records_with_testbed_info (self, sfa_records):
+        return self.fill_record_info (sfa_records)
+
+    ########## 
+    def register (self, sfa_record, hrn, pub_key):
+        type = sfa_record['type']
+        pl_record = self.sfa_fields_to_pl_fields(type, hrn, sfa_record)
+
+        if type == 'authority':
+            sites = self.GetSites([pl_record['login_base']])
+            if not sites:
+                pointer = self.AddSite(pl_record)
+            else:
+                pointer = sites[0]['site_id']
+
+        elif type == 'slice':
+            acceptable_fields=['url', 'instantiation', 'name', 'description']
+            for key in pl_record.keys():
+                if key not in acceptable_fields:
+                    pl_record.pop(key)
+            slices = self.GetSlices([pl_record['name']])
+            if not slices:
+                 pointer = self.AddSlice(pl_record)
+            else:
+                 pointer = slices[0]['slice_id']
+
+        elif type == 'user':
+            persons = self.GetPersons([sfa_record['email']])
+            if not persons:
+                pointer = self.AddPerson(dict(sfa_record))
+            else:
+                pointer = persons[0]['person_id']
+    
+            if 'enabled' in sfa_record and sfa_record['enabled']:
+                self.UpdatePerson(pointer, {'enabled': sfa_record['enabled']})
+            # add this person to the site only if she is being added for the first
+            # time by sfa and doesont already exist in plc
+            if not persons or not persons[0]['site_ids']:
+                login_base = get_leaf(sfa_record['authority'])
+                self.AddPersonToSite(pointer, login_base)
+    
+            # What roles should this user have?
+            self.AddRoleToPerson('user', pointer)
+            # Add the user's key
+            if pub_key:
+                self.AddPersonKey(pointer, {'key_type' : 'ssh', 'key' : pub_key})
+
+        elif type == 'node':
+            login_base = hrn_to_pl_login_base(sfa_record['authority'])
+            nodes = api.driver.GetNodes([pl_record['hostname']])
+            if not nodes:
+                pointer = api.driver.AddNode(login_base, pl_record)
+            else:
+                pointer = nodes[0]['node_id']
+    
+        return pointer
+        
+    ##########
+    # xxx actually old_sfa_record comes filled with plc stuff as well in the original code
+    def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
+        pointer = old_sfa_record['pointer']
+        type = old_sfa_record['type']
+
+        # new_key implemented for users only
+        if new_key and type not in [ 'user' ]:
+            raise UnknownSfaType(type)
+
+        if (type == "authority"):
+            self.UpdateSite(pointer, new_sfa_record)
+    
+        elif type == "slice":
+            pl_record=self.sfa_fields_to_pl_fields(type, hrn, new_sfa_record)
+            if 'name' in pl_record:
+                pl_record.pop('name')
+                self.UpdateSlice(pointer, pl_record)
+    
+        elif type == "user":
+            # SMBAKER: UpdatePerson only allows a limited set of fields to be
+            #    updated. Ideally we should have a more generic way of doing
+            #    this. I copied the field names from UpdatePerson.py...
+            update_fields = {}
+            all_fields = new_sfa_record
+            for key in all_fields.keys():
+                if key in ['first_name', 'last_name', 'title', 'email',
+                           'password', 'phone', 'url', 'bio', 'accepted_aup',
+                           'enabled']:
+                    update_fields[key] = all_fields[key]
+            self.UpdatePerson(pointer, update_fields)
+    
+            if new_key:
+                # must check this key against the previous one if it exists
+                persons = self.GetPersons([pointer], ['key_ids'])
+                person = persons[0]
+                keys = person['key_ids']
+                keys = self.GetKeys(person['key_ids'])
+                
+                # Delete all stale keys
+                key_exists = False
+                for key in keys:
+                    if new_key != key['key']:
+                        self.DeleteKey(key['key_id'])
+                    else:
+                        key_exists = True
+                if not key_exists:
+                    self.AddPersonKey(pointer, {'key_type': 'ssh', 'key': new_key})
+    
+        elif type == "node":
+            self.UpdateNode(pointer, new_sfa_record)
+
+        return True
+        
+
+    ##########
+    def remove (self, sfa_record):
+        type=sfa_record['type']
+        pointer=sfa_record['pointer']
+        if type == 'user':
+            persons = self.GetPersons(pointer)
+            # only delete this person if he has site ids. if he doesnt, it probably means
+            # he was just removed from a site, not actually deleted
+            if persons and persons[0]['site_ids']:
+                self.DeletePerson(pointer)
+        elif type == 'slice':
+            if self.GetSlices(pointer):
+                self.DeleteSlice(pointer)
+        elif type == 'node':
+            if self.GetNodes(pointer):
+                self.DeleteNode(pointer)
+        elif type == 'authority':
+            if self.GetSites(pointer):
+                self.DeleteSite(pointer)
+
+        return True
+
+
+
+
 
     ##
     # Convert SFA fields to PLC fields for use when registering up updating
     # registry record in the PLC database
     #
-    # @param type type of record (user, slice, ...)
-    # @param hrn human readable name
-    # @param sfa_fields dictionary of SFA fields
-    # @param pl_fields dictionary of PLC fields (output)
 
-    def sfa_fields_to_pl_fields(self, type, hrn, record):
-
-        def convert_ints(tmpdict, int_fields):
-            for field in int_fields:
-                if field in tmpdict:
-                    tmpdict[field] = int(tmpdict[field])
+    def sfa_fields_to_pl_fields(self, type, hrn, sfa_record):
 
         pl_record = {}
-        #for field in record:
-        #    pl_record[field] = record[field]
  
         if type == "slice":
-            if not "instantiation" in pl_record:
-                pl_record["instantiation"] = "plc-instantiated"
             pl_record["name"] = hrn_to_pl_slicename(hrn)
-           if "url" in record:
-               pl_record["url"] = record["url"]
-           if "description" in record:
-               pl_record["description"] = record["description"]
-           if "expires" in record:
-               pl_record["expires"] = int(record["expires"])
+            if "instantiation" in sfa_record:
+                pl_record['instantiation']=sfa_record['instantiation']
+            else:
+                pl_record["instantiation"] = "plc-instantiated"
+           if "url" in sfa_record:
+               pl_record["url"] = sfa_record["url"]
+           if "description" in sfa_record:
+               pl_record["description"] = sfa_record["description"]
+           if "expires" in sfa_record:
+               pl_record["expires"] = int(sfa_record["expires"])
 
         elif type == "node":
             if not "hostname" in pl_record:
-                if not "hostname" in record:
+                # fetch from sfa_record
+                if "hostname" not in sfa_record:
                     raise MissingSfaInfo("hostname")
-                pl_record["hostname"] = record["hostname"]
-            if not "model" in pl_record:
+                pl_record["hostname"] = sfa_record["hostname"]
+            if "model" in sfa_record: 
+                pl_record["model"] = sfa_record["model"]
+            else:
                 pl_record["model"] = "geni"
 
         elif type == "authority":
             pl_record["login_base"] = hrn_to_pl_login_base(hrn)
-
-            if not "name" in pl_record:
+            if "name" not in sfa_record:
                 pl_record["name"] = hrn
-
-            if not "abbreviated_name" in pl_record:
+            if "abbreviated_name" not in sfa_record:
                 pl_record["abbreviated_name"] = hrn
-
-            if not "enabled" in pl_record:
+            if "enabled" not in sfa_record:
                 pl_record["enabled"] = True
-
-            if not "is_public" in pl_record:
+            if "is_public" not in sfa_record:
                 pl_record["is_public"] = True
 
         return pl_record
 
+    ####################
+    def fill_record_info(self, records):
+        """
+        Given a (list of) SFA record, fill in the PLC specific 
+        and SFA specific fields in the record. 
+        """
+        if not isinstance(records, list):
+            records = [records]
+
+        self.fill_record_pl_info(records)
+        self.fill_record_hrns(records)
+        self.fill_record_sfa_info(records)
+        return records
+
     def fill_record_pl_info(self, records):
         """
         Fill in the planetlab specific fields of a SFA record. This
         involves calling the appropriate PLC method to retrieve the 
         database record for the object.
-        
-        PLC data is filled into the pl_info field of the record.
-    
+            
         @param record: record to fill in field (in/out param)     
         """
         # get ids by type
@@ -153,9 +307,6 @@ class PlDriver (PlShell):
                     pubkeys = [keys[key_id]['key'] for key_id in record['key_ids'] if key_id in keys] 
                     record['keys'] = pubkeys
 
-        # fill in record hrns
-        records = self.fill_record_hrns(records)   
         return records
 
     def fill_record_hrns(self, records):
@@ -231,7 +382,7 @@ class PlDriver (PlShell):
         return records   
 
     # aggregates is basically api.aggregates
-    def fill_record_sfa_info(self, records, aggregates):
+    def fill_record_sfa_info(self, records):
 
         def startswith(prefix, values):
             return [value for value in values if value.startswith(prefix)]
@@ -268,13 +419,11 @@ class PlDriver (PlShell):
         # we obtain
         
         # get the sfa records
-        # xxx thgen fixme - use SfaTable hardwired for now 
-        # table = self.SfaTable()
         table = SfaTable()
         person_list, persons = [], {}
         person_list = table.find({'type': 'user', 'pointer': person_ids})
         # create a hrns keyed on the sfa record's pointer.
-        # Its possible for  multiple records to have the same pointer so
+        # Its possible for multiple records to have the same pointer so
         # the dict's value will be a list of hrns.
         persons = defaultdict(list)
         for person in person_list:
@@ -312,10 +461,6 @@ class PlDriver (PlShell):
                 
             elif (type.startswith("authority")):
                 record['url'] = None
-                if record['hrn'] in aggregates:
-                    
-                    record['url'] = aggregates[record['hrn']].get_url()
-
                 if record['pointer'] != -1:
                     record['PI'] = []
                     record['operator'] = []
@@ -344,64 +489,24 @@ class PlDriver (PlShell):
                 # xxx TODO: PostalAddress, Phone
             record.update(sfa_info)
 
-    def fill_record_info(self, records, aggregates):
-        """
-        Given a SFA record, fill in the PLC specific and SFA specific
-        fields in the record. 
-        """
-        if not isinstance(records, list):
-            records = [records]
 
-        self.fill_record_pl_info(records)
-        self.fill_record_sfa_info(records, aggregates)
-
-    def update_membership_list(self, oldRecord, record, listName, addFunc, delFunc):
-        # get a list of the HRNs that are members of the old and new records
-        if oldRecord:
-            oldList = oldRecord.get(listName, [])
-        else:
-            oldList = []     
-        newList = record.get(listName, [])
-
-        # if the lists are the same, then we don't have to update anything
-        if (oldList == newList):
-            return
-
-        # build a list of the new person ids, by looking up each person to get
-        # their pointer
-        newIdList = []
-        # xxx thgen fixme - use SfaTable hardwired for now 
-        #table = self.SfaTable()
-        table = SfaTable()
-        records = table.find({'type': 'user', 'hrn': newList})
-        for rec in records:
-            newIdList.append(rec['pointer'])
-
-        # build a list of the old person ids from the person_ids field 
-        if oldRecord:
-            oldIdList = oldRecord.get("person_ids", [])
-            containerId = oldRecord.get_pointer()
+    ####################
+    # plcapi works by changes, compute what needs to be added/deleted
+    def update_relation (self, subject_type, target_type, subject_id, target_ids):
+        # hard-wire the code for slice/user for now, could be smarter if needed
+        if subject_type =='slice' and target_type == 'user':
+            subject=self.GetSlices (subject_id)[0]
+            current_target_ids = subject['person_ids']
+            add_target_ids = list ( set (target_ids).difference(current_target_ids))
+            del_target_ids = list ( set (current_target_ids).difference(target_ids))
+            logger.info ("subject_id = %s (type=%s)"%(subject_id,type(subject_id)))
+            for target_id in add_target_ids:
+                self.AddPersonToSlice (target_id,subject_id)
+                logger.info ("add_target_id = %s (type=%s)"%(target_id,type(target_id)))
+            for target_id in del_target_ids:
+                logger.info ("del_target_id = %s (type=%s)"%(target_id,type(target_id)))
+                self.DeletePersonFromSlice (target_id, subject_id)
         else:
-            # if oldRecord==None, then we are doing a Register, instead of an
-            # update.
-            oldIdList = []
-            containerId = record.get_pointer()
-
-    # add people who are in the new list, but not the oldList
-        for personId in newIdList:
-            if not (personId in oldIdList):
-                addFunc(personId, containerId)
-
-        # remove people who are in the old list, but not the new list
-        for personId in oldIdList:
-            if not (personId in newIdList):
-                delFunc(personId, containerId)
-
-    def update_membership(self, oldRecord, record):
-        if record.type == "slice":
-            self.update_membership_list(oldRecord, record, 'researcher',
-                                        self.AddPersonToSlice,
-                                        self.DeletePersonFromSlice)
-        elif record.type == "authority":
-            # xxx TODO
-            pass
+            logger.info('unexpected relation to maintain, %s -> %s'%(subject_type,target_type))
+
+        
index 972a97e..eaa772a 100644 (file)
@@ -1,4 +1,9 @@
+import sys
 import xmlrpclib
+import socket
+from urlparse import urlparse
+
+from sfa.util.sfalogging import logger
 
 class PlShell:
     """
@@ -24,16 +29,43 @@ class PlShell:
                     'get_nodes':'GetNodes',
                     }
 
+
+    # use the 'capability' auth mechanism for higher performance when the PLC db is local    
     def __init__ ( self, config ) :
-        self.plauth = {'Username': config.SFA_PLC_USER,
-                       'AuthMethod': 'password',
-                       'AuthString': config.SFA_PLC_PASSWORD}
-        
-        self.url = config.SFA_PLC_URL
-        #self.plauth = {'Username': 'root@test.onelab.eu',
-        #               'AuthMethod': 'password',
-        #               'AuthString': 'test++'}
-        self.proxy_server = xmlrpclib.Server(self.url, verbose = 0, allow_none = True)
+        url = config.SFA_PLC_URL
+        # try to figure if the url is local
+        hostname=urlparse(url).hostname
+        is_local=False
+        if hostname == 'localhost': is_local=True
+        # otherwise compare IP addresses
+        url_ip=socket.gethostbyname(hostname)
+        local_ip=socket.gethostbyname(socket.gethostname())
+        if url_ip==local_ip: is_local=True
+
+        if is_local:
+            try:
+                # too bad this is not installed properly
+                plcapi_path="/usr/share/plc_api"
+                if plcapi_path not in sys.path: sys.path.append(plcapi_path)
+                import PLC.Shell
+                plc_direct_access=True
+            except:
+                plc_direct_access=False
+        if is_local and plc_direct_access:
+            logger.debug('plshell access - capability')
+            self.plauth = { 'AuthMethod': 'capability',
+                            'Username':   config.SFA_PLC_USER,
+                            'AuthString': config.SFA_PLC_PASSWORD,
+                            }
+            self.proxy = PLC.Shell.Shell ()
+
+        else:
+            logger.debug('plshell access - xmlrpc')
+            self.plauth = { 'AuthMethod': 'password',
+                            'Username':   config.SFA_PLC_USER,
+                            'AuthString': config.SFA_PLC_PASSWORD,
+                            }
+            self.proxy = xmlrpclib.Server(url, verbose = 0, allow_none = True)
 
     def __getattr__(self, name):
         def func(*args, **kwds):
@@ -42,5 +74,7 @@ class PlShell:
             if name in PlShell.alias_calls: actual_name=PlShell.alias_calls[name]
             if not actual_name:
                 raise Exception, "Illegal method call %s for PL driver"%(name)
-            return getattr(self.proxy_server, actual_name)(self.plauth, *args, **kwds)
+            result=getattr(self.proxy, actual_name)(self.plauth, *args, **kwds)
+            logger.debug('%s (%s) returned ... %s'%(name,actual_name,result))
+            return result
         return func
diff --git a/sfa/plc/remoteshell.py b/sfa/plc/remoteshell.py
deleted file mode 100644 (file)
index 9deceb6..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-# remoteshell.py
-#
-# interface to the PLC api via xmlrpc
-#
-# RemoteShell() exports an API that looks identical to that exported by
-# PLC.Shell.Shell(). It's meant to be a drop in replacement for running
-# SFA on a different machine than PLC.
-
-import xmlrpclib
-
-class RemoteShell:
-    def __init__(self,logger):
-        self.servers = {}
-        self.logger=logger
-
-    def call(self, name, pl_auth, *args):
-
-        key = pl_auth["Url"] + "#" + pl_auth["Username"]
-
-        if not (key in self.servers):
-            self.logger.info("Connecting to PLCAPI at url %s"%pl_auth['Url'])
-            server = xmlrpclib.Server(pl_auth["Url"], verbose = 0, allow_none=True)
-            #server.AdmAuthCheck(pl_auth)
-            server.AuthCheck(pl_auth)
-            self.servers[key] = server
-
-        server = self.servers[key]
-
-        arglist = ["pl_auth"]
-        for arg in args:
-            arglist.append(repr(arg))
-
-        str = "server." + name + "(" + ",".join(arglist) + ")"
-        result = eval(str)
-
-        return result
-
-    # TODO: there's probably an automatic way to import all these stubs
-
-    def AddInitScript(self, pl_auth, *args):
-        return self.call("AddInitScript", pl_auth, *args)
-
-    def AddNode(self, pl_auth, *args):
-        return self.call("AddNode", pl_auth, *args)
-
-    def AddPerson(self, pl_auth, *args):
-        return self.call("AddPerson", pl_auth, *args)
-
-    def AddPersonToSlice(self, pl_auth, *args):
-        return self.call("AddPersonToSlice", pl_auth, *args)
-
-    def AddSite(self, pl_auth, *args):
-        return self.call("AddSite", pl_auth, *args)
-
-    def AddSlice(self, pl_auth, *args):
-        return self.call("AddSlice", pl_auth, *args)
-
-    def DeleteNode(self, pl_auth, *args):
-        return self.call("DeleteNode", pl_auth, *args)
-
-    def DeletePerson(self, pl_auth, *args):
-        return self.call("DeletePerson", pl_auth, *args)
-
-    def DeletePersonFromSlice(self, pl_auth, *args):
-        return self.call("DeletePersonFromSlice", pl_auth, *args)
-
-    def DeleteSite(self, pl_auth, *args):
-        return self.call("DeleteSite", pl_auth, *args)
-
-    def DeleteSlice(self, pl_auth, *args):
-        return self.call("DeleteSlice", pl_auth, *args)
-
-    def GetInitScripts(self, pl_auth, *args):
-        return self.call("GetInitScripts", pl_auth, *args)
-
-    def GetKeys(self, pl_auth, *args):
-        return self.call("GetKeys", pl_auth, *args)
-
-    def GetNodes(self, pl_auth, *args):
-        return self.call("GetNodes", pl_auth, *args)
-
-    def GetPersons(self, pl_auth, *args):
-        return self.call("GetPersons", pl_auth, *args)
-
-    def GetSites(self, pl_auth, *args):
-        return self.call("GetSites", pl_auth, *args)
-
-    def GetSliceAttributes(self, pl_auth, *args):
-        return self.call("GetSliceAttributes", pl_auth, *args)
-
-    def GetSlices(self, pl_auth, *args):
-        return self.call("GetSlices", pl_auth, *args)
-
-    def UpdateNode(self, pl_auth, *args):
-        return self.call("UpdateNode", pl_auth, *args)
-
-    def UpdatePerson(self, pl_auth, *args):
-        return self.call("UpdatePerson", pl_auth, *args)
-
-    def UpdateSite(self, pl_auth, *args):
-        return self.call("UpdateSite", pl_auth, *args)
-
-    def UpdateSlice(self, pl_auth, *args):
-        return self.call("UpdateSlice", pl_auth, *args)
-
-
index 8e311b7..4e38729 100644 (file)
@@ -24,7 +24,7 @@ class BaseVersion:
             'extensions': self.extensions
         }
 
-    def to_string(self):
+    def __str__(self):
         return "%s %s" % (self.type, self.version)
     
 
index 65513d0..44317be 100644 (file)
@@ -15,15 +15,16 @@ class PGv2Link:
             if 'component_manager' in link and link['component_manager']:
                 cm_element = link_elem.add_element('component_manager', name=link['component_manager'])
             # set interface_ref elements
-            for if_ref in [link['interface1'], link['interface2']]:
-                link_elem.add_instance('interface_ref', if_ref, Interface.fields)
-            # set property elements
-            prop1 = link_elem.add_element('property', source_id = link['interface1']['component_id'],
-                dest_id = link['interface2']['component_id'], capacity=link['capacity'], 
-                latency=link['latency'], packet_loss=link['packet_loss'])
-            prop2 = link_elem.add_element('property', source_id = link['interface2']['component_id'],
-                dest_id = link['interface1']['component_id'], capacity=link['capacity'], 
-                latency=link['latency'], packet_loss=link['packet_loss'])
+            if link.get('interface1') and link.get('interface2'):
+                for if_ref in [link['interface1'], link['interface2']]:
+                    link_elem.add_instance('interface_ref', if_ref, Interface.fields)
+                # set property elements
+                prop1 = link_elem.add_element('property', source_id = link['interface1']['component_id'],
+                    dest_id = link['interface2']['component_id'], capacity=link['capacity'], 
+                    latency=link['latency'], packet_loss=link['packet_loss'])
+                prop2 = link_elem.add_element('property', source_id = link['interface2']['component_id'],
+                    dest_id = link['interface1']['component_id'], capacity=link['capacity'], 
+                    latency=link['latency'], packet_loss=link['packet_loss'])
             if link.get('type'):
                 type_elem = link_elem.add_element('link_type', name=link['type'])            
  
index eb0518f..c37275a 100644 (file)
@@ -25,16 +25,18 @@ class PGv2Node:
                 component_name = xrn_to_hostname(node['component_id'])
                 node_elem.set('component_name', component_name)
             # set hardware types
-            for hardware_type in node.get('hardware_types', []): 
-                node_elem.add_instance('hardware_type', hardware_type, HardwareType.fields)
+            if node.get('hardware_types'):
+                for hardware_type in node.get('hardware_types', []): 
+                    node_elem.add_instance('hardware_type', hardware_type, HardwareType.fields)
             # set location
             if node.get('location'):
                 node_elem.add_instance('location', node['location'], Location.fields)       
             # set interfaces
-            for interface in  node.get('interfaces', []):
-                node_elem.add_instance('interface', interface, ['component_id', 'client_id', 'ipv4'])
+            if node.get('interfaces'):
+                for interface in  node.get('interfaces', []):
+                    node_elem.add_instance('interface', interface, ['component_id', 'client_id', 'ipv4'])
             # set available element
-            if node.get('boot_state', '').lower() == 'boot':
+            if node.get('boot_state') and node.get('boot_state').lower() == 'boot':
                 available_elem = node_elem.add_element('available', now='True')
             else:
                 available_elem = node_elem.add_element('available', now='False')
@@ -47,8 +49,9 @@ class PGv2Node:
                 slivers = Sliver({'type': 'plab-vserver'})
                 # we must also advertise the available initscripts
                 slivers['tags'] = []
-                for initscript in node.get('pl_initscripts', []):
-                    slivers['tags'].append({'name': 'initscript', 'value': initscript['name']})
+                if node.get('pl_initscripts'): 
+                    for initscript in node.get('pl_initscripts', []):
+                        slivers['tags'].append({'name': 'initscript', 'value': initscript['name']})
             PGv2SliverType.add_slivers(node_elem, slivers)
         
         return node_elems
index 7cffc91..be1d618 100644 (file)
@@ -1,6 +1,7 @@
 from sfa.rspecs.elements.element import Element  
 from sfa.rspecs.elements.execute import Execute  
 from sfa.rspecs.elements.install import Install  
+from sfa.rspecs.elements.services import Services  
 from sfa.rspecs.elements.login import Login
 
 class PGv2Services:
index 26d41a9..753192d 100644 (file)
@@ -62,9 +62,11 @@ class SFAv1Node:
             #    bw_unallocated = etree.SubElement(node_elem, 'bw_unallocated', units='kbps').text = str(int(node['bw_unallocated'])/1000)
 
             PGv2Services.add_services(node_elem, node.get('services', []))
-            for tag in node.get('tags', []):
-                tag_elem = node_elem.add_element(tag['tagname'])
-                tag_elem.set_text(tag['value'])
+            tags = node.get('tags', [])
+            if tags:
+                for tag in tags:
+                    tag_elem = node_elem.add_element(tag['tagname'])
+                    tag_elem.set_text(tag['value'])
             SFAv1Sliver.add_slivers(node_elem, node.get('slivers', []))
 
     @staticmethod 
@@ -90,7 +92,7 @@ class SFAv1Node:
         for hostname in hostnames:
             nodes = SFAv1Node.get_nodes(xml, {'component_id': '*%s*' % hostname})
             for node in nodes:
-                slivers = SFAv1Slivers.get_slivers(node.element)
+                slivers = SFAv1Sliver.get_slivers(node.element)
                 for sliver in slivers:
                     node.element.remove(sliver.element)
         
@@ -135,9 +137,11 @@ class SFAv1Node:
             # get tags
             node['tags'] =  SFAv1PLTag.get_pl_tags(node_elem, ignore=Node.fields)
 
-            parent = node_elem.getparent()
-            if (parent != None) and (parent.tag=="network") and ("name" in parent.attrib):
-                node['network_name'] = parent.attrib['name']
+            # temporary... play nice with old slice manager rspec
+            if not node['component_name']:
+                hostname_elem = node_elem.find("hostname")
+                if hostname_elem != None:
+                    node['component_name'] = hostname_elem.text
 
             nodes.append(node)
         return nodes            
index d1519e9..207a4a7 100644 (file)
@@ -14,8 +14,10 @@ class SFAv1Sliver:
             slivers = [slivers]
         for sliver in slivers:
             sliver_elem = xml.add_instance('sliver', sliver, ['name'])
-            for tag in sliver.get('tags', []):
-                SFAv1Sliver.add_sliver_attribute(sliver_elem, tag['tagname'], tag['value'])
+            tags = sliver.get('tags', [])
+            if tags:
+                for tag in tags:
+                    SFAv1Sliver.add_sliver_attribute(sliver_elem, tag['tagname'], tag['value'])
             if sliver.get('sliver_id'):
                 sliver_id_leaf = Xrn(sliver.get('sliver_id')).get_leaf()
                 sliver_id_parts = sliver_id_leaf.split(':')
index 1c57d7d..5cccf97 100755 (executable)
@@ -44,10 +44,15 @@ class PGRSpecConverter:
         sfa_version = version_manager._get_version('sfa', '1')    
         sfa_rspec = RSpec(version=sfa_version)
 
+        #nodes = pg_rspec.version.get_nodes()
+        #sfa_rspec.version.add_nodes(nodes())
+        #sfa_rspec.version.add_links(pg_rspec.version.get_links())
+        #return sfa_rspec.toxml() 
+
         # get network
-        network_urn = pg_rspec.version.get_network()
-        network,  _ = urn_to_hrn(network_urn)
-        network_element = sfa_rspec.xml.add_element('network', {'name': network, 'id': network})
+        networks = pg_rspec.version.get_networks()
+        network_hrn = networks[0]
+        network_element = sfa_rspec.xml.add_element('network', name=network_hrn, id=network_hrn)
         
         # get nodes
         pg_nodes_elements = pg_rspec.version.get_node_elements()
@@ -57,18 +62,18 @@ class PGRSpecConverter:
             attribs = dict(pg_node_element.attrib.items()) 
             attribs['id'] = 'n'+str(i)
             
-            node_element = sfa_rspec.xml.add_element('node', attribs, parent=network_element)
+            node_element = network_element.add_element('node')
+            for attrib in attribs:
+                node_element.set(attrib, attribs[attrib])
             urn = pg_node_element.xpath('@component_id', namespaces=pg_rspec.namespaces)
             if urn:
                 urn = urn[0]
                 hostname = Xrn.urn_split(urn)[-1]
-                hostname_element = sfa_rspec.xml.add_element('hostname', parent=node_element, text=hostname)
+                hostname_element = node_element.add_element('hostname')
+                hostname_element.set_text(hostname)
                 if hostname in nodes_with_slivers:
-                    sfa_rspec.xml.add_element('sliver', parent=node_element)
+                    node_element.add_element('sliver')  
                      
-            urn_element = sfa_rspec.xml.add_element('urn', parent=node_element, text=urn)
-
-
             # just copy over remaining child elements  
             for child in pg_node_element.getchildren():
                 node_element.append(transform(child).getroot())
index a04ff28..00095e2 100755 (executable)
@@ -46,8 +46,8 @@ class RSpec:
         else:
             #raise InvalidRSpec('unknown rspec schema: %s' % schema)
             # TODO: Should start raising an exception once SFA defines a schema.
-            # for now we just use the default  
-            self.version = self.version_manager.get_version()
+            # for now we just  default to sfa 
+            self.version = self.version_manager.get_version({'type':'sfa','version': '1'})
         self.version.xml = self.xml    
         self.namespaces = self.xml.namespaces
     
index 27eba93..d59986f 100644 (file)
@@ -1,12 +1,9 @@
 import os
-from sfa.util.faults import InvalidRSpec
+from sfa.util.faults import InvalidRSpec, UnsupportedRSpecVersion
 from sfa.rspecs.baseversion import BaseVersion 
 from sfa.util.sfalogging import logger    
 
 class VersionManager:
-    default_type = 'SFA'
-    default_version_num = '1'     
-        
     def __init__(self):
         self.versions = []
         self.load_versions()
@@ -31,12 +28,12 @@ class VersionManager:
         retval = None
         for version in self.versions:
             if type is None or type.lower() == version.type.lower():
-                if version_num is None or version_num == version.version:
+                if version_num is None or str(version_num) == version.version:
                     if content_type is None or content_type.lower() == version.content_type.lower() \
                       or version.content_type == '*':
                         retval = version
         if not retval:
-            raise InvalidRSpec("No such version format: %s version: %s type:%s "% (type, version_num, content_type))
+            raise UnvalidRSpecVersion("%s %s is not suported here"% (type, version_num, content_type))
         return retval
 
     def get_version(self, version=None):
@@ -57,7 +54,7 @@ class VersionManager:
         elif isinstance(version, BaseVersion):
             retval = version
         else:
-            retval = self._get_version(self.default_type, self.default_version_num)   
+            raise InvalidRSpecVersion("No such version: %s "% str(version))
  
         return retval
 
index 60387dc..b52b5f0 100644 (file)
@@ -19,16 +19,22 @@ class PGv2(BaseVersion):
     }
     namespaces = dict(extensions.items() + [('default', namespace)])
 
-    # Networks    
+    # Networks
     def get_networks(self):
-        networks = set()
-        nodes = self.xml.xpath('//default:node[@component_manager_id]', namespaces=self.namespaces)
-        for node in nodes: 
-            if 'component_manager_id' in node:
-                network_urn  = node.get('component_manager_id')
-                network_hrn = Xrn(network_urn).get_hrn()[0]
-                networks.add({'name': network_hrn})
-        return list(networks)
+        network_names = set()
+        nodes = self.xml.xpath('//default:node[@component_manager_id] | //node[@component_manager_id]', namespaces=self.namespaces)
+        for node in nodes:
+            if 'component_manager_id' in node.attrib:
+                network_urn = node.get('component_manager_id')
+                if network_urn.startswith("urn:"):
+                    network_hrn = Xrn(network_urn).get_hrn()[0]
+                else:
+                    # some component_manager_ids are hrns instead of urns??
+                    network_hrn = network_urn
+                network_names.add(network_hrn)
+        network_names = list(network_names)
+        networks = [{"name": x} for x in network_names]
+        return networks
 
     # Nodes
 
@@ -167,12 +173,24 @@ class PGv2(BaseVersion):
         """
         from sfa.rspecs.rspec import RSpec
         # just copy over all the child elements under the root element
-        if isinstance(in_rspec, RSpec):
-            in_rspec = in_rspec.toxml()
+        if isinstance(in_rspec, basestring):
+            in_rspec = RSpec(in_rspec)
+
+        nodes = in_rspec.version.get_nodes()
+        # protogeni rspecs need to advertise the availabel sliver types
+        for node in nodes:
+            if not node.has_key('sliver') or not node['sliver']:
+                node['sliver'] = {'name': 'plab-vserver'}
+            
+        self.add_nodes(nodes)
+        self.add_links(in_rspec.version.get_links())
+        
+        #
+        #rspec = RSpec(in_rspec)
+        #for child in rspec.xml.iterchildren():
+        #    self.xml.root.append(child)
+        
         
-        rspec = RSpec(in_rspec)
-        for child in rspec.xml.iterchildren():
-            self.xml.root.append(child)
 
     def cleanup(self):
         # remove unncecessary elements, attributes
index d954f62..affab84 100644 (file)
@@ -142,7 +142,7 @@ class SFAv1(BaseVersion):
             defaults = network_tag.add_element('sliver_defaults')
         elif isinstance(defaults, list):
             defaults = defaults[0]
-        Sfav1Sliver.add_sliver_attribute(defaults, name, value)
+        SFAv1Sliver.add_sliver_attribute(defaults, name, value)
 
     def get_default_sliver_attributes(self, network=None):
         if network:
@@ -150,14 +150,14 @@ class SFAv1(BaseVersion):
         else:
             defaults = self.xml.xpath("//sliver_defaults")
         if not defaults: return []
-        return Sfav1Sliver.get_sliver_attributes(defaults)
+        return SFAv1Sliver.get_sliver_attributes(defaults[0])
     
     def remove_default_sliver_attribute(self, name, value, network=None):
         if network:
             defaults = self.xml.xpath("//network[@name='%s']/sliver_defaults" % network)
         else:
             defaults = self.xml.xpath("//sliver_defaults" % network)
-        attribs = Sfav1Sliver.get_sliver_attributes(defaults)
+        attribs = SFAv1Sliver.get_sliver_attributes(defaults)
         for attrib in attribs:
             if attrib['name'] == name and attrib['value'] == value:
                 attrib.element.delete()    
index 0fbe140..b87e119 100755 (executable)
@@ -23,11 +23,12 @@ import sys
 from optparse import OptionParser
 
 from sfa.util.config import Config
-from sfa.util.table import SfaTable
 
 from sfa.trust.gid import GID, create_uuid
 from sfa.trust.hierarchy import Hierarchy
 
+from sfa.storage.table import SfaTable
+
 def main():
     args = sys.argv
     script_name = args[0]
index 0d99e98..62acb4b 100644 (file)
@@ -5,17 +5,19 @@ import os
 import traceback
 import socket
 
-import sfa.client.xmlrpcprotocol as xmlrpcprotocol 
-from sfa.util.table import SfaTable
 from sfa.util.prefixTree import prefixTree
 from sfa.util.config import Config
 
-from sfa.generic import Generic
-
 from sfa.trust.certificate import Keypair
 from sfa.trust.hierarchy import Hierarchy
 from sfa.server.registry import Registries
 
+from sfa.storage.table import SfaTable
+
+import sfa.client.xmlrpcprotocol as xmlrpcprotocol 
+
+from sfa.generic import Generic
+
 def main():
     config = Config()
     if not config.SFA_REGISTRY_ENABLED:
index dbd5e4f..6c05060 100755 (executable)
@@ -136,8 +136,8 @@ def update_cert_records(gids):
     Removes old records from the db.
     """
     # import SfaTable here so this module can be loaded by PlcComponentApi
-    from sfa.util.table import SfaTable
-    from sfa.util.record import SfaRecord
+    from sfa.storage.table import SfaTable
+    from sfa.storage.record import SfaRecord
     if not gids:
         return
     table = SfaTable()
index ed1ee30..3775391 100755 (executable)
@@ -98,7 +98,7 @@ def get_node_key(registry=None, verbose=False):
     cert.save_to_file(certfile)
     
     registry = server_proxy(url = registry, keyfile=keyfile, certfile=certfile)    
-    registry.get_key()
+    registry.get_key_from_incoming_ip()
 
 def create_server_keypair(keyfile=None, certfile=None, hrn="component", verbose=False):
     """
index 845ccff..79a5540 100644 (file)
@@ -1,18 +1,22 @@
 import os, os.path
 import datetime
 
-from sfa.util.faults import SfaAPIError
+from sfa.util.faults import SfaFault, SfaAPIError
+from sfa.util.genicode import GENICODE
 from sfa.util.config import Config
 from sfa.util.cache import Cache
 from sfa.trust.auth import Auth
+
 from sfa.trust.certificate import Keypair, Certificate
 from sfa.trust.credential import Credential
 from sfa.trust.rights import determine_rights
+
 from sfa.server.xmlrpcapi import XmlrpcApi
-from sfa.util.genicode import GENICODE
+
+from sfa.client.return_value import ReturnValue
 
 # thgen xxx fixme this is wrong all right, but temporary, will use generic
-from sfa.util.table import SfaTable
+from sfa.storage.table import SfaTable
 
 ####################
 class SfaApi (XmlrpcApi): 
@@ -201,7 +205,8 @@ class SfaApi (XmlrpcApi):
         if self.cache:
             server_version = self.cache.get(cache_key)
         if not server_version:
-            server_version = server.GetVersion()
+            result = server.GetVersion()
+            server_version = ReturnValue.get_value(result)
             # cache version for 24 hours
             self.cache.add(cache_key, server_version, ttl= 60*60*24)
         return server_version
@@ -213,7 +218,7 @@ class SfaApi (XmlrpcApi):
             'am_type': 'sfa',
             'am_code': None,
         }
-        if isinstnace(result, SfaFault):
+        if isinstance(result, SfaFault):
             code['geni_code'] = result.faultCode
             code['am_code'] = result.faultCode                        
                 
@@ -227,7 +232,7 @@ class SfaApi (XmlrpcApi):
 
     def get_geni_output(self, result):
         output = ""
-        if isinstance(result, SFaFault):
+        if isinstance(result, SfaFault):
             output = result.faultString 
         return output
 
@@ -244,9 +249,9 @@ class SfaApi (XmlrpcApi):
         Converts the specified result into a standard GENI compliant 
         response  
         """
-        if self.interface.lower() == 'aggregate'
+        if self.interface.lower() in ['aggregate', 'slicemgr']
             if hasattr(self.config, 'SFA_AGGREGATE_API_VERSION') and \
-              self.config.SFA_AGGREGATE_API_VERSION == "2":
+              self.config.SFA_AGGREGATE_API_VERSION == 2:
                 result = self.prepare_response_v2_am(result)
         return XmlrpcApi.prepare_response(self, result, method)
 
index f182ee0..b6f8e95 100644 (file)
@@ -111,6 +111,7 @@ class XmlrpcApi:
             callablemethod = getattr(module, classname)(self)
             return getattr(module, classname)(self)
         except (ImportError, AttributeError):
+            self.logger.log_exc("Error importing method: %s" % method)
             raise SfaInvalidAPIMethod, method
 
     def call(self, source, method, *args):
diff --git a/sfa/storage/__init__.py b/sfa/storage/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
similarity index 98%
rename from sfa/util/filter.py
rename to sfa/storage/filter.py
index 8f037ca..afe425d 100644 (file)
@@ -1,16 +1,9 @@
 from types import StringTypes
-try:
-    set
-except NameError:
-    from sets import Set
-    set = Set
-
-try: import pgdb
-except: pass
+import pgdb
  
 from sfa.util.faults import SfaInvalidArgument
-from sfa.util.parameter import Parameter, Mixed, python_type
 
+from sfa.storage.parameter import Parameter, Mixed, python_type
 
 class Filter(Parameter, dict):
     """
similarity index 99%
rename from sfa/util/record.py
rename to sfa/storage/record.py
index 7ebf379..46c6699 100644 (file)
@@ -8,9 +8,9 @@ from types import StringTypes
 
 from sfa.trust.gid import GID
 
-from sfa.util.parameter import Parameter
+from sfa.storage.parameter import Parameter
 from sfa.util.xrn import get_authority
-from sfa.util.row import Row
+from sfa.storage.row import Row
 from sfa.util.xml import XML 
 
 class SfaRecord(Row):
similarity index 100%
rename from sfa/util/row.py
rename to sfa/storage/row.py
diff --git a/sfa/storage/sfa.sql b/sfa/storage/sfa.sql
new file mode 100644 (file)
index 0000000..3d7984d
--- /dev/null
@@ -0,0 +1,55 @@
+--
+-- SFA database schema
+--
+
+SET client_encoding = 'UNICODE';
+
+--------------------------------------------------------------------------------
+-- Version
+--------------------------------------------------------------------------------
+
+-- Database version
+CREATE TABLE sfa_db_version (
+    version integer NOT NULL,
+    subversion integer NOT NULL DEFAULT 0
+) WITH OIDS;
+
+-- the migration scripts do not use the major 'version' number
+-- so 5.0 sets subversion at 100
+-- in case your database misses the site and persons tags feature, 
+-- you might wish to first upgrade to 4.3-rc16 before moving to some 5.0
+-- or run the up script here
+-- http://svn.planet-lab.org/svn/PLCAPI/branches/4.3/migrations/
+
+INSERT INTO sfa_db_version (version, subversion) VALUES (1, 1);
+
+--------------------------------------------------------------------------------
+-- Aggregates and store procedures
+--------------------------------------------------------------------------------
+
+-- Like MySQL GROUP_CONCAT(), this function aggregates values into a
+-- PostgreSQL array.
+CREATE AGGREGATE array_accum (
+    sfunc = array_append,
+    basetype = anyelement,
+    stype = anyarray,
+    initcond = '{}'
+);
+
+-- main table 
+CREATE TABLE sfa ( 
+    record_id serial PRIMARY KEY , 
+    hrn text NOT NULL, 
+    authority text NOT NULL, 
+    peer_authority text, 
+    gid text, 
+    type text NOT NULL, 
+    pointer integer, 
+    date_created timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, 
+    last_updated timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+CREATE INDEX sfa_hrn_ids on sfa (hrn);
+CREATE INDEX sfa_type_ids on sfa (type);
+CREATE INDEX sfa_authority_ids on sfa (authority);
+CREATE INDEX sfa_peer_authority_ids on sfa (peer_authority);
+CREATE INDEX sfa_pointer_ids on sfa (pointer);
similarity index 81%
rename from sfa/util/table.py
rename to sfa/storage/table.py
index 065e8ab..3e47f3e 100644 (file)
@@ -6,10 +6,11 @@
 from types import StringTypes
 
 from sfa.util.config import Config
-from sfa.util.parameter import Parameter
-from sfa.util.filter import Filter
-from sfa.util.PostgreSQL import PostgreSQL
-from sfa.util.record import SfaRecord, AuthorityRecord, NodeRecord, SliceRecord, UserRecord
+
+from sfa.storage.parameter import Parameter
+from sfa.storage.filter import Filter
+from sfa.storage.PostgreSQL import PostgreSQL
+from sfa.storage.record import SfaRecord, AuthorityRecord, NodeRecord, SliceRecord, UserRecord
 
 class SfaTable(list):
 
@@ -34,6 +35,7 @@ class SfaTable(list):
         if tables:
             return True
         return False
+
     def db_fields(self, obj=None):
         
         db_fields = self.db.fields(self.SFA_TABLE_PREFIX)
@@ -54,34 +56,34 @@ class SfaTable(list):
 
 
     def create(self):
-        
-        querystr = "CREATE TABLE " + self.tablename + " ( \
-                record_id serial PRIMARY KEY , \
-                hrn text NOT NULL, \
-                authority text NOT NULL, \
-                peer_authority text, \
-                gid text, \
-                type text NOT NULL, \
-                pointer integer, \
-                date_created timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, \
-                last_updated timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP);"
-        template = "CREATE INDEX %s_%s_idx ON %s (%s);"
-        indexes = [template % ( self.tablename, field, self.tablename, field) \
-                   for field in ['hrn', 'type', 'authority', 'peer_authority', 'pointer']]
-        # IF EXISTS doenst exist in postgres < 8.2
-        try:
-            self.db.do('DROP TABLE IF EXISTS ' + self.tablename)
-        except:
-            try:
-                self.db.do('DROP TABLE' + self.tablename)
-            except:
-                pass
-         
-        self.db.do(querystr)
-        for index in indexes:
-            self.db.do(index)
-        
-        self.db.commit()
+        pass
+#        querystr = "CREATE TABLE " + self.tablename + " ( \
+#                record_id serial PRIMARY KEY , \
+#                hrn text NOT NULL, \
+#                authority text NOT NULL, \
+#                peer_authority text, \
+#                gid text, \
+#                type text NOT NULL, \
+#                pointer integer, \
+#                date_created timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, \
+#                last_updated timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP);"
+#        template = "CREATE INDEX %s_%s_idx ON %s (%s);"
+#        indexes = [template % ( self.tablename, field, self.tablename, field) \
+#                   for field in ['hrn', 'type', 'authority', 'peer_authority', 'pointer']]
+#        # IF EXISTS doenst exist in postgres < 8.2
+#        try:
+#            self.db.do('DROP TABLE IF EXISTS ' + self.tablename)
+#        except:
+#            try:
+#                self.db.do('DROP TABLE' + self.tablename)
+#            except:
+#                pass
+#         
+#        self.db.do(querystr)
+#        for index in indexes:
+#            self.db.do(index)
+#        
+#        self.db.commit()
     
     def remove(self, record):
         params = {'record_id': record['record_id']}
index 2ad7f7b..f114a2d 100644 (file)
@@ -36,6 +36,7 @@ class Config:
             # path to configuration data
             self.config_path = os.path.dirname(config_file)
             
+            ### xxx todo implement defaults in default_config.xml 
             # path to server data
             if not hasattr(self, 'SFA_DATA_DIR'):
                 # default to /var/lib/sfa not specified in config
@@ -46,29 +47,12 @@ class Config:
                 
             # path to config data
             if not hasattr(self, 'SFA_CONFIG_DIR'):
-                # default to /var/lib/sfa not specified in config
+                # default to /etc/sfa not specified in config
                 self.SFA_CONFIG_DIR="/etc/sfa"
 
             if not hasattr(self, 'SFA_REGISTRY_LEVEL1_AUTH'):
                 self.SFA_REGISTRY_LEVEL1_AUTH=None
 
-            # define interface types
-            # this will determine which manager to use
-            if not hasattr(self, 'SFA_REGISTRY_TYPE'):
-                self.SFA_REGISTRY_TYPE='pl'
-
-            if not hasattr(self, 'SFA_AGGREGATE_TYPE'):
-                self.SFA_AGGREGATE_TYPE='pl'
-
-            if not hasattr(self, 'SFA_SM_TYPE'):
-                self.SFA_SM_TYPE='pl'
-
-            if not hasattr(self, 'SFA_CM_TYPE'):
-                self.SFA_COMPONENT_TYPE='pl'
-
-            if not hasattr(self, 'SFA_MAX_SLICE_RENEW'):
-                self.SFA_MAX_SLICE_RENEW=60
-
             # create the data directory if it doesnt exist
             if not os.path.isdir(self.SFA_DATA_DIR):
                 try:
@@ -92,12 +76,6 @@ class Config:
 
         return (aggr_mgr_ip,aggr_mgr_port)
 
-    def get_aggregate_type(self):
-        if (hasattr(self,'SFA_AGGREGATE_TYPE')):
-            return self.SFA_AGGREGATE_TYPE
-        else:
-            return "pl"
-
     def get_interface_hrn(self):
         if (hasattr(self,'SFA_INTERFACE_HRN')):
             return self.SFA_INTERFACE_HRN
@@ -125,20 +103,3 @@ class Config:
 
         return (am_apiclient_path,am_url)
 
-    ##
-    # SFA uses a PLCAPI connection to perform operations on the registry,
-    # such as creating and deleting slices. This connection requires an account
-    # on the PLC server with full administrator access.
-    #
-    # The Url parameter controls whether the connection uses PLCAPI directly (i.e.
-    # SFA is located on the same machine as PLC), or uses a XMLRPC connection
-    # to the PLC machine. If you wish to use the API directly, then remove the Url
-    # field from the dictionary. 
-
-    def get_plc_auth(self):
-        return {
-            'AuthMethod': 'capability',
-            'Username': self.SFA_PLC_USER,
-            'AuthString':  self.SFA_PLC_PASSWORD,
-            "Url": self.SFA_PLC_URL
-            }
index 4a1a5e4..ef277ff 100644 (file)
@@ -255,6 +255,22 @@ class InvalidRSpec(SfaFault):
     def __str__(self):
         return repr(self.value)
 
+class InvalidRSpecVersion(SfaFault):
+    def __init__(self, value, extra = None):
+        self.value = value
+        faultString = "Invalid RSpec version: %(value)s" % locals()
+        SfaFault.__init__(self, GENICODE.BADVERSION, faultString, extra)
+    def __str__(self):
+        return repr(self.value)
+
+class UnsupportedRSpecVersion(SfaFault):
+    def __init__(self, value, extra = None):
+        self.value = value
+        faultString = "Unsupported RSpec version: %(value)s" % locals()
+        SfaFault.__init__(self, GENICODE.UNSUPPORTED, faultString, extra)
+    def __str__(self):
+        return repr(self.value)
+
 class InvalidRSpecElement(SfaFault):
     def __init__(self, value, extra = None):
         self.value = value
index 97ddb39..4bfeb9b 100644 (file)
@@ -7,10 +7,10 @@ import time
 from types import IntType, LongType, StringTypes
 import textwrap
 
-
 from sfa.util.sfalogging import logger
 from sfa.util.faults import SfaFault, SfaInvalidAPIMethod, SfaInvalidArgumentCount, SfaInvalidArgument
-from sfa.util.parameter import Parameter, Mixed, python_type, xmlrpc_type
+
+from sfa.storage.parameter import Parameter, Mixed, python_type, xmlrpc_type
 
 class Method:
     """
index 0eff8e8..329d84e 100755 (executable)
@@ -2,7 +2,7 @@ import unittest
 import xmlrpclib
 from sfa.trust.gid import *
 from sfa.util.config import *
-from sfa.util.record import *
+from sfa.storage.record import *
 
 class TestRecord(unittest.TestCase):
     def setUp(self):
index de44628..e794e89 100755 (executable)
@@ -16,7 +16,7 @@ import inspect
 from types import *
 from optparse import OptionParser
 
-from sfa.util.parameter import Parameter,Mixed
+from sfa.storage.parameter import Parameter,Mixed
 
 import globals