X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=src%2Fnepi%2Futil%2Fsfaapi.py;h=f460b7e8a2f665f565aab79d3e86850206a4dc60;hb=58a2b493f8df1072a1faa653c8abb6a3f9ba21fa;hp=48dfb48543b644045afb0173d857fe411eec5521;hpb=6d8bb1d08981ce3e584d8a9e0276b58927290243;p=nepi.git diff --git a/src/nepi/util/sfaapi.py b/src/nepi/util/sfaapi.py index 48dfb485..f460b7e8 100644 --- a/src/nepi/util/sfaapi.py +++ b/src/nepi/util/sfaapi.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 @@ -21,6 +20,7 @@ import threading import hashlib import re import os +import time from nepi.util.logger import Logger @@ -36,7 +36,7 @@ from nepi.util.sfarspec_proc import SfaRSpecProcessing class SFAAPI(object): """ - API for quering the SFA service. + API for quering the SFA service. It uses Sfi class from the tool sfi client. """ def __init__(self, sfi_user, sfi_auth, sfi_registry, sfi_sm, private_key, ec, batch, rtype, timeout): @@ -46,6 +46,7 @@ class SFAAPI(object): self._resources_cache = None self._already_cached = False self._ec = ec + self.apis = 1 if batch: self._testbed_res = rtype @@ -73,6 +74,10 @@ class SFAAPI(object): self._set_blacklist() def _set_blacklist(self): + """ + Initialize the blacklist with previous nodes blacklisted, in + previous runs. + """ 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: @@ -82,6 +87,12 @@ class SFAAPI(object): self._blacklist.add(host) def _get_total_res(self): + """ + Get the total amount of resources instanciated using this API, + to be able to add them using the same Allocate and Provision + call at once. Specially for Wilabt testbed that doesn't allow + to add slivers after the slice already has some. + """ rms = list() res_gids = self._ec.resources for gid in res_gids: @@ -90,11 +101,12 @@ class SFAAPI(object): rms.append(rm) return rms - def _sfi_exec_method(self, command, slicename=None, rspec=None, urn=None): + def _sfi_exec_method(self, command, slicename=None, rspec=None, urn=None, action=None): """ - Execute sfi method. + Execute sfi method, which correspond to SFA call. It can be the following + calls: Describe, Delete, Allocate, Provision, ListResources. """ - if command in ['describe', 'delete', 'allocate', 'provision']: + if command in ['describe', 'delete', 'allocate', 'provision', 'action']: if not slicename: raise TypeError("The slice hrn is expected for this method %s" % command) if command == 'allocate' and not rspec: @@ -106,6 +118,8 @@ class SFAAPI(object): args_list = [slicename] if command != 'delete': args_list = args_list + ['-o', '/tmp/rspec_output'] + if command == 'action': + args_list = [slicename, action] elif command == 'resources': args_list = ['-o', '/tmp/rspec_output'] @@ -197,18 +211,17 @@ class SFAAPI(object): else: slice_resources = [] if slice_resources: slice_resources_hrn = self.get_resources_hrn(slice_resources) - for s_hrn_key, s_hrn_value in slice_resources_hrn.iteritems(): + for s_hrn_key, s_hrn_value in slice_resources_hrn.items(): s_parts = s_hrn_value.split('.') s_hrn = '.'.join(s_parts[:2]) + '.' + '\\.'.join(s_parts[2:]) resources_hrn_new.append(s_hrn) resources_urn = self._get_resources_urn(resources_hrn_new) - rspec = self.rspec_proc.build_sfa_rspec(slicename, resources_urn, leases) - f = open("/tmp/rspec_input.rspec", "w") - f.truncate(0) - f.write(rspec) - f.close() + rspec = self.rspec_proc.build_sfa_rspec(slicename, resources_urn, None, leases) + with open("/tmp/rspec_input.rspec", "w") as f: + f.truncate(0) + f.write(rspec) if not os.path.getsize("/tmp/rspec_input.rspec") > 0: raise RuntimeError("Fail to create rspec file to allocate resource in slice %s" % slicename) @@ -229,31 +242,35 @@ class SFAAPI(object): raise RuntimeError("Fail to provision resource for slice %s" % slicename) return True - def add_resource_to_slice_batch(self, slicename, resource_hrn, leases=None): + def add_resource_to_slice_batch(self, slicename, resource_hrn, properties=None, leases=None): """ Method to add all resources together to the slice. Previous deletion of slivers. + Specially used for wilabt that doesn't allow to add more resources to the slice + after some resources are added. Every sliver have to be deleted and the batch + has to be added at once. """ - # Specially used for wilabt that doesn't allow to add more resources to the slice - # after some resources are added. Every sliver have to be deleted and the batch - # has to be added at once. self._count += 1 self._slice_resources_batch.append(resource_hrn) resources_hrn_new = list() if self._count == len(self._total): + check_all_inslice = self._check_all_inslice(self._slice_resources_batch, slicename) + if check_all_inslice == True: + return True for resource_hrn in self._slice_resources_batch: resource_parts = resource_hrn.split('.') resource_hrn = '.'.join(resource_parts[:2]) + '.' + '\\.'.join(resource_parts[2:]) resources_hrn_new.append(resource_hrn) with self.lock_slice: - self._sfi_exec_method('delete', slicename) + if check_all_inslice != 0: + self._sfi_exec_method('delete', slicename) + time.sleep(480) + # Re implementing urn from hrn because the library sfa-common doesn't work for wilabt resources_urn = self._get_urn(resources_hrn_new) - rspec = self.rspec_proc.build_sfa_rspec(slicename, resources_urn, leases) - - f = open("/tmp/rspec_input.rspec", "w") - f.truncate(0) - f.write(rspec) - f.close() + rspec = self.rspec_proc.build_sfa_rspec(slicename, resources_urn, properties, leases) + with open("/tmp/rspec_input.rspec", "w") as f: + f.truncate(0) + f.write(rspec) if not os.path.getsize("/tmp/rspec_input.rspec") > 0: raise RuntimeError("Fail to create rspec file to allocate resources in slice %s" % slicename) @@ -270,6 +287,7 @@ class SFAAPI(object): try: self._log.debug("Provisioning resources in slice %s" % slicename) self._sfi_exec_method('provision', slicename) + self._sfi_exec_method('action', slicename=slicename, action='geni_start') except: raise RuntimeError("Fail to provision resource for slice %s" % slicename) return True @@ -279,6 +297,24 @@ class SFAAPI(object): else: self._log.debug(" Waiting for more nodes to add the batch to the slice ") + def _check_all_inslice(self, resources_hrn, slicename): + slice_res = self.get_slice_resources(slicename)['resource'] + if slice_res: + if len(slice_res[0]['services']) != 0: + slice_res_hrn = self.get_resources_hrn(slice_res).values() + if self._compare_lists(slice_res_hrn, resources_hrn): + return True + else: return len(slice_res_hrn) + return 0 + + def _compare_lists(self, list1, list2): + if len(list1) != len(list2): + return False + for item in list1: + if item not in list2: + return False + return True + def _get_urn(self, resources_hrn): """ Get urn from hrn. @@ -295,8 +331,8 @@ class SFAAPI(object): def remove_resource_from_slice(self, slicename, resource_hrn, leases=None): """ - Get the list of resources' urn, build the rspec string and call the allocate - and provision method. + Remove slivers from slice. Currently sfi doesn't support removing particular + slivers. """ resource_urn = self._get_resources_urn([resource_hrn]).pop() with self.lock_slice: @@ -309,6 +345,9 @@ class SFAAPI(object): def remove_all_from_slice(self, slicename): """ De-allocate and de-provision all slivers of the named slice. + Currently sfi doesn't support removing particular + slivers, so this method works only for removing every sliver. Setting the + resource_hrn parameter is not necessary. """ with self.lock_slice: try: @@ -329,6 +368,10 @@ class SFAAPI(object): return resources_urn def blacklist_resource(self, resource_hrn): + """ + Adding resource_hrn to blacklist, and taking + the resource from the reserved list. + """ with self.lock_blist: self._blacklist.add(resource_hrn) with self.lock_resv: @@ -336,15 +379,24 @@ class SFAAPI(object): self._reserved.remove(resource_hrn) def blacklisted(self, resource_hrn): + """ + Check if the resource is in the blacklist. + """ with self.lock_blist: if resource_hrn in self._blacklist: return True return False def reserve_resource(self, resource_hrn): + """ + Add resource to the reserved list. + """ self._reserved.add(resource_hrn) def reserved(self, resource_hrn): + """ + Check that the resource in not reserved. + """ with self.lock_resv: if resource_hrn in self._reserved: return True @@ -352,6 +404,33 @@ class SFAAPI(object): self.reserve_resource(resource_hrn) return False + def release(self): + """ + Remove hosts from the reserved and blacklist lists, and in case + the persist attribute is set, it saves the blacklisted hosts + in the blacklist file. + """ + self.apis -= 1 + if self.apis == 0: + blacklist = self._blacklist + self._blacklist = set() + self._reserved = set() +# if self._ecobj.get_global('PlanetlabSfaNode', '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 SFAAPIFactory(object): """ API Factory to manage a map of SFAAPI instances as key-value pairs, it @@ -376,6 +455,8 @@ class SFAAPIFactory(object): api = SFAAPI(sfi_user, sfi_auth, sfi_registry, sfi_sm, private_key, ec, batch, rtype, timeout) cls._apis[key] = api + else: + api.apis += 1 return api