X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=src%2Fnepi%2Fresources%2Fplanetlab%2Fplcapi.py;h=d2970e8c733b461f04c6f0d1010122243266335d;hb=6285ca51026efb69642eea9dfc7c480e722d84a9;hp=25ac4d78c1845e36d39a05bf257b8a1c72d931ec;hpb=62a8f5c90afe9033f532206c811cff8ea76b2c09;p=nepi.git diff --git a/src/nepi/resources/planetlab/plcapi.py b/src/nepi/resources/planetlab/plcapi.py index 25ac4d78..d2970e8c 100644 --- a/src/nepi/resources/planetlab/plcapi.py +++ b/src/nepi/resources/planetlab/plcapi.py @@ -3,9 +3,8 @@ # Copyright (C) 2013 INRIA # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation; # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -20,6 +19,7 @@ import functools import hashlib import socket +import os import time import threading import xmlrpclib @@ -135,15 +135,15 @@ class PLCAPI(object): _required_methods = set() - def __init__(self, username = None, password = None, session_key = None, - proxy = None, - hostname = "www.planet-lab.eu", - urlpattern = "https://%(hostname)s:443/PLCAPI/", + def __init__(self, username, password, hostname, urlpattern, ec, proxy, session_key = None, local_peer = "PLE"): self._blacklist = set() self._reserved = set() self._nodes_cache = None + self._already_cached = False + self._ecobj = ec + self.count = 1 if session_key is not None: self.auth = dict(AuthMethod='session', session=session_key) @@ -174,7 +174,11 @@ class PLCAPI(object): self._proxy_transport = lambda : None self.threadlocal = threading.local() - + + # Load blacklist from file + if self._ecobj.get_global('planetlab::Node', 'persist_blacklist'): + self._set_blacklist() + @property def api(self): # Cannot reuse same proxy in all threads, py2.7 is not threadsafe @@ -191,6 +195,7 @@ class PLCAPI(object): return self.api def test(self): + # TODO: Use nepi utils Logger instead of warning!! import warnings # validate XMLRPC server checking supported API calls @@ -207,10 +212,20 @@ class PLCAPI(object): try: # test authorization network_types = _retry(self.mcapi.GetNetworkTypes)(self.auth) - except (xmlrpclib.ProtocolError, xmlrpclib.Fault),e: + except (xmlrpclib.ProtocolError, xmlrpclib.Fault) as e: warnings.warn(str(e)) return True + + def _set_blacklist(self): + nepi_home = os.path.join(os.path.expanduser("~"), ".nepi") + plblacklist_file = os.path.join(nepi_home, "plblacklist.txt") + with open(plblacklist_file, 'r') as f: + hosts_tobl = f.read().splitlines() + if hosts_tobl: + nodes_id = self.get_nodes(hosts_tobl, ['node_id']) + for node_id in nodes_id: + self._blacklist.add(node_id['node_id']) @property def network_types(self): @@ -269,7 +284,7 @@ class PLCAPI(object): * plain : boolean, use plain bootstrapfs image if set (for tests) """ if not isinstance(node, (str, int, long)): - raise ValueError, "Node must be either a non-unicode string or an int" + raise ValueError("Node must be either a non-unicode string or an int") return _retry(self.mcapi.GetNodeFlavour)(self.auth, node) def get_nodes(self, node_id_or_name = None, fields = None, **kw): @@ -340,8 +355,12 @@ class PLCAPI(object): filters.update(kw) if not filters and not fieldstuple: - if not self._nodes_cache: + if not self._nodes_cache and not self._already_cached: + self._already_cached = True self._nodes_cache = _retry(self.mcapi.GetNodes)(self.auth) + elif not self._nodes_cache: + while not self._nodes_cache: + time.sleep(10) return self._nodes_cache return _retry(self.mcapi.GetNodes)(self.auth, filters, *fieldstuple) @@ -409,6 +428,9 @@ class PLCAPI(object): def update_slice(self, slice_id_or_name, **kw): return _retry(self.mcapi.UpdateSlice)(self.auth, slice_id_or_name, kw) + def delete_slice_node(self, slice_id_or_name, node_id_or_hostname): + return _retry(self.mcapi.DeleteSliceFromNodes)(self.auth, slice_id_or_name, node_id_or_hostname) + def start_multicall(self): self.threadlocal.mc = xmlrpclib.MultiCall(self.mcapi) @@ -420,8 +442,8 @@ class PLCAPI(object): def get_slice_nodes(self, slicename): return self.get_slices(slicename, ['node_ids'])[0]['node_ids'] - def add_slice_nodes(self, slicename, nodes = None): - self.update_slice(slicename, nodes = nodes) + def add_slice_nodes(self, slicename, nodes): + self.update_slice(slicename, nodes=nodes) def get_node_info(self, node_id): self.start_multicall() @@ -450,24 +472,44 @@ class PLCAPI(object): else: return None - def blacklist_host(self, hostname): - self._blacklist.add(hostname) + def blacklist_host(self, node_id): + self._blacklist.add(node_id) def blacklisted(self): - return self._blacklist + return self._blacklist - def unblacklist_host(self, hostname): - del self._blacklist[hostname] + def unblacklist_host(self, node_id): + del self._blacklist[node_id] - def reserve_host(self, hostname): - self._reserved.add(hostname) + def reserve_host(self, node_id): + self._reserved.add(node_id) def reserved(self): return self._reserved - def unreserve_host(self, hostname): - del self._reserved[hostname] - + def unreserve_host(self, node_id): + del self._reserved[node_id] + + def release(self): + self.count -= 1 + if self.count == 0: + blacklist = self._blacklist + self._blacklist = set() + self._reserved = set() + if self._ecobj.get_global('PlanetlabNode', 'persist_blacklist'): + if blacklist: + to_blacklist = list() + hostnames = self.get_nodes(list(blacklist), ['hostname']) + for hostname in hostnames: + to_blacklist.append(hostname['hostname']) + + nepi_home = os.path.join(os.path.expanduser("~"), ".nepi") + plblacklist_file = os.path.join(nepi_home, "plblacklist.txt") + + with open(plblacklist_file, 'w') as f: + for host in to_blacklist: + f.write("%s\n" % host) + class PLCAPIFactory(object): """ @@ -482,13 +524,12 @@ class PLCAPIFactory(object): _apis = dict() @classmethod - def get_api(cls, slicename, pl_pass, pl_host, - pl_ptn = "https://%(hostname)s:443/PLCAPI/", - proxy = None): + def get_api(cls, pl_user, pl_pass, pl_host, + pl_ptn, ec, proxy = None): """ Get existing PLCAPI instance - :param slicename: Planelab slice name - :type slicename: str + :param pl_user: Planelab user name (used for web login) + :type pl_user: str :param pl_pass: Planetlab password (used for web login) :type pl_pass: str :param pl_host: Planetlab registry host (e.g. "www.planet-lab.eu") @@ -498,23 +539,24 @@ class PLCAPIFactory(object): :param proxy: Proxy service url :type pl_ptn: str """ - if slice and pl_pass and pl_host: - key = cls._make_key(slicename, pl_host) + if pl_user and pl_pass and pl_host: + key = cls._make_key(pl_user, pl_host) with cls._lock: api = cls._apis.get(key) if not api: - api = cls.create_api(slicename, pl_pass, pl_host, pl_ptn, proxy) + api = cls.create_api(pl_user, pl_pass, pl_host, pl_ptn, ec, proxy) + else: + api.count += 1 return api return None @classmethod - def create_api(cls, slicename, pl_pass, pl_host, - pl_ptn = "https://%(hostname)s:443/PLCAPI/", - proxy = None): + def create_api(cls, pl_user, pl_pass, pl_host, + pl_ptn, ec, proxy = None): """ Create an PLCAPI instance - :param slicename: Planelab slice name - :type slicename: str + :param pl_user: Planelab user name (used for web login) + :type pl_user: str :param pl_pass: Planetlab password (used for web login) :type pl_pass: str :param pl_host: Planetlab registry host (e.g. "www.planet-lab.eu") @@ -524,14 +566,9 @@ class PLCAPIFactory(object): :param proxy: Proxy service url :type pl_ptn: str """ - api = PLCAPI( - username = slicename, - password = pl_pass, - hostname = pl_host, - urlpattern = pl_ptn, - proxy = proxy - ) - key = cls._make_key(slicename, pl_host) + api = PLCAPI(username = pl_user, password = pl_pass, hostname = pl_host, + urlpattern = pl_ptn, ec = ec, proxy = proxy) + key = cls._make_key(pl_user, pl_host) cls._apis[key] = api return api @@ -546,3 +583,4 @@ class PLCAPIFactory(object): skey = "".join(map(str, args)) return hashlib.md5(skey).hexdigest() +