-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
+++ /dev/null
-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
<description>Basic system variables.</description>
<variablelist>
+ <variable id="generic_flavour" type="string">
+ <name>Generic Flavour</name>
+ <value>pl</value>
+ <description>This string refers to a class located in sfa.generic that describes
+ which specific implementation needs to be used for api, manager and driver objects.
+ PlanetLab users do not need to change this setting.
+ </description>
+ </variable>
+
<variable id="interface_hrn" type="string">
<name>Human readable name</name>
<value>plc</value>
<description>The human readable name for this interface.</description>
</variable>
+ <variable id="aggregate_api_version" type="int">
+ <name>Aggregate Manager API Version</name>
+ <value>1</value>
+ <description>The Aggregate API version</description>
+ </variable>
+
<variable id="credential_schema" type="string">
<name>Credential Schema</name>
<value>/etc/sfa/credential.xsd</value>
</description>
</variable>
- <variable id="generic_flavour" type="string">
- <name>Generic Flavour</name>
- <value>pl</value>
- <description>This string refers to a class located in sfa.generic that describes
- which specific implementation needs to be used for api, manager and driver objects.
- PlanetLab users do not need to change this setting.
- </description>
- </variable>
-
</variablelist>
</category>
<description>The settings that tell this SFA instance where to find its database. You can essentially leave this as-is unless you plan on hosting your data on some other box.</description>
<variablelist>
+ <variable id="enabled" type="boolean">
+ <name>Enabled</name>
+ <value>true</value>
+ <description>Enable the database server on this machine.</description>
+ </variable>
+
<variable id="host" type="hostname">
<name>Database host</name>
<value>localhost</value>
<variable id="user" type="string">
<name>Database user</name>
- <value>pgsqluser</value>
+ <value>sfadbuser</value>
<description>When SFA gets co-hosted with a myplc, this should match the PLC config.</description>
</variable>
"SFA_PLC_USER",
"SFA_PLC_PASSWORD",
"SFA_DB_HOST",
- "SFA_DB_USER",
- "SFA_DB_PASSWORD",
]
configuration={ \
+++ /dev/null
-<?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=""user""/>
- <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>
+++ /dev/null
-<?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=""""/>
- <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=""""/>
- <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>
+++ /dev/null
-<?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>
+++ /dev/null
-<?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>
+++ /dev/null
-<?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="""" 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="""" 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>
+++ /dev/null
-<?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>
'sfatables',
'sfatables/commands',
'sfatables/processors',
- 'flashpolicy',
]
+initscripts = [ 'sfa', 'sfa-cm' ]
+
data_files = [('/etc/sfa/', [ 'config/aggregates.xml',
'config/registries.xml',
'config/default_config.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/', [ "sfa/init.d/%s"%x for x in initscripts ])]
# add sfatables processors as data_files
processor_files = [f for f in glob('sfatables/processors/*') if os.path.isfile(f)]
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:
%define name sfa
-%define version 1.1
-%define taglevel 4
+%define version 2.0
+%define taglevel 0
%define release %{taglevel}%{?pldistro:.%{pldistro}}%{?date:.%{date}}
%global python_sitearch %( python -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)" )
Packager: PlanetLab Central <support@planet-lab.org>
Distribution: PlanetLab %{plrelease}
URL: %{SCMURL}
+
Summary: the SFA python libraries
Group: Applications/System
-
BuildRequires: make
Requires: python >= 2.5
Requires: m2crypto
Requires: xmlsec1-openssl-devel
Requires: libxslt-python
Requires: python-ZSI
+# for uuidgen - used in db password generation
+# on f8 this actually comes with e2fsprogs, go figure
+Requires: util-linux-ng
# xmlbuilder depends on lxml
Requires: python-lxml
Requires: python-setuptools
Requires: postgresql >= 8.2, postgresql-server >= 8.2
Requires: postgresql-python
Requires: python-psycopg2
+Requires: pyOpenSSL >= 0.7
+Requires: myplc-config
# python 2.5 has uuid module added, for python 2.4 we still need it.
# we can't really check for if we can load uuid as a python module,
#Requires: python-uuid
#%endif
-%package cm
-Summary: the SFA layer around MyPLC NodeManager
-Group: Applications/System
-Requires: sfa
-Requires: pyOpenSSL >= 0.6
-
%package plc
Summary: the SFA layer around MyPLC
Group: Applications/System
Requires: sfa
Requires: python-psycopg2
-Requires: myplc-config
-Requires: pyOpenSSL >= 0.7
%package client
Summary: the SFA experimenter-side CLI
Group: Applications/System
Requires: sfa
+%package cm
+Summary: the SFA layer around MyPLC NodeManager
+Group: Applications/System
+Requires: sfa
+Requires: pyOpenSSL >= 0.6
+
%package flashpolicy
Summary: SFA support for flash clients
Group: Applications/System
%description
This package provides the python libraries for the PlanetLab implementation of SFA
-%description cm
-This package implements the SFA interface which serves as a layer
-between the existing PlanetLab NodeManager interfaces and the SFA API.
-
%description plc
This package implements the SFA interface which serves as a layer
between the existing PlanetLab interfaces and the SFA API.
in an SFA network, in much the same way as iptables is for ip
networks. This is the command line interface to manage sfatables
+%description cm
+This package implements the SFA interface which serves as a layer
+between the existing PlanetLab NodeManager interfaces and the SFA API.
+
%description flashpolicy
This package provides support for adobe flash client applications.
%install
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
%clean
rm -rf $RPM_BUILD_ROOT
%files
-# sfa and sfatables depend each other.
+# sfa and sfatables depend on each other.
+%{python_sitelib}/sfa
+%{python_sitelib}/xmlbuilder
+/etc/init.d/sfa
%{_bindir}/sfa-start.py*
-/etc/sfatables/*
-%{python_sitelib}/*
%{_bindir}/keyconvert.py*
+%{_bindir}/sfa-config-tty
+%config /etc/sfa/default_config.xml
+%config (noreplace) /etc/sfa/aggregates.xml
+%config (noreplace) /etc/sfa/registries.xml
/var/www/html/wsdl/*.wsdl
-%files cm
-/etc/init.d/sfa-cm
-%{_bindir}/sfa_component_setup.py*
-# cron jobs here
-
%files plc
%defattr(-,root,root)
-%config /etc/sfa/default_config.xml
-%config (noreplace) /etc/sfa/aggregates.xml
-%config (noreplace) /etc/sfa/registries.xml
-/etc/init.d/sfa
/etc/sfa/pl.rng
/etc/sfa/credential.xsd
/etc/sfa/top.xsd
/etc/sfa/xml.xsd
/etc/sfa/protogeni-rspec-common.xsd
/etc/sfa/topology
-%{_bindir}/sfa-config-tty
%{_bindir}/sfa-import-plc.py*
-%{_bindir}/sfa-clean-peer-records.py*
%{_bindir}/sfa-nuke-plc.py*
+%{_bindir}/sfa-clean-peer-records.py*
%{_bindir}/gen-sfa-cm-config.py*
%{_bindir}/sfa-ca.py*
%{_bindir}/sfadump.py*
%files sfatables
+/etc/sfatables/*
%{_bindir}/sfatables
+%{python_sitelib}/sfatables
+
+%files cm
+/etc/init.d/sfa-cm
+%{_bindir}/sfa_component_setup.py*
+# cron jobs here
%files flashpolicy
%{_bindir}/sfa_flashpolicy.py*
[ "$1" -ge "1" ] && service sfa-cm restart || :
%changelog
+* 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
+- server calls support optional 'options'
+- client sends options in argument when needed
+- fix infinite getattr recursion in elements/element.py
+- error codes in line with geni
+
* Fri Nov 18 2011 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - sfa-1.1-4
- fixed links and attributes in rspecs
- minor cleanup in the API methods, and more consistent names in manager methods
--- /dev/null
+
+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
import sys
sys.path.append('.')
+
import os, os.path
import tempfile
import socket
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.util.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
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
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:
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
user_cred = self.get_user_cred().save_to_string(save_parents=True)
server = self.slicemgr
server = self.server_proxy_from_opts(opts)
-
- options = {}
-
+
+ options = {'call_id': unique_call_id()}
+ #panos add info options
+ if opts.info:
+ options['info'] = opts.info
+
if args:
cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
hrn = args[0]
- options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
+ options['geni_slice_urn'] = hrn_to_urn(hrn, 'slice')
else:
cred = user_cred
- hrn = None
-
+
creds = [cred]
if opts.delegate:
delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
# 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()
- #panos add info options
- if opts.info:
- options['info'] = opts.info
- call_args = [creds]
- if self.server_supports_options_arg(server):
- options = {'call_id': unique_call_id()}
- call_args.append(options)
+ 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
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):
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):
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):
# 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
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
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()
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())
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:
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']
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
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__":
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):
"""
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:
# description: Wraps PLCAPI into the SFA compliant API
#
-# Source config
-[ -f /etc/sfa/sfa_config ] && . /etc/sfa/sfa_config
-
# source function library
. /etc/init.d/functions
-# Regenerate configuration files - almost verbatim from plc.init
-reload ()
+# Default locations
+PGDATA=/var/lib/pgsql/data
+postgresql_conf=$PGDATA/postgresql.conf
+pghba_conf=$PGDATA/pg_hba.conf
+postgresql_sysconfig=/etc/sysconfig/pgsql
+
+# PLC consolidated (merged) config file
+plc_whole_config=/etc/planetlab/plc_config.xml
+# SFA consolidated (merged) config file
+sfa_whole_config=/etc/sfa/sfa_config.xml
+# SFA default config (read-only template)
+sfa_default_config=/etc/sfa/default_config.xml
+# SFA local (site-dependent) file
+sfa_local_config=/etc/sfa/configs/site.xml
+
+# Source sfa shell config if present
+[ -f /etc/sfa/sfa_config ] && . /etc/sfa/sfa_config
+
+# Export so that we do not have to specify -p to psql invocations
+export PGPORT=$SFA_DB_PORT
+
+##########
+# Total number of errors
+ERRORS=0
+
+# Count the exit status of the last command
+check ()
{
+ ERRORS=$(($ERRORS+$?))
+}
+
+# can't trust the return of service postgresql start / nor status
+function postgresql_check () {
+
+ # wait until postmaster is up and running - or 10s max
+ if status postmaster >& /dev/null && [ -f /var/lock/subsys/postgresql ] ; then
+ # The only way we can be sure is if we can access it
+ for i in $(seq 1 10) ; do
+ # Must do this as the postgres user initially (before we
+ # fix pg_hba.conf to passwordless localhost access).
+ su -c 'psql -U postgres -c "" template1' postgres && return 0
+ sleep 1
+ done
+ fi
+
+ return 1
+}
+
+
+# Regenerate configuration files - almost verbatim from plc.init
+function reload () {
force=$1
# Regenerate the main configuration file from default values
# overlaid with site-specific and current values.
# Thierry -- 2007-07-05 : values in plc_config.xml are *not* taken into account here
- files=(
- /etc/sfa/default_config.xml
- /etc/sfa/configs/site.xml
- )
+ files=( $sfa_default_config $sfa_local_config )
for file in "${files[@]}" ; do
- if [ -n "$force" -o $file -nt /etc/sfa/sfa_config.xml ] ; then
+ if [ -n "$force" -o $file -nt $sfa_whole_config ] ; then
tmp=$(mktemp /tmp/sfa_config.xml.XXXXXX)
plc-config --xml "${files[@]}" >$tmp
if [ $? -eq 0 ] ; then
- mv $tmp /etc/sfa/sfa_config.xml
- chmod 444 /etc/sfa/sfa_config.xml
+ mv $tmp $sfa_whole_config
+ chmod 444 $sfa_whole_config
else
echo "SFA: Warning: Invalid configuration file(s) detected"
rm -f $tmp
done
# Convert configuration to various formats
- if [ -n "$force" -o /etc/sfa/sfa_config.xml -nt /etc/sfa/sfa_config ] ; then
- plc-config --shell /etc/sfa/sfa_config.xml >/etc/sfa/sfa_config
+ if [ -n "$force" -o $sfa_whole_config -nt /etc/sfa/sfa_config ] ; then
+ plc-config --shell $sfa_whole_config >/etc/sfa/sfa_config
fi
- if [ -n "$force" -o /etc/sfa/sfa_config.xml -nt /etc/sfa/sfa_config.py ] ; then
- plc-config --python /etc/sfa/sfa_config.xml >/etc/sfa/sfa_config.py
+ 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
fi
-# if [ -n "$force" -o /etc/sfa/sfa_config.xml -nt /etc/sfa/php/sfa_config.php ] ; then
+# if [ -n "$force" -o $sfa_whole_config -nt /etc/sfa/php/sfa_config.php ] ; then
# mkdir -p /etc/sfa/php
-# plc-config --php /etc/sfa/sfa_config.xml >/etc/sfa/php/sfa_config.php
+# plc-config --php $sfa_whole_config >/etc/sfa/php/sfa_config.php
# fi
# [re]generate the sfa_component_config
- gen-sfa-cm-config.py
+ # this is a server-side thing but produces a file that somehow needs to be pushed
+ # on the planetlab nodes; in the case where sfa and myplc run on different boxes
+ # (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
}
-start() {
+### initialize DB (don't chkconfig postgresql on)
+function db_start () {
+
+ # only if enabled
+ [ "$SFA_DB_ENABLED" == 1 ] || return
+
+ if ! rpm -q myplc >& /dev/null; then
+
+ ######## standalone deployment - no colocated myplc
+
+ ######## sysconfig
+ # Set data directory and redirect startup output to /var/log/pgsql
+ mkdir -p $(dirname $postgresql_sysconfig)
+ # remove previous definitions
+ touch $postgresql_sysconfig
+ tmp=${postgresql_sysconfig}.new
+ ( egrep -v '^(PGDATA=|PGLOG=|PGPORT=)' $postgresql_sysconfig
+ echo "PGDATA=$PGDATA"
+ echo "PGLOG=/var/log/pgsql"
+ echo "PGPORT=$PLC_DB_PORT"
+ ) >> $tmp ; mv -f $tmp $postgresql_sysconfig
+
+ ######## /var/lib/pgsql/data
+ # Fix ownership (rpm installation may have changed it)
+ chown -R -H postgres:postgres $(dirname $PGDATA)
+
+ # PostgreSQL must be started at least once to bootstrap
+ # /var/lib/pgsql/data
+ if [ ! -f $postgresql_conf ] ; then
+ service postgresql initdb &> /dev/null || :
+ check
+ fi
+
+ ######## /var/lib/pgsql/data/postgresql.conf
+ registry_ip=""
+ foo=$(python -c "import socket; print socket.gethostbyname(\"$SFA_REGISTRY_HOST\")") && registry_ip="$foo"
+ # Enable DB server. drop Postgresql<=7.x
+ # PostgreSQL >=8.0 defines listen_addresses
+ # listen on a specific IP + localhost, more robust when run within a vserver
+ sed -i -e '/^listen_addresses/d' $postgresql_conf
+ if [ -z "$registry_ip" ] ; then
+ echo "listen_addresses = 'localhost'" >> $postgresql_conf
+ else
+ echo "listen_addresses = '${registry_ip},localhost'" >> $postgresql_conf
+ fi
+ # tweak timezone to be 'UTC'
+ sed -i -e '/^timezone=/d' $postgresql_conf
+ echo "timezone='UTC'" >> $postgresql_conf
+
+ ######## /var/lib/pgsql/data/pg_hba.conf
+ # Disable access to all DBs from all hosts
+ sed -i -e '/^\(host\|local\)/d' $pghba_conf
+
+ # Enable passwordless localhost access
+ echo "local all all trust" >>$pghba_conf
+ # grant access
+ (
+ echo "host $SFA_DB_NAME $SFA_DB_USER 127.0.0.1/32 password"
+ [ -n "$registry_ip" ] && echo "host $SFA_DB_NAME $SFA_DB_USER ${registry_ip}/32 password"
+ ) >>$pghba_conf
+
+ # Fix ownership (sed -i changes it)
+ chown postgres:postgres $postgresql_conf $pghba_conf
+
+ ######## 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 >& /dev/null
+ reload force
+ fi
+
+ else
+
+ ######## we are colocated with a myplc
+ # no need to worry about the pgsql setup (see /etc/plc.d/postgresql)
+ # myplc enforces the password for its user
+ 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 >& /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
+
+ ######## Start up the server
+ # not too nice, but.. when co-located with myplc we'll let it start/stop postgresql
+ if ! rpm -q myplc >& /dev/null ; then
+ echo STARTING...
+ service postgresql start >& /dev/null
+ fi
+ postgresql_check
+ check
+
+ ######## 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 >& /dev/null
+ else
+ 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
+ fi
+ check
+
+ MESSAGE=$"Checking for PostgreSQL server"
+ echo -n "$MESSAGE"
+ [ "$ERRORS" == 0 ] && success "$MESSAGE" || failure "$MESSAGE" ; echo
+}
+
+# shutdown DB
+function db_stop () {
+
+ # only if enabled
+ [ "$SFA_DB_ENABLED" == 1 ] || return
+
+ # not too nice, but.. when co-located with myplc we'll let it start/stop postgresql
+ if ! rpm -q myplc >& /dev/null ; then
+ service postgresql stop >& /dev/null
+ check
+ MESSAGE=$"Stopping PostgreSQL server"
+ echo -n "$MESSAGE"
+ [ "$ERRORS" == 0 ] && success "$MESSAGE" || failure "$MESSAGE" ; echo
+ fi
+}
+
+function start() {
reload
+ db_start
+
# install peer certs
action $"SFA installing peer certs" daemon /usr/bin/sfa-start.py -t -d $OPTIONS
action "Flash Policy Server" daemon /usr/bin/sfa_flashpolicy.py --file="$SFA_FLASHPOLICY_CONFIG_FILE" --port=$SFA_FLASHPOLICY_PORT -d
fi
- RETVAL=$?
- [ $RETVAL -eq 0 ] && touch /var/lock/subsys/sfa-start.py
+ touch /var/lock/subsys/sfa-start.py
}
-stop() {
+function stop() {
action $"Shutting down SFA" killproc sfa-start.py
- RETVAL=$?
- [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/sfa-start.py
+ db_stop
+
+ rm -f /var/lock/subsys/sfa-start.py
}
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={}):
ad_rspec_versions.append(rspec_version.to_dict())
if rspec_version.content_type in ['*', 'request']:
request_rspec_versions.append(rspec_version.to_dict())
- default_rspec_version = version_manager.get_version("sfa 1").to_dict()
xrn=Xrn(api.hrn)
version_more = {'interface':'aggregate',
+ 'sfa': 2,
+ 'geni_api': api.config.SFA_AGGREGATE_API_VERSION,
'testbed':'myplc',
'hrn':xrn.get_hrn(),
- 'request_rspec_versions': request_rspec_versions,
- 'ad_rspec_versions': ad_rspec_versions,
- 'default_ad_rspec': default_rspec_version
+ 'geni_request_rspec_versions': request_rspec_versions,
+ 'geni_ad_rspec_versions': ad_rspec_versions,
}
return version_core(version_more)
return 1
def DeleteSliver(self, api, xrn, creds, options={}):
- call_id = option.get('call_id')
+ call_id = options.get('call_id')
if Callids().already_handled(call_id): return ""
(hrn, _) = urn_to_hrn(xrn)
slicename = hrn_to_pl_slicename(hrn)
return 1
def ListSlices(self, api, creds, options={}):
- call_id = option.get('call_id')
+ call_id = options.get('call_id')
if Callids().already_handled(call_id): return []
# look in cache first
if self.caching and api.cache:
return slice_urns
def ListResources(self, api, creds, options={}):
- call_id = option.get('call_id')
+ call_id = options.get('call_id')
if Callids().already_handled(call_id): return ""
# get slice's hrn from options
xrn = options.get('geni_slice_urn', None)
+ cached = options.get('cached', True)
(hrn, _) = urn_to_hrn(xrn)
version_manager = VersionManager()
version_string = version_string + "_"+options.get('info', 'default')
# look in cache first
- if self.caching and api.cache and not xrn:
+ if self.caching and api.cache and not xrn and cached:
rspec = api.cache.get(version_string)
if rspec:
api.logger.info("aggregate.ListResources: returning cached value for hrn %s"%hrn)
#panos: passing user-defined options
#print "manager options = ",options
- aggregate = Aggregate(api, options)
- rspec = aggregate.get_rspec(slice_xrn=xrn, version=rspec_version)
+ aggregate = Aggregate(api)
+ rspec = aggregate.get_rspec(slice_xrn=xrn, version=rspec_version, options=options)
# cache the result
if self.caching and api.cache and not xrn:
ad_rspec_versions.append(rspec_version.to_dict())
if rspec_version.content_type in ['*', 'request']:
request_rspec_versions.append(rspec_version.to_dict())
- default_rspec_version = version_manager.get_version("sfa 1").to_dict()
xrn=Xrn(api.hrn)
version_more = {'interface':'aggregate',
+ 'sfa': 1,
+ 'geni_api': api.config.SFA_AGGREGATE_API_VERSION,
'testbed':'myplc',
'hrn':xrn.get_hrn(),
- 'request_rspec_versions': request_rspec_versions,
- 'ad_rspec_versions': ad_rspec_versions,
- 'default_ad_rspec': default_rspec_version
+ 'geni_request_rspec_versions': request_rspec_versions,
+ 'geni_ad_rspec_versions': ad_rspec_versions,
}
return version_core(version_more)
--- /dev/null
+#
+# 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
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
# 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']:
+ 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
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 = {}
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):
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
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
+ # 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']
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)
# 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_relation(record, 'researcher', record.get('researcher'), 'user')
return record.get_gid_object().save_to_string(save_parents=True)
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_relation(record, 'researcher', new_record.get('researcher'), 'user')
return 1
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
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
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.
ad_rspec_versions.append(rspec_version.to_dict())
if rspec_version.content_type in ['*', 'request']:
request_rspec_versions.append(rspec_version.to_dict())
- default_rspec_version = version_manager.get_version("sfa 1").to_dict()
xrn=Xrn(api.hrn, 'authority+sa')
version_more = {'interface':'slicemgr',
+ 'sfa': 1,
+ 'geni_api': api.config.SFA_AGGREGATE_API_VERSION,
'hrn' : xrn.get_hrn(),
'urn' : xrn.get_urn(),
'peers': peers,
- 'request_rspec_versions': request_rspec_versions,
- 'ad_rspec_versions': ad_rspec_versions,
- 'default_ad_rspec': default_rspec_version
+ 'geni_request_rspec_versions': request_rspec_versions,
+ 'geni_ad_rspec_versions': ad_rspec_versions,
}
sm_version=version_core(version_more)
# local aggregate if present needs to have localhost resolved
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"}
# get the rspec from the aggregate
interface = api.aggregates[aggregate]
server = api.server_proxy(interface, cred)
- threads.run(_ListResources, aggregate, server, [cred], options, call_id)
+ threads.run(_ListResources, aggregate, server, [cred], options)
results = threads.get_results()
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")
logger.log_exc('Something wrong in _CreateSliver with URL %s'%server.url)
return {"aggregate": aggregate, "elapsed": time.time()-tStart, "status": "exception", "exc_info": sys.exc_info()}
- call_id = option.get('call_id')
+ call_id = options.get('call_id')
if Callids().already_handled(call_id): return ""
# Validate the RSpec against PlanetLab's schema --disabled for now
# The schema used here needs to aggregate the PL and VINI schemas
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()
args.append(options)
return server.RenewSliver(*args)
- call_id = option.get('call_id')
+ call_id = options.get('call_id')
if Callids().already_handled(call_id): return True
(hrn, type) = urn_to_hrn(xrn)
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={}):
args.append(options)
return server.DeleteSliver(*args)
- call_id = option.get('call_id')
+ call_id = options.get('call_id')
if Callids().already_handled(call_id): return ""
(hrn, type) = urn_to_hrn(xrn)
# get the callers hrn
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']]
continue
interface = api.aggregates[aggregate]
server = api.server_proxy(interface, cred)
- threads.run(_ListSlices, server, [cred], call_id, options)
+ 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)
origin_hrn = options.get('origin_hrn', None)
if not origin_hrn:
origin_hrn = Credential(string=valid_creds[0]).get_gid_caller().get_hrn()
- rspec = self.api.manager.ListResources(self.api, creds, options, options)
+ rspec = self.api.manager.ListResources(self.api, creds, options)
# filter rspec through sfatables
if self.api.interface in ['aggregate']:
Stop
Update
UpdateSliver
-get_key
+get_key_from_incoming_ip
get_trusted_certs
reset_slice
""".split()
+++ /dev/null
-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
--- /dev/null
+from sfa.util.method import Method
+from sfa.util.parameter import Parameter
+from sfa.util.sfalogging import logger
+
+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
#panos new user options variable
user_options = {}
- def __init__(self, api, user_options={}):
+ def __init__(self, api):
self.api = api
- self.user_options = user_options
-
+
def get_sites(self, filter={}):
sites = {}
for site in self.api.driver.GetSites(filter):
return (slice, slivers)
- def get_nodes_and_links(self, slice=None,slivers=[]):
+ def get_nodes_and_links(self, slice=None,slivers=[], options={}):
filter = {}
tags_filter = {}
if slice and 'node_ids' in slice and slice['node_ids']:
filter['node_id'] = slice['node_ids']
tags_filter=filter.copy()
+
+ geni_available = options.get('geni_available')
+ if geni_available:
+ filter['boot_state'] = 'boot'
filter.update({'peer_id': None})
nodes = self.api.driver.GetNodes(filter)
return (rspec_nodes, links)
- def get_rspec(self, slice_xrn=None, version = None):
+ def get_rspec(self, slice_xrn=None, version = None, options={}):
version_manager = VersionManager()
version = version_manager.get_version(version)
rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
slice, slivers = self.get_slice_and_slivers(slice_xrn)
- rspec = RSpec(version=rspec_version, user_options=self.user_options)
+ rspec = RSpec(version=rspec_version, user_options=options)
if slice and 'expires' in slice:
rspec.xml.set('expires', epochparse(slice['expires']))
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):
#
-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
+# 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):
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)
assert (rspec_type == 'pl' or rspec_type == 'vini' or \
rspec_type == 'eucalyptus' or rspec_type == 'max')
+ ########## disabled users
+ def is_enabled (self, record):
+ self.fill_record_info(record, deep=False)
+ 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, deep=True)
+
+ ##########
+ 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, deep=False):
+ """
+ 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)
+ if deep:
+ 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
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):
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)]
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:
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'] = []
# 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, [])
+ ####################
+ # 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
+ 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:
- oldList = []
- newList = record.get(listName, [])
-
- # if the lists are the same, then we don't have to update anything
- if (oldList == newList):
- return
+ logger.info('unexpected relation to maintain, %s -> %s'%(subject_type,target_type))
- # 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()
- 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
+
+import sys
import xmlrpclib
+import socket
+from urlparse import urlparse
+
+from sfa.util.sfalogging import logger
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):
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
+++ /dev/null
-# 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)
-
-
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'])
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')
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
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:
# 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
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(':')
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()
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())
# Networks
def get_networks(self):
networks = set()
- nodes = self.xml.xpath('//default:node[@component_manager_id]', namespaces=self.namespaces)
+ 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:
network_urn = node.get('component_manager_id')
"""
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
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):
"""
import os, os.path
import datetime
-from sfa.util.faults import SfaAPIError
+from sfa.util.faults import SfaFault, SfaAPIError
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
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
+
+
+ def get_geni_code(self, result):
+ code = {
+ 'geni_code': GENICODE.SUCCESS,
+ 'am_type': 'sfa',
+ 'am_code': None,
+ }
+ if isinstance(result, SfaFault):
+ code['geni_code'] = result.faultCode
+ code['am_code'] = result.faultCode
+
+ return code
+
+ def get_geni_value(self, result):
+ value = result
+ if isinstance(result, SfaFault):
+ value = ""
+ return value
+
+ def get_geni_output(self, result):
+ output = ""
+ if isinstance(result, SfaFault):
+ output = result.faultString
+ return output
+
+ def prepare_response_v2_am(self, result):
+ response = {
+ 'code': self.get_geni_code(result),
+ 'value': self.get_geni_value(result),
+ 'output': self.get_geni_output(result),
+ }
+ return response
+
+ def prepare_response(self, result, method=""):
+ """
+ Converts the specified result into a standard GENI compliant
+ response
+ """
+ if self.interface.lower() in ['aggregate', 'slicemgr']:
+ if hasattr(self.config, 'SFA_AGGREGATE_API_VERSION') and \
+ self.config.SFA_AGGREGATE_API_VERSION == 2:
+ result = self.prepare_response_v2_am(result)
+ return XmlrpcApi.prepare_response(self, result, method)
+
# 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
# 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:
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
- }
#
import xmlrpclib
+from sfa.util.genicode import GENICODE
class SfaFault(xmlrpclib.Fault):
def __init__(self, faultCode, faultString, extra = None):
faultString = "Invalid method " + method
if interface:
faultString += " for interface " + interface
- SfaFault.__init__(self, 100, faultString, extra)
+ SfaFault.__init__(self, GENICODE.UNSUPPORTED, faultString, extra)
class SfaInvalidArgumentCount(SfaFault):
def __init__(self, got, min, max = min, extra = None):
expected = "%d" % min
faultString = "Expected %s arguments, got %d" % \
(expected, got)
- SfaFault.__init__(self, 101, faultString, extra)
+ SfaFault.__init__(self, GENICODE.BADARGS, faultString, extra)
class SfaInvalidArgument(SfaFault):
def __init__(self, extra = None, name = None):
faultString = "Invalid %s value" % name
else:
faultString = "Invalid argument"
- SfaFault.__init__(self, 102, faultString, extra)
+ SfaFault.__init__(self, GENICODE.BADARGS, faultString, extra)
class SfaAuthenticationFailure(SfaFault):
def __init__(self, extra = None):
faultString = "Failed to authenticate call"
- SfaFault.__init__(self, 103, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
class SfaDBError(SfaFault):
def __init__(self, extra = None):
faultString = "Database error"
- SfaFault.__init__(self, 106, faultString, extra)
+ SfaFault.__init__(self, GENICODE.DBERROR, faultString, extra)
class SfaPermissionDenied(SfaFault):
def __init__(self, extra = None):
faultString = "Permission denied"
- SfaFault.__init__(self, 108, faultString, extra)
+ SfaFault.__init__(self, GENICODE.FORBIDDEN, faultString, extra)
class SfaNotImplemented(SfaFault):
def __init__(self, interface=None, extra = None):
faultString = "Not implemented"
if interface:
faultString += " at interface " + interface
- SfaFault.__init__(self, 109, faultString, extra)
+ SfaFault.__init__(self, GENICODE.UNSUPPORTED, faultString, extra)
class SfaAPIError(SfaFault):
def __init__(self, extra = None):
faultString = "Internal API error"
- SfaFault.__init__(self, 111, faultString, extra)
+ SfaFault.__init__(self, GENICODE.SERVERERROR, faultString, extra)
class MalformedHrnException(SfaFault):
def __init__(self, value, extra = None):
self.value = value
faultString = "Malformed HRN: %(value)s" % locals()
- SfaFault.__init__(self, 102, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Tree Exception: %(value)s, " % locals()
- SfaFault.__init__(self, 111, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Non exsiting record %(value)s, " % locals()
- SfaFault.__init__(self, 111, faultString, extra)
+ SfaFault.__init__(self, GENICODE.SEARCHFAILED, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Existing record: %(value)s, " % locals()
- SfaFault.__init__(self, 111, faultString, extra)
+ SfaFault.__init__(self, GENICODE.REFUSED, faultString, extra)
def __str__(self):
return repr(self.value)
-class NonexistingCredType(SfaFault):
- def __init__(self, value, extra = None):
- self.value = value
- faultString = "Non existing record: %(value)s, " % locals()
- SfaFault.__init__(self, 111, faultString, extra)
- def __str__(self):
- return repr(self.value)
-
-class NonexistingFile(SfaFault):
- def __init__(self, value, extra = None):
- self.value = value
- faultString = "Non existing file: %(value)s, " % locals()
- SfaFault.__init__(self, 111, faultString, extra)
- def __str__(self):
- return repr(self.value)
-
class InvalidRPCParams(SfaFault):
def __init__(self, value, extra = None):
self.value = value
faultString = "Invalid RPC Params: %(value)s, " % locals()
- SfaFault.__init__(self, 102, faultString, extra)
+ SfaFault.__init__(self, GENICODE.RPCERROR, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Connection Key GID mismatch: %(value)s" % locals()
- SfaFault.__init__(self, 102, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Missing Caller GID: %(value)s" % locals()
- SfaFault.__init__(self, 102, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Record not found: %(value)s" % locals()
- SfaFault.__init__(self, 102, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Unknown SFA Type: %(value)s" % locals()
- SfaFault.__init__(self, 102, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Missing authority: %(value)s" % locals()
- SfaFault.__init__(self, 102, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "PlanetLab record does not exist : %(value)s" % locals()
- SfaFault.__init__(self, 102, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Permission error: %(value)s" % locals()
- SfaFault.__init__(self, 108, faultString, extra)
+ SfaFault.__init__(self, GENICODE.FORBIDDEN, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Insufficient rights: %(value)s" % locals()
- SfaFault.__init__(self, 108, faultString, extra)
+ SfaFault.__init__(self, GENICODE.FORBIDDEN, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Missing delegate bit: %(value)s" % locals()
- SfaFault.__init__(self, 108, faultString, extra)
+ SfaFault.__init__(self, GENICODE.FORBIDDEN, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Child rights not subset of parent: %(value)s" % locals()
- SfaFault.__init__(self, 103, faultString, extra)
+ SfaFault.__init__(self, GENICODE.FORBIDDEN, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Cert missing parent: %(value)s" % locals()
- SfaFault.__init__(self, 103, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Cert not signed by parent: %(value)s" % locals()
- SfaFault.__init__(self, 103, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Cert URN is not an extension of its parent: %(value)s" % locals()
- SfaFault.__init__(self, 103, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "GID invalid parent hrn: %(value)s" % locals()
- SfaFault.__init__(self, 102, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Sliver does not exist : %(value)s" % locals()
- SfaFault.__init__(self, 102, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
def __str__(self):
return repr(self.value)
class BadRequestHash(xmlrpclib.Fault):
def __init__(self, hash = None, extra = None):
faultString = "bad request hash: " + str(hash)
- xmlrpclib.Fault.__init__(self, 902, faultString)
+ xmlrpclib.Fault.__init__(self, GENICODE.ERROR, faultString)
class MissingTrustedRoots(SfaFault):
def __init__(self, value, extra = None):
self.value = value
faultString = "Trusted root directory does not exist: %(value)s" % locals()
- SfaFault.__init__(self, 102, faultString, extra)
+ SfaFault.__init__(self, GENICODE.SERVERERROR, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Missing information: %(value)s" % locals()
- SfaFault.__init__(self, 102, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Invalid RSpec: %(value)s" % locals()
- SfaFault.__init__(self, 108, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Invalid RSpec Element: %(value)s" % locals()
- SfaFault.__init__(self, 108, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Invalid XML Document: %(value)s" % locals()
- SfaFault.__init__(self, 108, faultString, extra)
- def __str__(self):
- return repr(self.value)
-
-class InvalidXMLElement(SfaFault):
- def __init__(self, value, extra = None):
- self.value = value
- faultString = "Invalid XML Element: %(value)s" % locals()
- SfaFault.__init__(self, 108, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
def __str__(self):
return repr(self.value)
class AccountNotEnabled(SfaFault):
def __init__(self, extra = None):
faultString = "Account Disabled"
- SfaFault.__init__(self, 108, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra = None):
self.value = value
faultString = "Unable to verify credential: %(value)s, " %locals()
- SfaFault.__init__(self, 115, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
def __str__(self):
return repr(self.value)
def __init__(self, value, extra=None):
self.value = value
faultString = "%s cert is expired" % value
- SfaFault.__init__(self, 102, faultString, extra)
+ SfaFault.__init__(self, GENICODE.ERROR, faultString, extra)
INPORGRESS=16,
ALREADYEXISTS=17
)
-
-from sfatables.runtime import SFATablesRules
+# sfa should not depend on sfatables
+# if the sfatables.runtime import fails, just define run_sfatables as identity
-def fetch_context(slice_hrn, user_hrn, contexts):
- """
- Returns the request context required by sfatables. At some point, this
- mechanism should be changed to refer to "contexts", which is the
- information that sfatables is requesting. But for now, we just return
- the basic information needed in a dict.
- """
- base_context = {'sfa':{'user':{'hrn':user_hrn}, 'slice':{'hrn':slice_hrn}}}
- return base_context
+try:
+ from sfatables.runtime import SFATablesRules
-def run_sfatables(chain, hrn, origin_hrn, rspec, context_callback = None ):
- """
- Run the rspec through sfatables
- @param chain Name of rule chain
- @param hrn Object's hrn
- @param origin_hrn Original caller's hrn
- @param rspec Incoming rspec
- @param context_callback Callback used to generate the request context
+ def fetch_context(slice_hrn, user_hrn, contexts):
+ """
+ Returns the request context required by sfatables. At some point, this
+ mechanism should be changed to refer to "contexts", which is the
+ information that sfatables is requesting. But for now, we just return
+ the basic information needed in a dict.
+ """
+ base_context = {'sfa':{'user':{'hrn':user_hrn}, 'slice':{'hrn':slice_hrn}}}
+ return base_context
- @return rspec
- """
- if not context_callback:
- context_callback = fetch_context
+ def run_sfatables(chain, hrn, origin_hrn, rspec, context_callback = None ):
+ """
+ Run the rspec through sfatables
+ @param chain Name of rule chain
+ @param hrn Object's hrn
+ @param origin_hrn Original caller's hrn
+ @param rspec Incoming rspec
+ @param context_callback Callback used to generate the request context
+
+ @return rspec
+ """
+ if not context_callback:
+ context_callback = fetch_context
- chain = chain.upper()
- rules = SFATablesRules(chain)
- if rules.sorted_rule_list:
- contexts = rules.contexts
- request_context = context_callback(hrn, origin_hrn, contexts)
- rules.set_context(request_context)
- newrspec = rules.apply(rspec)
- else:
- newrspec = rspec
- return newrspec
+ chain = chain.upper()
+ rules = SFATablesRules(chain)
+ if rules.sorted_rule_list:
+ contexts = rules.contexts
+ request_context = context_callback(hrn, origin_hrn, contexts)
+ rules.set_context(request_context)
+ newrspec = rules.apply(rspec)
+ else:
+ newrspec = rspec
+ return newrspec
+
+except:
+
+ from sfa.util.logging import logger
+ def run_sfatables (_,__,___, rspec, ____=None):
+ logger.warning("Cannot import sfatables.runtime, please install package sfa-sfatables")
+ return rspec
import socket
def version_core (more={}):
- core = { 'geni_api':1,
- 'sfa' : 1,
- 'code_tag' : version_tag,
+ core = { 'code_tag' : version_tag,
'code_url' : scm_url,
'hostname' : socket.gethostname(),
}