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)
266 def GetInterfaces(self, interfaceIdOrIp=None, fields=None, **kw):
267 if fields is not None:
268 fieldstuple = (fields,)
271 if interfaceIdOrIp is not None:
272 return _retry(self.mcapi.GetInterfaces)(self.auth, interfaceIdOrIp, *fieldstuple)
274 filters = kw.pop('filters',{})
276 return _retry(self.mcapi.GetInterfaces)(self.auth, filters, *fieldstuple)
278 def GetSlices(self, sliceIdOrName=None, fields=None, **kw):
279 if fields is not None:
280 fieldstuple = (fields,)
283 if sliceIdOrName is not None:
284 return _retry(self.mcapi.GetSlices)(self.auth, sliceIdOrName, *fieldstuple)
286 filters = kw.pop('filters',{})
288 return _retry(self.mcapi.GetSlices)(self.auth, filters, *fieldstuple)
290 def UpdateSlice(self, sliceIdOrName, **kw):
291 return _retry(self.mcapi.UpdateSlice)(self.auth, sliceIdOrName, kw)
293 def StartMulticall(self):
294 self.threadlocal.mc = xmlrpclib.MultiCall(self.mcapi)
296 def FinishMulticall(self):
297 mc = self.threadlocal.mc
298 del self.threadlocal.mc
301 def GetSliceNodes(self, slicename):
302 return self.GetSlices(slicename, ['node_ids'])[0]['node_ids']
304 def AddSliceNodes(self, slicename, nodes = None):
305 self.UpdateSlice(slicename, nodes = nodes)
307 def GetNodeInfo(self, node_id):
308 self.StartMulticall()
309 info = self.GetNodes(node_id)
310 tags = self.GetNodeTags(node_id=node_id, fields=('tagname','value'))
311 info, tags = self.FinishMulticall()
314 def GetSliceId(self, slicename):
316 slices = self.GetSlices(slicename, fields=('slice_id',))
318 slice_id = slices[0]['slice_id']
319 # If it wasn't found, don't remember this failure, keep trying
322 def GetSliceVnetSysTag(self, slicename):
323 slicetags = self.GetSliceTags(
325 tagname = 'vsys_vnet',
328 return slicetags[0]['value']
332 def plcapi(auth_user, auth_string, plc_host, plc_url):
336 username = auth_user,
337 password = auth_string,
342 # anonymous access - may not be enough for much