applied the except and raise fixers to the master branch to close the gap with py3
[nepi.git] / src / nepi / resources / planetlab / plcapi.py
index 97c4846..d2970e8 100644 (file)
@@ -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,16 +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)
@@ -175,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
@@ -209,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):
@@ -271,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):
@@ -429,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()
@@ -459,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):
     """ 
@@ -492,8 +525,7 @@ class PLCAPIFactory(object):
 
     @classmethod 
     def get_api(cls, pl_user, pl_pass, pl_host,
-            pl_ptn = "https://%(hostname)s:443/PLCAPI/",
-            proxy = None):
+            pl_ptn, ec, proxy = None):
         """ Get existing PLCAPI instance
 
         :param pl_user: Planelab user name (used for web login)
@@ -512,14 +544,15 @@ class PLCAPIFactory(object):
             with cls._lock:
                 api = cls._apis.get(key)
                 if not api:
-                    api = cls.create_api(pl_user, 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, pl_user, pl_pass, pl_host,
-            pl_ptn = "https://%(hostname)s:443/PLCAPI/",
-            proxy = None):
+            pl_ptn, ec, proxy = None):
         """ Create an PLCAPI instance
 
         :param pl_user: Planelab user name (used for web login)
@@ -533,13 +566,8 @@ class PLCAPIFactory(object):
         :param proxy: Proxy service url
         :type pl_ptn: str
         """
-        api = PLCAPI(
-            username = pl_user,
-            password = pl_pass,
-            hostname = pl_host,
-            urlpattern = pl_ptn,
-            proxy = proxy
-        )
+        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
@@ -555,3 +583,4 @@ class PLCAPIFactory(object):
         skey = "".join(map(str, args))
         return hashlib.md5(skey).hexdigest()
 
+