applied the except and raise fixers to the master branch to close the gap with py3
[nepi.git] / src / nepi / resources / planetlab / sfa_node.py
index 59f1df0..fca374e 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
 #
 # Author: Lucia Guevgeozian <lucia.guevgeozian_odizzio@inria.fr>
 
+from __future__ import print_function
+
 from nepi.execution.attribute import Attribute, Flags, Types
 from nepi.execution.resource import ResourceManager, clsinit_copy, \
-        ResourceState, reschedule_delay 
+        ResourceState
 from nepi.resources.linux.node import LinuxNode
 from nepi.util.sfaapi import SFAAPIFactory 
 from nepi.util.execfuncs import lexec
@@ -27,6 +28,7 @@ from nepi.util import sshfuncs
 
 from random import randint
 import re
+import os
 import weakref
 import time
 import socket
@@ -35,10 +37,10 @@ import datetime
 
 @clsinit_copy
 class PlanetlabSfaNode(LinuxNode):
-    _rtype = "PlanetlabSfaNode"
+    _rtype = "planetlab::sfa::Node"
     _help = "Controls a PlanetLab host accessible using a SSH key " \
             "and provisioned using SFA"
-    _backend = "planetlab"
+    _platform = "planetlab"
 
     @classmethod
     def _register_attributes(cls):
@@ -184,6 +186,18 @@ class PlanetlabSfaNode(LinuxNode):
             self.set("gateway", None)
             self.set("gatewayUser", None)
 
+        # Blacklist file for PL nodes
+        nepi_home = os.path.join(os.path.expanduser("~"), ".nepi")
+        plblacklist_file = os.path.join(nepi_home, "plblacklist.txt")
+        if not os.path.exists(plblacklist_file):
+            if os.path.isdir(nepi_home):
+                with open(plblacklist_file, 'w') as clear:
+                    pass
+            else:
+                os.makedirs(nepi_home)
+                with open(plblacklist_file, 'w') as clear:
+                    pass
+
     def _skip_provision(self):
         sfa_user = self.get("sfauser")
         if not sfa_user:
@@ -192,6 +206,10 @@ class PlanetlabSfaNode(LinuxNode):
     
     @property
     def sfaapi(self):
+        """
+        Property to instanciate the SFA API based in sfi client.
+        For each SFA method called this instance is used.
+        """
         if not self._sfaapi:
             sfa_user = self.get("sfauser")
             sfa_sm = "http://sfa3.planet-lab.eu:12346/"
@@ -228,69 +246,70 @@ class PlanetlabSfaNode(LinuxNode):
 
             # check that the node is not blacklisted or being provisioned
             # by other RM
-            if not self._blacklisted(host_hrn):
-                if not self._reserved(host_hrn):
-                    # Node in reservation
-                    ping_ok = self._do_ping(hostname)
-                    if not ping_ok:
-                        self._blacklist_node(host_hrn)
-                        self.fail_node_not_alive(hostname)
-                    else:
-                        if self._check_if_in_slice([host_hrn]):
-                            self.debug("The node %s is already in the slice" % hostname)
-                            self._slicenode = True
-                        self._node_to_provision = host_hrn
-                        super(PlanetlabSfaNode, self).do_discover()
-        
-#        else:
-#            # the user specifies constraints based on attributes, zero, one or 
-#            # more nodes can match these constraints 
-#            nodes = self._filter_based_on_attributes()
-#
-#            # nodes that are already part of user's slice have the priority to
-#            # provisioned
-#            nodes_inslice = self._check_if_in_slice(nodes)
-#            nodes_not_inslice = list(set(nodes) - set(nodes_inslice))
-#            
-#            node_id = None
-#            if nodes_inslice:
-#                node_id = self._choose_random_node(nodes_inslice)
-#                self._slicenode = True                
-#                
-#            if not node_id:
-#                # Either there were no matching nodes in the user's slice, or
-#                # the nodes in the slice  were blacklisted or being provisioned
-#                # by other RM. Note nodes_not_inslice is never empty
-#                node_id = self._choose_random_node(nodes_not_inslice)
-#                self._slicenode = False
-#
-#            if node_id:
-#                self._node_to_provision = node_id
-#                try:
-#                    self._set_hostname_attr(node_id)
-#                    self.info(" Selected node to provision ")
-#                    super(PlanetlabSfaNode, self).do_discover()
-#                except:
-#                    with PlanetlabSfaNode.lock:
-#                        self._blacklist_node(node_id)
-#                    self.do_discover()
-#            else:
-#               self.fail_not_enough_nodes() 
-#    
+            if not self._blacklisted(host_hrn) and not self._reserved(host_hrn):
+                # Node in reservation
+                ping_ok = self._do_ping(hostname)
+                if not ping_ok:
+                    self._blacklist_node(host_hrn)
+                    self.fail_node_not_alive(hostname)
+                else:
+                    if self._check_if_in_slice([host_hrn]):
+                        self.debug("The node %s is already in the slice" % hostname)
+                        self._slicenode = True
+                    self._node_to_provision = host_hrn
+            else:
+                self.fail_node_not_available(hostname)
+            super(PlanetlabSfaNode, self).do_discover()
+
+        else:
+            hosts_hrn = nodes.values()
+            nodes_inslice = self._check_if_in_slice(hosts_hrn)
+            nodes_not_inslice = list(set(hosts_hrn) - set(nodes_inslice))
+            host_hrn = None
+            if nodes_inslice:
+                host_hrn = self._choose_random_node(nodes, nodes_inslice)
+                self._slicenode = True          
+
+            if not host_hrn:
+                # Either there were no matching nodes in the user's slice, or
+                # the nodes in the slice  were blacklisted or being provisioned
+                # by other RM. Note nodes_not_inslice is never empty
+                host_hrn = self._choose_random_node(nodes, nodes_not_inslice)
+                self._slicenode = False
+
+            if host_hrn:
+                self._node_to_provision = host_hrn
+                try:
+                    self._set_hostname_attr(host_hrn)
+                    self.info(" Selected node to provision ")
+                    super(PlanetlabSfaNode, self).do_discover()
+                except:
+                    self._blacklist_node(host_hrn)
+                    self.do_discover()
+            else:
+               self.fail_not_enough_nodes() 
+    
     def _blacklisted(self, host_hrn):
+        """
+        Check in the SFA API that the node is not in the blacklist.
+        """
         if self.sfaapi.blacklisted(host_hrn):
-           self.fail_node_not_available(host_hrn)
+           return True
         return False
 
     def _reserved(self, host_hrn):
+        """
+        Check in the SFA API that the node is not in the reserved
+        list.
+        """
         if self.sfaapi.reserved(host_hrn):
-            self.fail_node_not_available(host_hrn)
+            return True
         return False
             
     def do_provision(self):
         """
-        Add node to user's slice after verifing that the node is functioning
-        correctly.
+        Add node to user's slice and verifing that the node is functioning
+        correctly. Check ssh, file system.
         """
         if self._skip_provision():
             super(PlanetlabSfaNode, self).do_provision()
@@ -358,6 +377,12 @@ class PlanetlabSfaNode(LinuxNode):
             
         super(PlanetlabSfaNode, self).do_provision()
 
+    def do_release(self):
+        super(PlanetlabSfaNode, self).do_release()
+        if self.state == ResourceState.RELEASED and not self._skip_provision():
+            self.debug(" Releasing SFA API ")
+            self.sfaapi.release()
+
 #    def _filter_based_on_attributes(self):
 #        """
 #        Retrive the list of nodes hrn that match user's constraints 
@@ -491,52 +516,64 @@ class PlanetlabSfaNode(LinuxNode):
 ##            self.fail_discovery()
 ##
 ##        return nodes_id
-#        
-#    def _choose_random_node(self, nodes):
-#        """
-#        From the possible nodes for provision, choose randomly to decrese the
-#        probability of different RMs choosing the same node for provision
-#        """
-#        size = len(nodes)
-#        while size:
-#            size = size - 1
-#            index = randint(0, size)
-#            node_id = nodes[index]
-#            nodes[index] = nodes[size]
-#
-#            # check the node is not blacklisted or being provision by other RM
-#            # and perform ping to check that is really alive
-#            with PlanetlabNode.lock:
-#
-#                blist = self.plapi.blacklisted()
-#                plist = self.plapi.reserved()
-#                if node_id not in blist and node_id not in plist:
-#                    ping_ok = self._do_ping(node_id)
-#                    if not ping_ok:
-#                        self._set_hostname_attr(node_id)
-#                        self.warn(" Node not responding PING ")
-#                        self._blacklist_node(node_id)
-#                    else:
-#                        # discovered node for provision, added to provision list
-#                        self._put_node_in_provision(node_id)
-#                        return node_id
-#
+        
+    def _choose_random_node(self, nodes, hosts_hrn):
+        """
+        From the possible nodes for provision, choose randomly to decrese the
+        probability of different RMs choosing the same node for provision
+        """
+        size = len(hosts_hrn)
+        while size:
+            size = size - 1
+            index = randint(0, size)
+            host_hrn = hosts_hrn[index]
+            hosts_hrn[index] = hosts_hrn[size]
+
+            # check the node is not blacklisted or being provision by other RM
+            # and perform ping to check that is really alive
+            if not self._blacklisted(host_hrn):
+                if not self._reserved(host_hrn):
+                    print(self.sfaapi._reserved ,self.guid)
+                    for hostname, hrn in nodes.iteritems():
+                        if host_hrn == hrn:
+                            print('hostname' ,hostname)
+                            ping_ok = self._do_ping(hostname)
+                
+                    if not ping_ok:
+                        self._set_hostname_attr(hostname)
+                        self.warning(" Node not responding PING ")
+                        self._blacklist_node(host_hrn)
+                    else:
+                        # discovered node for provision, added to provision list
+                        self._node_to_provision = host_hrn
+                        return host_hrn
+
 #    def _get_nodes_id(self, filters=None):
 #        return self.plapi.get_nodes(filters, fields=['node_id'])
 #
     def _add_node_to_slice(self, host_hrn):
+        """
+        Add node to slice, using SFA API.
+        """
         self.info(" Adding node to slice ")
         slicename = self.get("username").replace('_', '.')
         slicename = 'ple.' + slicename
         self.sfaapi.add_resource_to_slice(slicename, host_hrn)
 
     def _delete_from_slice(self):
+        """
+        Delete every node from slice, using SFA API.
+        Sfi client doesn't work for particular node urns.
+        """
         self.warning(" Deleting node from slice ")
         slicename = self.get("username").replace('_', '.')
         slicename = 'ple.' + slicename
         self.sfaapi.remove_all_from_slice(slicename)
 
     def _get_hostname(self):
+        """
+        Get the attribute hostname.
+        """
         hostname = self.get("hostname")
         if hostname:
             return hostname
@@ -546,7 +583,7 @@ class PlanetlabSfaNode(LinuxNode):
     def _set_hostname_attr(self, node):
         """
         Query SFAAPI for the hostname of a certain host hrn and sets the
-        attribute hostname, it will over write the previous value
+        attribute hostname, it will over write the previous value.
         """
         hosts_hrn = self.sfaapi.get_resources_hrn()
         for hostname, hrn  in hosts_hrn.iteritems():
@@ -556,7 +593,7 @@ class PlanetlabSfaNode(LinuxNode):
     def _check_if_in_slice(self, hosts_hrn):
         """
         Check using SFA API if any host hrn from hosts_hrn is in the user's
-        slice
+        slice.
         """
         slicename = self.get("username").replace('_', '.')
         slicename = 'ple.' + slicename
@@ -569,7 +606,7 @@ class PlanetlabSfaNode(LinuxNode):
 
     def _do_ping(self, hostname):
         """
-        Perform ping command on node's IP matching hostname
+        Perform ping command on node's IP matching hostname.
         """
         ping_ok = False
         ip = self._get_ip(hostname)
@@ -585,7 +622,7 @@ class PlanetlabSfaNode(LinuxNode):
 
     def _blacklist_node(self, host_hrn):
         """
-        Add node mal functioning node to blacklist
+        Add mal functioning node to blacklist (in SFA API).
         """
         self.warning(" Blacklisting malfunctioning node ")
         self.sfaapi.blacklist_resource(host_hrn)
@@ -613,24 +650,24 @@ class PlanetlabSfaNode(LinuxNode):
     def fail_discovery(self):
         msg = "Discovery failed. No candidates found for node"
         self.error(msg)
-        raise RuntimeError, msg
+        raise RuntimeError(msg)
 
     def fail_node_not_alive(self, hostname=None):
         msg = "Node %s not alive" % hostname
-        raise RuntimeError, msg
+        raise RuntimeError(msg)
     
     def fail_node_not_available(self, hostname):
         msg = "Node %s not available for provisioning" % hostname
-        raise RuntimeError, msg
+        raise RuntimeError(msg)
 
     def fail_not_enough_nodes(self):
         msg = "Not enough nodes available for provisioning"
-        raise RuntimeError, msg
+        raise RuntimeError(msg)
 
     def fail_sfaapi(self):
         msg = "Failing while trying to instanciate the SFA API.\nSet the" + \
             " attributes sfauser and sfaPrivateKey."
-        raise RuntimeError, msg
+        raise RuntimeError(msg)
 
     def valid_connection(self, guid):
         # TODO: Validate!