1 <?xml version="1.0" encoding="UTF-8"?>
3 <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
5 <!ENTITY Methods SYSTEM "Methods.xml">
10 <title>PlanetLab Central API Documentation</title>
13 <chapter id="Introduction">
14 <title>Introduction</title>
16 <para>The PlanetLab Central API (PLCAPI) is the interface through
17 which the PlanetLab Central database should be accessed and
18 maintained. The API is used by the website, by nodes, by automated
19 scripts, and by users to access and update information about
20 users, nodes, sites, slices, and other entities maintained by the
23 <section id="Authentication">
24 <title>Authentication</title>
26 <para>The API should be accessed via XML-RPC over HTTPS. The API
27 supports the standard introspection calls <link
28 linkend="system.listMethods">system.listMethods</link>, <link
29 linkend="system.methodSignature">system.methodSignature</link>,
30 and <link linkend="system.methodHelp">system.methodHelp</link>,
31 and the standard batching call <link
32 linkend="system.multicall">system.multicall</link>. With the
33 exception of these calls, all PLCAPI calls take an
34 authentication structure as their first argument. All
35 authentication structures require the specification of
36 <parameter>AuthMethod</parameter>. If the documentation for a
37 call does not further specify the authentication structure, then
38 any of (but only) the following authentication structures may be
43 <para>Session authentication. User sessions are typically
44 valid for 24 hours. Node sessions are valid until the next
45 reboot. Obtain a session key with <link
46 linkend="GetSession">GetSession</link> using another form of
47 authentication, such as password or GnuPG
48 authentication.</para>
49 <informaltable frame="none" rules="rows">
52 <row><entry>AuthMethod</entry><entry><literal>session</literal></entry></row>
53 <row><entry>session</entry><entry>Session key</entry></row>
59 <para>Password authentication.</para>
60 <informaltable frame="none" rules="rows">
63 <row><entry>AuthMethod</entry><entry><literal>password</literal></entry></row>
64 <row><entry>Username</entry><entry>Username, typically an e-mail address</entry></row>
65 <row><entry>AuthString</entry><entry>Authentication string, typically a password</entry></row>
71 <para>GnuPG authentication. Users may upload a GPG public key
72 using <link linkend="AddPersonKey">AddPersonKey</link>. Peer
73 GPG keys should be added with <link
74 linkend="AddPeer">AddPeer</link> or <link
75 linkend="UpdatePeer">UpdatePeer</link>.
77 <informaltable frame="none" rules="rows">
80 <row><entry>AuthMethod</entry><entry><literal>gpg</literal></entry></row>
81 <row><entry>name</entry><entry>Peer or user name</entry></row>
82 <row><entry>signature</entry><entry>GnuPG signature of
84 url="http://www.w3.org/TR/xml-c14n">canonicalized</ulink>
85 <ulink url="http://www.xmlrpc.com/spec">XML-RPC</ulink>
86 representation of the rest of the arguments to the
93 <para>Anonymous authentication.</para>
94 <informaltable frame="none" rules="rows">
97 <row><entry>AuthMethod</entry><entry><literal>anonymous</literal></entry></row>
108 <para>Some functions may only be called by users with certain
109 roles (see <link linkend="GetRoles">GetRoles</link>), and others
110 may return different information to different callers depending
111 on the role(s) of the caller.</para>
113 <para>The <literal>node</literal> and
114 <literal>anonymous</literal> roles are pseudo-roles. A function
115 that allows the <literal>node</literal> role may be called by
116 automated scripts running on a node, such as the Boot and Node
117 Managers. A function that allows the
118 <literal>anonymous</literal> role may be called by anyone; an
119 API authentication structure must still be specified (see <xref
120 linkend="Authentication"/>).</para>
123 <section id="Filters">
124 <title>Filters</title>
126 <para>Most of the <function>Get</function> methods take a
127 filter argument. Filters may be arrays of integer (and sometimes
128 string) identifiers, or a struct representing a filter on the
129 attributes of the entities being queried. For example,
132 >>> GetNodes([1,2,3])
133 >>> GetNodes({'node_id': [1,2,3]})
137 <para>Would be equivalent queries. Attributes that are
138 themselves arrays (such as <literal>interface_ids</literal>
139 and <literal>slice_ids</literal> for nodes) cannot be used in
142 <para> Filters support a few extra features illustrated in the following examples.</para>
144 <section id="pattern-matching">
145 <title> Pattern Matching</title>
146 <para> <literal>*</literal> can be used in a text value and have the usual meaning, so all nodes in the <emphasis>fr</emphasis> can be obtained with:
147 <programlisting>GetNodes ( { 'hostname' : '*.fr' } ) </programlisting>
151 <section id="negation">
152 <title> Negation </title>
153 <para> Fields starting with a <literal>~</literal> are negated, so non-local nodes can be fetched with:
154 <programlisting>GetNodes( { '~peer_id' : None } ) </programlisting>
158 <section id="numeric">
159 <title> Nueric comparisons </title>
160 <para> Strictly greater/smaller operations are achieved by prepending the field name like in:
161 <programlisting>GetEvents( { '>time' : 1178531418 } ) </programlisting>
163 <para> Greater/smaller or equal:
164 <programlisting>GetEvents( { ']event_id' : 2305 } ) </programlisting>
168 <section id="sort-clip">
169 <title> Sorting and Clipping </title>
170 <para> The following 3 special fields can be used to extract only a subset of the results for pagination:
171 <programlisting> GetNodes( { '-SORT' : 'hostname' , '-OFFSET' : 30 , '-LIMIT' : 25 }</programlisting>
179 <para> The PLC API comes with a feature called
180 <emphasis>tags</emphasis>, that basically aims at supporting an
181 extensible data model. A few classes (as of this writing, Nodes,
182 Interfaces and Slices) are eligible for being dynamically
183 extended beyond the basic set of fields that are built into the
184 database schema.</para>
186 <para> Historically, this is a generalization of the concept of
187 <emphasis> SliceAttribute </emphasis>, and the more recent
188 concept of <emphasis> InterfaceSetting </emphasis>, that with
189 release 5.0 have been renamed into <emphasis> SliceTag
190 </emphasis> and <emphasis> InterfaceTag </emphasis>,
191 respectively. </para>
193 <section id="tags-low-level">
194 <title> Low level </title>
195 <para> The low level interface to tags relies on the following items:
199 A <emphasis> TagType </emphasis> object basically models a
200 new column that needs to be added to other objects. In
201 much the same way as nodes are named through a <emphasis>
202 hostname </emphasis>, tagtypes are named with a
203 <emphasis>tagname</emphasis>, plus additional information
204 (category, description) that is mostly informative. The
205 convention is to use a category that depicts the type of
206 objects that the tag type, like e.g. <emphasis>
207 node/config </emphasis>
211 <para> You would then be allowed to attach a value to, say,
212 a Node, by calling <emphasis> AddNodeTag </emphasis>, and
213 then as usual change this value with <emphasis>
214 UpdateNodeTag </emphasis>, or delete it with <emphasis>
215 DeleteNodeTag </emphasis>. </para>
221 <section id="accessors">
222 <title> Accessors </title>
223 <para> A rather more convenient way to use tags is through
224 Accessors. This convenience is located in <emphasis>
225 PLC/Accessors </emphasis>, and allows you to easily define Get
226 or Set methods dedicated to a given tag. This is for instance
227 how the <emphasis> GetNodeArch </emphasis> and <emphasis>
228 SetNodeArch </emphasis> methods are implemented. These methods
229 greatly simplify tags manipulation as they take care of
232 <para> Lazily create <emphasis> TagTypes </emphasis> when
236 <para> Create or update the, say, <emphasis> NodeTag
237 </emphasis> object, as needed.</para>
241 <para> <emphasis> Site-specific </emphasis> accessors can be
242 defined in <emphasis>
243 /usr/share/plc_api/PLC/Accessors/Accessors_site.py </emphasis>
244 that will be preserved across updates of the PLCAPI rpm.
247 This mechanism does not currently support setting slice
248 tags that apply only on a given node or nodegroup.
252 <section id="expose-in-api">
253 <title> Through regular Add/Get/Update methods </title>
255 Finally, tags may also get manipulated through the
256 <emphasis>AddNode</emphasis>, <emphasis>GetNodes</emphasis>,
257 and <emphasis>UpdateNode</emphasis> methods:
261 The <literal>define_accessors</literal> function in the
262 Accessors factory has an optional argument named <literal>
263 expose_in_api </literal>. When this is set, the
264 corresponding tag becomes visible from the Add/Get/Update
265 methods almost as if it was a native tag.
269 So for instance the following code would be legal and do as expected:
271 # create a x86_64 node
272 >>> AddNode({'hostname':'pl1.foo.com','arch':'x86_64'})
273 # get details for pl1.foo.com including tag 'arch' tag
274 >>> GetNodes(['pl1.foo.com'],['boot_state','node_type','arch'])
275 # set the 'deployment' tag
276 >>> UpdateNode('pl1.foo.com',{'deployment':'beta'})
277 # get all alpha and beta nodes
278 >>> GetNodes({'deployment':'*a'},['hostname','deployment'])
283 The current limitation about tags as opposed to native
284 fields is that, for performance, tags won't get returned
285 when using the implicit set of columns. So for instance:
287 # get all details for 'pl1.foo.com'
288 >>> node=GetNodes(['pl1.foo.com'])[0]
289 # this did not return the 'arch' tag
300 <section id="nodegroups">
301 <title>Nodegroups</title>
303 <para> In earlier versions up to v4.2, <emphasis> NodeGroups
304 </emphasis> used to be defined extensively. So you would,
305 basically, create an empty nodegroup instance, and then use
306 <emphasis> AddNodeToNodeGroup </emphasis> or <emphasis>
307 DeleteNodeFromNodeGroup </emphasis> to manage the nodegroup's
310 <para> The new model has been redefined as follows. You now define
311 a nodegroup as the set of nodes for which a given <emphasis> Tag
312 </emphasis> has a given value, which are defined once and for good
313 when creating the <emphasis> NodeGroup </emphasis> object. </para>
315 <para> So for instance for managing the set of nodes that are
316 running various levels of software code, PLC has defined two
317 <emphasis> NodeGroups </emphasis> named <literal> alpha </literal>
318 and <literal> beta </literal>. With the new model, we would now do
319 something like the following, using the built-in <literal>
320 deployment </literal> tag that is created for that purpose:
322 >>> AddNodeGroup('alphanodes','deployment','alpha')
324 >>> AddNodeGroup('betanodes','deployment','beta')
326 >>> for ng in GetNodeGroups(['alphanodes','betanodes'],['groupname','node_ids']): print ng
327 {'groupname': u'alphanodes', 'node_ids': []}
328 {'groupname': u'betanodes', 'node_ids': []}
329 >>> SetNodeDeployment('vnode01.inria.fr','alpha')
330 >>> for ng in GetNodeGroups(['alphanodes','betanodes'],['groupname','node_ids']): print ng
331 {'groupname': u'alphanodes', 'node_ids': [1]}
332 {'groupname': u'betanodes', 'node_ids': []}
333 >>> SetNodeDeployment('vnode01.inria.fr','beta')
334 >>> for ng in GetNodeGroups(['alphanodes','betanodes'],['groupname','node_ids']): print ng
335 {'groupname': u'alphanodes', 'node_ids': []}
336 {'groupname': u'betanodes', 'node_ids': [1]}
343 <title>PlanetLab shell</title>
345 <para>A command-line program called <command>plcsh</command>
346 simplifies authentication structure handling, and is useful for
347 scripting. This program is distributed as a Linux RPM called
348 PLCAPI and requires Python ≥2.4.</para>
351 usage: plcsh [options]
354 -f CONFIG, --config=CONFIG
355 PLC configuration file
356 -h URL, --url=URL API URL
357 -c CACERT, --cacert=CACERT
359 -k INSECURE, --insecure=INSECURE
360 Do not check SSL certificate
361 -m METHOD, --method=METHOD
362 API authentication method
363 -s SESSION, --session=SESSION
365 -u USER, --user=USER API user name
366 -p PASSWORD, --password=PASSWORD
368 -r ROLE, --role=ROLE API role
369 -x, --xmlrpc Use XML-RPC interface
370 --help show this help message and exit
373 <para>Specify at least the API URL and your user name:</para>
376 plcsh --url https://www.planet-lab.org/PLCAPI/ -u user@site.edu
379 <para>You will be presented with a prompt. From here, you can
380 invoke API calls and omit the authentication structure, as it will
381 be filled in automatically.</para>
384 user@site.edu connected using password authentication
385 Type "system.listMethods()" or "help(method)" for more information.
386 [user@site.edu]>>> AuthCheck()
388 [user@site.edu]>>> GetNodes([121], ['node_id', 'hostname'])
389 [{'node_id': 121, 'hostname': 'planetlab-1.cs.princeton.edu'}]
392 <para>As this program is actually a Python interpreter, you may
393 create variables, execute for loops, import other packages, etc.,
394 directly on the command line as you would using the regular Python
397 <para>To use <command>plcsh</command> programmatically, import
398 the <function>PLC.Shell</function> module:</para>
405 # Default location that the PLCAPI RPM installs the PLC class
406 sys.path.append('/usr/share/plc_api')
408 # Initialize shell environment. Shell() will define all PLCAPI methods
409 # in the specified namespace (specifying globals() will define them
411 from PLC.Shell import Shell
412 plc = Shell(globals(),
413 url = "https://www.planet-lab.org/PLCAPI/",
414 user = "user@site.edu",
415 password = "password")
417 # Both are equivalent
418 nodes = GetNodes([121], ['node_id', 'hostname'])
419 nodes = plc.GetNodes([121], ['node_id', 'hostname'])
423 <section id='standalone'>
424 <title>Using regular python</title>
426 <para>It is also possible to write simple regular-python scripts,
427 as illustrated in the example below. The only difference with the
428 examples above is that all API calls need to be passed a first
429 argument for authentication. This example would write in a file
430 the name of all the hosts attached to a given slice.</para>
433 #!/usr/bin/env python
437 plc_host='www.planet-lab.eu'
438 login='thierry.parmentelat@sophia.inria.fr'
441 slice_name='inria_heartbeat'
443 auth = { 'AuthMethod' : 'password',
445 'AuthString' : password,
448 api_url="https://%s:443/PLCAPI/"%plc_host
450 plc_api = xmlrpclib.ServerProxy(api_url,allow_none=True)
452 # the slice's node ids
453 node_ids = plc_api.GetSlices(auth,slice_name,['node_ids'])[0]['node_ids']
455 # get hostname for these nodes
456 slice_nodes = plc_api.GetNodes(auth,node_ids,['hostname'])
459 f=open('mynodes.txt','w')
460 for node in slice_nodes:
461 print >>f,node['hostname']
468 <chapter id="Methods">
469 <title>PlanetLab API Methods</title>
477 <!-- LocalWords: PlanetLab API PLCAPI RPC HTTPS listMethods methodSignature
479 <!-- LocalWords: methodHelp multicall AuthMethod GetSession GnuPG Username GPG
481 <!-- LocalWords: AuthString AddPersonKey AddPeer UpdatePeer gpg