12 except (socket.error, IOError, OSError):
20 _expected_methods = set(
21 ['AddNodeTag', 'AddConfFile', 'DeletePersonTag', 'AddNodeType', 'DeleteBootState', 'SliceListNames', 'DeleteKey',
22 'SliceGetTicket', 'SliceUsersList', 'SliceUpdate', 'GetNodeGroups', 'SliceCreate', 'GetNetworkMethods', 'GetNodeFlavour',
23 'DeleteNode', 'BootNotifyOwners', 'AddPersonKey', 'AddNode', 'UpdateNodeGroup', 'GetAddressTypes', 'AddIlink', 'DeleteNetworkType',
24 'GetInitScripts', 'GenerateNodeConfFile', 'AddSite', 'BindObjectToPeer', 'SliceListUserSlices', 'GetPeers', 'AddPeer', 'DeletePeer',
25 'AddRole', 'DeleteRole', 'SetPersonPrimarySite', 'AddSiteAddress', 'SliceDelete', 'NotifyPersons', 'GetKeyTypes', 'GetConfFiles',
26 'GetIlinks', 'AddTagType', 'GetNodes', 'DeleteNodeTag', 'DeleteSliceFromNodesWhitelist', 'UpdateAddress', 'ResetPassword',
27 'AddSliceToNodesWhitelist', 'AddRoleToTagType', 'AddLeases', 'GetAddresses', 'AddInitScript', 'RebootNode', 'GetPCUTypes',
28 'RefreshPeer', 'GetBootMedium', 'UpdateKey', 'UpdatePCU', 'GetSession', 'AddInterfaceTag', 'UpdatePCUType', 'GetInterfaces',
29 'SliceExtendedInfo', 'SliceNodesList', 'DeleteRoleFromTagType', 'DeleteSlice', 'GetSites', 'DeleteMessage', 'GetSliceFamily',
30 'GetPlcRelease', 'UpdateTagType', 'AddSliceInstantiation', 'ResolveSlices', 'GetSlices', 'DeleteRoleFromPerson', 'GetSessions',
31 'UpdatePeer', 'VerifyPerson', 'GetPersonTags', 'DeleteKeyType', 'AddSlice', 'SliceUserAdd', 'DeleteSession', 'GetMessages',
32 'DeletePCU', 'GetPeerData', 'DeletePersonFromSite', 'DeleteTagType', 'GetPCUs', 'UpdateLeases', 'AddMessage',
33 'DeletePCUProtocolType', 'DeleteInterfaceTag', 'AddPersonToSite', 'GetSlivers', 'SliceNodesDel', 'DeleteAddressTypeFromAddress',
34 'AddNodeGroup', 'GetSliceTags', 'DeleteSite', 'GetSiteTags', 'UpdateMessage', 'DeleteSliceFromNodes', 'SliceRenew',
35 'UpdatePCUProtocolType', 'DeleteSiteTag', 'GetPCUProtocolTypes', 'GetEvents', 'GetSliceTicket', 'AddPersonTag', 'BootGetNodeDetails',
36 'DeleteInterface', 'DeleteNodeGroup', 'AddPCUProtocolType', 'BootCheckAuthentication', 'AddSiteTag', 'AddAddressTypeToAddress',
37 'DeleteConfFile', 'DeleteInitScript', 'DeletePerson', 'DeleteIlink', 'DeleteAddressType', 'AddBootState', 'AuthCheck',
38 'NotifySupport', 'GetSliceInstantiations', 'AddPCUType', 'AddPCU', 'AddSession', 'GetEventObjects', 'UpdateSiteTag',
39 'UpdateNodeTag', 'AddPerson', 'BlacklistKey', 'UpdateInitScript', 'AddSliceToNodes', 'RebootNodeWithPCU', 'GetNodeTags',
40 'GetSliceKeys', 'GetSliceSshKeys', 'AddNetworkMethod', 'SliceNodesAdd', 'DeletePersonFromSlice', 'ReportRunlevel',
41 'GetNetworkTypes', 'UpdateSite', 'DeleteConfFileFromNodeGroup', 'UpdateNode', 'DeleteSliceInstantiation', 'DeleteSliceTag',
42 'BootUpdateNode', 'UpdatePerson', 'UpdateConfFile', 'SliceUserDel', 'DeleteLeases', 'AddConfFileToNodeGroup', 'UpdatePersonTag',
43 'DeleteConfFileFromNode', 'AddPersonToSlice', 'UnBindObjectFromPeer', 'AddNodeToPCU', 'GetLeaseGranularity', 'DeletePCUType',
44 'GetTagTypes', 'GetNodeTypes', 'UpdateInterfaceTag', 'GetRoles', 'UpdateSlice', 'UpdateSliceTag', 'AddSliceTag', 'AddNetworkType',
45 'AddInterface', 'AddAddressType', 'AddRoleToPerson', 'DeleteNodeType', 'GetLeases', 'UpdateInterface', 'SliceInfo', 'DeleteAddress',
46 'SliceTicketGet', 'GetPersons', 'GetWhitelist', 'AddKeyType', 'UpdateAddressType', 'GetPeerName', 'DeleteNetworkMethod',
47 'UpdateIlink', 'AddConfFileToNode', 'GetKeys', 'DeleteNodeFromPCU', 'GetInterfaceTags', 'GetBootStates', 'SetInterfaceSens', 'SetNodeLoadm',
48 'GetInterfaceRate', 'GetNodeLoadw', 'SetInterfaceKey', 'GetNodeSlices', 'GetNodeLoadm', 'SetSliceVref', 'GetInterfaceIwpriv', 'SetNodeLoadw',
49 'SetNodeSerial', 'GetNodePlainBootstrapfs', 'SetNodeMEMw', 'GetNodeResponse', 'SetInterfaceRate', 'SetSliceInitscript',
50 'SetNodeFcdistro', 'GetNodeLoady', 'SetNodeArch', 'SetNodeKargs', 'SetNodeMEMm', 'SetNodeBWy', 'SetNodeBWw',
51 'SetInterfaceSecurityMode', 'SetNodeBWm', 'SetNodeASType', 'GetNodeKargs', 'GetPersonColumnconf', 'GetNodeResponsem',
52 'GetNodeCPUy', 'GetNodeCramfs', 'SetNodeSlicesw', 'SetPersonColumnconf', 'SetNodeSlicesy', 'GetNodeCPUw', 'GetNodeBWy',
53 'GetNodeCPUm', 'GetInterfaceDriver', 'GetNodeLoad', 'GetInterfaceMode', 'GetNodeSerial', 'SetNodeSlicesm', 'SetNodeLoady',
54 'GetNodeReliabilityw', 'SetSliceFcdistro', 'GetNodeReliabilityy', 'SetInterfaceEssid', 'SetSliceInitscriptCode',
55 'GetNodeExtensions', 'GetSliceOmfControl', 'SetNodeCity', 'SetInterfaceIfname', 'SetNodeHrn', 'SetNodeNoHangcheck',
56 'GetNodeNoHangcheck', 'GetSliceFcdistro', 'SetNodeCountry', 'SetNodeKvariant', 'GetNodeKvariant', 'GetNodeMEMy',
57 'SetInterfaceIwpriv', 'GetNodeMEMw', 'SetInterfaceBackdoor', 'GetInterfaceFreq', 'SetInterfaceChannel', 'SetInterfaceNw',
58 'GetPersonShowconf', 'GetSliceInitscriptCode', 'SetNodeMEM', 'GetInterfaceEssid', 'GetNodeMEMm', 'SetInterfaceMode',
59 'SetInterfaceIwconfig', 'GetNodeSlicesm', 'GetNodeBWm', 'SetNodePlainBootstrapfs', 'SetNodeRegion', 'SetNodeCPU',
60 'GetNodeSlicesw', 'SetNodeBW', 'SetNodeSlices', 'SetNodeCramfs', 'GetNodeSlicesy', 'GetInterfaceKey', 'GetSliceInitscript',
61 'SetNodeCPUm', 'SetSliceArch', 'SetNodeLoad', 'SetNodeResponse', 'GetSliceSliverHMAC', 'GetNodeBWw', 'GetNodeRegion',
62 'SetNodeMEMy', 'GetNodeASType', 'SetNodePldistro', 'GetSliceArch', 'GetNodeCountry', 'SetSliceOmfControl', 'GetNodeHrn',
63 'GetNodeCity', 'SetInterfaceAlias', 'GetNodeBW', 'GetNodePldistro', 'GetSlicePldistro', 'SetNodeASNumber', 'GetSliceHmac',
64 'SetSliceHmac', 'GetNodeMEM', 'GetNodeASNumber', 'GetInterfaceAlias', 'GetSliceVref', 'GetNodeArch', 'GetSliceSshKey',
65 'GetInterfaceKey4', 'GetInterfaceKey2', 'GetInterfaceKey3', 'GetInterfaceKey1', 'GetInterfaceBackdoor', 'GetInterfaceIfname',
66 'SetSliceSliverHMAC', 'SetNodeReliability', 'GetNodeCPU', 'SetPersonShowconf', 'SetNodeExtensions', 'SetNodeCPUy',
67 'SetNodeCPUw', 'GetNodeResponsew', 'SetNodeResponsey', 'GetInterfaceSens', 'SetNodeResponsew', 'GetNodeResponsey',
68 'GetNodeReliability', 'GetNodeReliabilitym', 'SetNodeResponsem', 'SetInterfaceDriver', 'GetInterfaceSecurityMode',
69 'SetNodeDeployment', 'SetNodeReliabilitym', 'GetNodeFcdistro', 'SetInterfaceFreq', 'GetInterfaceNw', 'SetNodeReliabilityy',
70 'SetNodeReliabilityw', 'GetInterfaceIwconfig', 'SetSlicePldistro', 'SetSliceSshKey', 'GetNodeDeployment', 'GetInterfaceChannel',
71 'SetInterfaceKey2', 'SetInterfaceKey3', 'SetInterfaceKey1', 'SetInterfaceKey4'])
73 _required_methods = set()
75 def __init__(self, username=None, password=None, sessionkey=None,
76 hostname = "www.planet-lab.eu",
77 urlpattern = "https://%(hostname)s:443/PLCAPI/",
78 localPeerName = "PLE"):
79 if sessionkey is not None:
80 self.auth = dict(AuthMethod='session', session=sessionkey)
81 elif username is not None and password is not None:
82 self.auth = dict(AuthMethod='password', Username=username, AuthString=password)
84 self.auth = dict(AuthMethod='anonymous')
86 self._localPeerName = localPeerName
87 self._url = urlpattern % {'hostname':hostname}
89 self.threadlocal = threading.local()
93 # Cannot reuse same proxy in all threads, py2.7 is not threadsafe
94 return xmlrpclib.ServerProxy(
101 return self.threadlocal.mc
102 except AttributeError:
108 # validate XMLRPC server checking supported API calls
109 methods = set(_retry(self.mcapi.system.listMethods)())
110 if self._required_methods - methods:
111 warnings.warn("Unsupported REQUIRED methods: %s" % ( ", ".join(sorted(self._required_methods - methods)), ) )
113 if self._expected_methods - methods:
114 warnings.warn("Unsupported EXPECTED methods: %s" % ( ", ".join(sorted(self._expected_methods - methods)), ) )
118 network_types = _retry(self.mcapi.GetNetworkTypes)(self.auth)
119 except (xmlrpclib.ProtocolError, xmlrpclib.Fault),e:
120 warnings.warn(str(e))
126 def network_types(self):
128 return self._network_types
129 except AttributeError:
130 self._network_types = _retry(self.mcapi.GetNetworkTypes)(self.auth)
131 return self._network_types
136 return self._peer_map
137 except AttributeError:
138 peers = _retry(self.mcapi.GetPeers)(self.auth, {}, ['shortname','peername','peer_id'])
139 self._peer_map = dict(
140 (peer['shortname'], peer['peer_id'])
143 self._peer_map.update(
144 (peer['peername'], peer['peer_id'])
147 self._peer_map.update(
148 (peer['peer_id'], peer['shortname'])
151 self._peer_map[None] = self._localPeerName
152 return self._peer_map
155 def GetNodeFlavour(self, node):
157 Returns detailed information on a given node's flavour, i.e. its base installation.
159 This depends on the global PLC settings in the PLC_FLAVOUR area, optionnally overridden by any of the following tags if set on that node:
160 'arch', 'pldistro', 'fcdistro', 'deployment', 'extensions'
164 * node : int or string
165 - int, Node identifier
166 - string, Fully qualified hostname
171 * extensions : array of string, extensions to add to the base install
172 * fcdistro : string, the fcdistro this node should be based upon
173 * nodefamily : string, the nodefamily this node should be based upon
174 * plain : boolean, use plain bootstrapfs image if set (for tests)
176 if not isinstance(node, (str, int, long)):
177 raise ValueError, "Node must be either a non-unicode string or an int"
178 return _retry(self.mcapi.GetNodeFlavour)(self.auth, node)
180 def GetNodes(self, nodeIdOrName=None, fields=None, **kw):
182 Returns an array of structs containing details about nodes.
183 If nodeIdOrName is specified and is an array of node identifiers or hostnames,
184 or the filters keyword argument with struct of node attributes,
185 or node attributes by keyword argument,
186 only nodes matching the filter will be returned.
188 If fields is specified, only the specified details will be returned.
189 NOTE that if fields is unspecified, the complete set of native fields are returned,
190 which DOES NOT include tags at this time.
192 Some fields may only be viewed by admins.
196 fields: an optional list of fields to retrieve. The default is all.
198 filters: an optional mapping with custom filters, which is the only
199 way to support complex filters like negation and numeric comparisons.
201 peer: a string (or sequence of strings) with the name(s) of peers
202 to filter - or None for local nodes.
204 if fields is not None:
205 fieldstuple = (fields,)
208 if nodeIdOrName is not None:
209 return _retry(self.mcapi.GetNodes)(self.auth, nodeIdOrName, *fieldstuple)
211 filters = kw.pop('filters',{})
214 peer = kw.pop('peer')
216 nameToId = self.peer_map.get
218 if hasattr(peer, '__iter__'):
219 # we can't mix local and external nodes, so
220 # split and re-issue recursively in that case
221 if None in peer or self._localPeerName in peer:
224 if self._localPeerName in peer:
225 peer.remove(self._localPeerName)
227 self.GetNodes(nodeIdOrName, fields, filters=filters, peer=peer, **kw)
228 + self.GetNodes(nodeIdOrName, fields, filters=filters, peer=None, **kw)
231 peer_filter = map(nameToId, peer)
232 elif peer is None or peer == self._localPeerName:
235 peer_filter = nameToId(peer)
237 filters['peer_id'] = peer_filter
240 return _retry(self.mcapi.GetNodes)(self.auth, filters, *fieldstuple)
242 def GetNodeTags(self, nodeTagId=None, fields=None, **kw):
243 if fields is not None:
244 fieldstuple = (fields,)
247 if nodeTagId is not None:
248 return _retry(self.mcapi.GetNodeTags)(self.auth, nodeTagId, *fieldstuple)
250 filters = kw.pop('filters',{})
252 return _retry(self.mcapi.GetNodeTags)(self.auth, filters, *fieldstuple)
254 def GetSliceTags(self, sliceTagId=None, fields=None, **kw):
255 if fields is not None:
256 fieldstuple = (fields,)
259 if sliceTagId is not None:
260 return _retry(self.mcapi.GetSliceTags)(self.auth, sliceTagId, *fieldstuple)
262 filters = kw.pop('filters',{})
264 return _retry(self.mcapi.GetSliceTags)(self.auth, filters, *fieldstuple)
267 def GetInterfaces(self, interfaceIdOrIp=None, fields=None, **kw):
268 if fields is not None:
269 fieldstuple = (fields,)
272 if interfaceIdOrIp is not None:
273 return _retry(self.mcapi.GetInterfaces)(self.auth, interfaceIdOrIp, *fieldstuple)
275 filters = kw.pop('filters',{})
277 return _retry(self.mcapi.GetInterfaces)(self.auth, filters, *fieldstuple)
279 def GetSlices(self, sliceIdOrName=None, fields=None, **kw):
280 if fields is not None:
281 fieldstuple = (fields,)
284 if sliceIdOrName is not None:
285 return _retry(self.mcapi.GetSlices)(self.auth, sliceIdOrName, *fieldstuple)
287 filters = kw.pop('filters',{})
289 return _retry(self.mcapi.GetSlices)(self.auth, filters, *fieldstuple)
291 def UpdateSlice(self, sliceIdOrName, **kw):
292 return _retry(self.mcapi.UpdateSlice)(self.auth, sliceIdOrName, kw)
295 def StartMulticall(self):
296 self.threadlocal.mc = xmlrpclib.MultiCall(self.mcapi)
298 def FinishMulticall(self):
299 mc = self.threadlocal.mc
300 del self.threadlocal.mc
303 def GetSliceNodes(self, slicename):
304 return self.GetSlices(slicename, ['node_ids'])[0]['node_ids']
306 def AddSliceNodes(self, slicename, nodes = None):
307 self.UpdateSlice(slicename, nodes = nodes)
309 def GetNodeInfo(self, node_id):
310 self.StartMulticall()
311 info = self.GetNodes(node_id)
312 tags = self.GetNodeTags(node_id=node_id, fields=('tagname','value'))
313 info, tags = self.FinishMulticall()
316 def GetSliceId(self, slicename):
318 slices = self.GetSlices(slicename, fields=('slice_id',))
320 slice_id = slices[0]['slice_id']
323 def plcapi(auth_user, auth_string, plc_host, plc_url):
327 username = auth_user,
328 password = auth_string,
333 # anonymous access - may not be enough for much