]> PlanetLab Central API Documentation Introduction The PlanetLab Central API (PLCAPI) is the interface through which the PlanetLab Central database should be accessed and maintained. The API is used by the website, by nodes, by automated scripts, and by users to access and update information about users, nodes, sites, slices, and other entities maintained by the database.
Authentication The API should be accessed via XML-RPC over HTTPS. The API supports the standard introspection calls system.listMethods, system.methodSignature, and system.methodHelp, and the standard batching call system.multicall. With the exception of these calls, all PLCAPI calls take an authentication structure as their first argument. All authentication structures require the specification of AuthMethod. If the documentation for a call does not further specify the authentication structure, then any of (but only) the following authentication structures may be used: Session authentication. User sessions are typically valid for 24 hours. Node sessions are valid until the next reboot. Obtain a session key with GetSession using another form of authentication, such as password or GnuPG authentication. AuthMethodsession sessionSession key Password authentication. AuthMethodpassword UsernameUsername, typically an e-mail address AuthStringAuthentication string, typically a password GnuPG authentication. Users may upload a GPG public key using AddPersonKey. Peer GPG keys should be added with AddPeer or UpdatePeer. AuthMethodgpg namePeer or user name signatureGnuPG signature of the canonicalized XML-RPC representation of the rest of the arguments to the call. Anonymous authentication. AuthMethodanonymous
Roles Some functions may only be called by users with certain roles (see GetRoles), and others may return different information to different callers depending on the role(s) of the caller. The node and anonymous roles are pseudo-roles. A function that allows the node role may be called by automated scripts running on a node, such as the Boot and Node Managers. A function that allows the anonymous role may be called by anyone; an API authentication structure must still be specified (see ).
Filters Most of the Get methods take a filter argument. Filters may be arrays of integer (and sometimes string) identifiers, or a struct representing a filter on the attributes of the entities being queried. For example, >>> GetNodes([1,2,3]) >>> GetNodes({'node_id': [1,2,3]}) Would be equivalent queries. Attributes that are themselves arrays (such as interface_ids and slice_ids for nodes) cannot be used in filters. Filters support a few extra features illustrated in the following examples.
Pattern Matching * can be used in a text value and have the usual meaning, so all nodes in the fr can be obtained with: GetNodes ( { 'hostname' : '*.fr' } )
Negation Fields starting with a ~ are negated, so non-local nodes can be fetched with: GetNodes( { '~peer_id' : None } )
Numeric comparisons Strictly greater/smaller operations are achieved by prepending the field name like in: GetEvents( { '>time' : 1178531418 } ) Greater/smaller or equal: GetEvents( { ']event_id' : 2305 } )
Sorting and Clipping The following 3 special fields can be used to extract only a subset of the results for pagination: GetNodes( { '-SORT' : 'hostname' , '-OFFSET' : 30 , '-LIMIT' : 25 }
Tags The PLC API comes with a feature called tags, that basically aims at supporting an extensible data model. A few classes (as of this writing, Nodes, Interfaces and Slices) are eligible for being dynamically extended beyond the basic set of fields that are built into the database schema. Historically, this is a generalization of the concept of SliceAttribute , and the more recent concept of InterfaceSetting , that with release 5.0 have been renamed into SliceTag and InterfaceTag , respectively.
Low level The low level interface to tags relies on the following items: A TagType object basically models a new column that needs to be added to other objects. In much the same way as nodes are named through a hostname , tagtypes are named with a tagname, plus additional information (category, description) that is mostly informative. The convention is to use a category that depicts the type of objects that the tag type, like e.g. node/config You would then be allowed to attach a value to, say, a Node, by calling AddNodeTag , and then as usual change this value with UpdateNodeTag , or delete it with DeleteNodeTag .
Accessors A rather more convenient way to use tags is through Accessors. This convenience is located in PLC/Accessors , and allows you to easily define Get or Set methods dedicated to a given tag. This is for instance how the GetNodeArch and SetNodeArch methods are implemented. These methods greatly simplify tags manipulation as they take care of Lazily create TagTypes when needed, Create or update the, say, NodeTag object, as needed. Site-specific accessors can be defined in /usr/share/plc_api/PLC/Accessors/Accessors_site.py that will be preserved across updates of the PLCAPI rpm. This mechanism does not currently support setting slice tags that apply only on a given node or nodegroup.
Through regular Add/Get/Update methods Finally, tags may also get manipulated through the AddNode, GetNodes, and UpdateNode methods: The define_accessors function in the Accessors factory has an optional argument named expose_in_api . When this is set, the corresponding tag becomes visible from the Add/Get/Update methods almost as if it was a native tag. So for instance the following code would be legal and do as expected: # create a x86_64 node >>> AddNode({'hostname':'pl1.foo.com','arch':'x86_64'}) # get details for pl1.foo.com including tag 'arch' tag >>> GetNodes(['pl1.foo.com'],['boot_state','node_type','arch']) # set the 'deployment' tag >>> UpdateNode('pl1.foo.com',{'deployment':'beta'}) # get all alpha and beta nodes >>> GetNodes({'deployment':'*a'},['hostname','deployment']) The current limitation about tags as opposed to native fields is that, for performance, tags won't get returned when using the implicit set of columns. So for instance: # get all details for 'pl1.foo.com' >>> node=GetNodes(['pl1.foo.com'])[0] # this did not return the 'arch' tag >>> 'arch' in node False
Nodegroups In earlier versions up to v4.2, NodeGroups used to be defined extensively. So you would, basically, create an empty nodegroup instance, and then use AddNodeToNodeGroup or DeleteNodeFromNodeGroup to manage the nodegroup's contents. The new model has been redefined as follows. You now define a nodegroup as the set of nodes for which a given Tag has a given value, which are defined once and for good when creating the NodeGroup object. So for instance for managing the set of nodes that are running various levels of software code, PLC has defined two NodeGroups named alpha and beta . With the new model, we would now do something like the following, using the built-in deployment tag that is created for that purpose: >>> AddNodeGroup('alphanodes','deployment','alpha') 21 >>> AddNodeGroup('betanodes','deployment','beta') 21 >>> for ng in GetNodeGroups(['alphanodes','betanodes'],['groupname','node_ids']): print ng {'groupname': u'alphanodes', 'node_ids': []} {'groupname': u'betanodes', 'node_ids': []} >>> SetNodeDeployment('vnode01.inria.fr','alpha') >>> for ng in GetNodeGroups(['alphanodes','betanodes'],['groupname','node_ids']): print ng {'groupname': u'alphanodes', 'node_ids': [1]} {'groupname': u'betanodes', 'node_ids': []} >>> SetNodeDeployment('vnode01.inria.fr','beta') >>> for ng in GetNodeGroups(['alphanodes','betanodes'],['groupname','node_ids']): print ng {'groupname': u'alphanodes', 'node_ids': []} {'groupname': u'betanodes', 'node_ids': [1]}
PlanetLab shell A command-line program called plcsh simplifies authentication structure handling, and is useful for scripting. This program is distributed as a Linux RPM called PLCAPI and requires Python ≥2.4. usage: plcsh [options] options: -f CONFIG, --config=CONFIG PLC configuration file -h URL, --url=URL API URL -c CACERT, --cacert=CACERT API SSL certificate -k INSECURE, --insecure=INSECURE Do not check SSL certificate -m METHOD, --method=METHOD API authentication method -s SESSION, --session=SESSION API session key -u USER, --user=USER API user name -p PASSWORD, --password=PASSWORD API password -r ROLE, --role=ROLE API role -x, --xmlrpc Use XML-RPC interface --help show this help message and exit Specify at least the API URL and your user name: plcsh --url https://www.planet-lab.org/PLCAPI/ -u user@site.edu You will be presented with a prompt. From here, you can invoke API calls and omit the authentication structure, as it will be filled in automatically. user@site.edu connected using password authentication Type "system.listMethods()" or "help(method)" for more information. [user@site.edu]>>> AuthCheck() 1 [user@site.edu]>>> GetNodes([121], ['node_id', 'hostname']) [{'node_id': 121, 'hostname': 'planetlab-1.cs.princeton.edu'}] As this program is actually a Python interpreter, you may create variables, execute for loops, import other packages, etc., directly on the command line as you would using the regular Python shell. To use plcsh programmatically, import the PLC.Shell module: #!/usr/bin/python import sys # Default location that the PLCAPI RPM installs the PLC class sys.path.append('/usr/share/plc_api') # Initialize shell environment. Shell() will define all PLCAPI methods # in the specified namespace (specifying globals() will define them # globally). from PLC.Shell import Shell plc = Shell(globals(), url = "https://www.planet-lab.org/PLCAPI/", user = "user@site.edu", password = "password") # Both are equivalent nodes = GetNodes([121], ['node_id', 'hostname']) nodes = plc.GetNodes([121], ['node_id', 'hostname'])
Using regular python It is also possible to write simple regular-python scripts, as illustrated in the example below. The only difference with the examples above is that all API calls need to be passed a first argument for authentication. This example would write in a file the name of all the hosts attached to a given slice. #!/usr/bin/env python import xmlrpclib plc_host='www.planet-lab.eu' login='thierry.parmentelat@sophia.inria.fr' password='xxxxxxxx' slice_name='inria_heartbeat' auth = { 'AuthMethod' : 'password', 'Username' : login, 'AuthString' : password, } api_url="https://%s:443/PLCAPI/"%plc_host plc_api = xmlrpclib.ServerProxy(api_url,allow_none=True) # the slice's node ids node_ids = plc_api.GetSlices(auth,slice_name,['node_ids'])[0]['node_ids'] # get hostname for these nodes slice_nodes = plc_api.GetNodes(auth,node_ids,['hostname']) # store in a file f=open('mynodes.txt','w') for node in slice_nodes: print >>f,node['hostname'] f.close()
PlanetLab API Methods &Methods;