X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=src%2Fnepi%2Fresources%2Fplanetlab%2Fsfa_node.py;h=fca374e4d8994fb9d0b24988cc0e7eed7e80b6c3;hb=6285ca51026efb69642eea9dfc7c480e722d84a9;hp=59f1df0a4501abb435da5a6b9d736220e2ea1076;hpb=6d8bb1d08981ce3e584d8a9e0276b58927290243;p=nepi.git diff --git a/src/nepi/resources/planetlab/sfa_node.py b/src/nepi/resources/planetlab/sfa_node.py index 59f1df0a..fca374e4 100644 --- a/src/nepi/resources/planetlab/sfa_node.py +++ b/src/nepi/resources/planetlab/sfa_node.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 @@ -17,9 +16,11 @@ # # Author: Lucia Guevgeozian +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!