X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=src%2Fnepi%2Ftestbeds%2Fplanetlab%2Fnode.py;h=a73f6ab791f8366f4436434c9b75d2e3aac5d5ba;hb=476134e26e61b5b8522b45cbc4c379b6ffa8e0b5;hp=527560073f95da63cf8146184e355cac664e3739;hpb=ee111fbea1f62df09e8ec2e56291e1a9c6189dca;p=nepi.git diff --git a/src/nepi/testbeds/planetlab/node.py b/src/nepi/testbeds/planetlab/node.py index 52756007..a73f6ab7 100644 --- a/src/nepi/testbeds/planetlab/node.py +++ b/src/nepi/testbeds/planetlab/node.py @@ -76,6 +76,7 @@ class Node(object): DEPENDS_PIDFILE = '/tmp/nepi-depends.pid' DEPENDS_LOGFILE = '/tmp/nepi-depends.log' + RPM_FUSION_URL = 'http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-stable.noarch.rpm' RPM_FUSION_URL_F12 = 'http://download1.rpmfusion.org/free/fedora/releases/12/Everything/x86_64/os/rpmfusion-free-release-12-1.noarch.rpm' @@ -113,7 +114,7 @@ class Node(object): self.maxLoad = None self.min_num_external_ifaces = None self.max_num_external_ifaces = None - self.timeframe = 'm' + self._timeframe = 'w' # Applications and routes add requirements to connected nodes self.required_packages = set() @@ -130,7 +131,8 @@ class Node(object): self.ident_path = None self.server_key = None self.home_path = None - self.enable_cleanup = False + self.enable_proc_cleanup = False + self.enable_home_cleanup = False # Those are filled when an actual node is allocated self._node_id = None @@ -139,6 +141,27 @@ class Node(object): # Logging self._logger = logging.getLogger('nepi.testbeds.planetlab') + + def set_timeframe(self, timeframe): + if timeframe == "latest": + self._timeframe = "" + elif timeframe == "month": + self._timeframe = "m" + elif timeframe == "year": + self._timeframe = "y" + else: + self._timeframe = "w" + + def get_timeframe(self): + if self._timeframe == "": + return "latest" + if self._timeframe == "m": + return "month" + if self._timeframe == "y": + return "year" + return "week" + + timeframe = property(get_timeframe, set_timeframe) def _nepi_testbed_environment_setup_get(self): command = cStringIO.StringIO() @@ -153,8 +176,10 @@ class Node(object): for envval in envvals: command.write(' ; export %s=%s' % (envkey, envval)) return command.getvalue() + def _nepi_testbed_environment_setup_set(self, value): pass + _nepi_testbed_environment_setup = property( _nepi_testbed_environment_setup_get, _nepi_testbed_environment_setup_set) @@ -178,7 +203,7 @@ class Node(object): self._logger.info("Finding candidates for %s", self.make_filter_description()) fields = ('node_id',) - replacements = {'timeframe':self.timeframe} + replacements = {'timeframe':self._timeframe} # get initial candidates (no tag filters) basefilters = self.build_filters({}, self.BASEFILTERS) @@ -209,9 +234,9 @@ class Node(object): if attr in applicable: tagfilter = rootfilters.copy() tagfilter['tagname'] = tagname % replacements - tagfilter[expr % replacements] = getattr(self,attr) + tagfilter[expr % replacements] = str(getattr(self,attr)) tagfilter['node_id'] = list(candidates) - + candidates &= set(map(operator.itemgetter('node_id'), self._sliceapi.GetNodeTags(filters=tagfilter, fields=fields))) @@ -272,7 +297,7 @@ class Node(object): def resolvable(node_id): try: - addr = socket.gethostbyname(hostnames[node_id]) + addr = server.gethostbyname(hostnames[node_id]) return addr is not None except: return False @@ -345,7 +370,7 @@ class Node(object): def rate_nodes(self, nodes): rates = collections.defaultdict(int) tags = collections.defaultdict(dict) - replacements = {'timeframe':self.timeframe} + replacements = {'timeframe':self._timeframe} tagnames = [ tagname % replacements for tagname, weight, default in self.RATE_FACTORS ] @@ -380,9 +405,9 @@ class Node(object): orig_attrs['max_num_external_ifaces'] = self.max_num_external_ifaces self.min_num_external_ifaces = None self.max_num_external_ifaces = None - self.timeframe = 'm' + if not self._timeframe: self._timeframe = 'w' - replacements = {'timeframe':self.timeframe} + replacements = {'timeframe':self._timeframe} for attr, tag in self.BASEFILTERS.iteritems(): if tag in info: @@ -412,7 +437,7 @@ class Node(object): orig_attrs['server_key'] = self.server_key self.server_key = info['ssh_rsa_key'] - self.hostip = socket.gethostbyname(self.hostname) + self.hostip = server.gethostbyname(self.hostname) try: self.__orig_attrs @@ -453,17 +478,17 @@ class Node(object): RPM_FUSION_URL = self.RPM_FUSION_URL rpmFusion = ( - 'rpm -q $(rpm -q -p %(RPM_FUSION_URL)s) || sudo -S rpm -i %(RPM_FUSION_URL)s' + 'rpm -q rpmfusion-free-release || sudo -S rpm -i %(RPM_FUSION_URL)s' ) % { 'RPM_FUSION_URL' : RPM_FUSION_URL } else: rpmFusion = '' - + if rpmFusion: (out,err),proc = server.popen_ssh_command( rpmFusion, - host = self.hostname, + host = self.hostip, port = None, user = self.slicename, agent = None, @@ -475,7 +500,7 @@ class Node(object): if proc.wait(): if self.check_bad_host(out,err): self.blacklist() - raise RuntimeError, "Failed to set up application: %s %s" % (out,err,) + raise RuntimeError, "Failed to set up application on host %s: %s %s" % (self.hostname, out,err,) # Launch p2p yum dependency installer self._yum_dependencies.async_setup() @@ -497,9 +522,11 @@ class Node(object): raise UnresponsiveNodeError, "Unresponsive host %s" % (self.hostname,) # Ensure the node is clean (no apps running that could interfere with operations) - if self.enable_cleanup: - self.do_cleanup() - + if self.enable_proc_cleanup: + self.do_proc_cleanup() + if self.enable_home_cleanup: + self.do_home_cleanup() + def wait_dependencies(self, pidprobe=1, probe=0.5, pidmax=10, probemax=10): # Wait for the p2p installer if self._yum_dependencies and not self._installed: @@ -511,7 +538,7 @@ class Node(object): # they have to be created for deployment (out,err),proc = server.eintr_retry(server.popen_ssh_command)( "echo 'ALIVE'", - host = self.hostname, + host = self.hostip, port = None, user = self.slicename, agent = None, @@ -534,8 +561,8 @@ class Node(object): return False def destroy(self): - if self.enable_cleanup: - self.do_cleanup() + if self.enable_proc_cleanup: + self.do_proc_cleanup() def blacklist(self): if self._node_id: @@ -543,12 +570,12 @@ class Node(object): import util util.appendBlacklist(self.hostname) - def do_cleanup(self): + def do_proc_cleanup(self): if self.testbed().recovering: # WOW - not now return - self._logger.info("Cleaning up %s", self.hostname) + self._logger.info("Cleaning up processes on %s", self.hostname) cmds = [ "sudo -S killall python tcpdump || /bin/true ; " @@ -566,7 +593,7 @@ class Node(object): cmd % { 'slicename' : self.slicename , }, - host = self.hostname, + host = self.hostip, port = None, user = self.slicename, agent = None, @@ -577,7 +604,34 @@ class Node(object): retry = 3 ) proc.wait() - + + def do_home_cleanup(self): + if self.testbed().recovering: + # WOW - not now + return + + self._logger.info("Cleaning up home on %s", self.hostname) + + cmds = [ + "find . -maxdepth 1 \( -name '.cache' -o -name '.local' -o -name '.config' -o -name 'nepi-*' \) -execdir rm -rf {} + " + ] + + for cmd in cmds: + (out,err),proc = server.popen_ssh_command( + # Some apps need two kills + cmd, + host = self.hostip, + port = None, + user = self.slicename, + agent = None, + ident_key = self.ident_path, + server_key = self.server_key, + tty = True, # so that ps -N -T works as advertised... + timeout = 60, + retry = 3 + ) + proc.wait() + def prepare_dependencies(self): # Configure p2p yum dependency installer if self.required_packages and not self._installed: @@ -613,10 +667,10 @@ class Node(object): if len(routes) > MAX_VROUTE_ROUTES: return 'sliceip' - vsys_vnet = ipaddr.IPNetwork(vsys_vnet) + vsys_vnet = ipaddr.IPv4Network(vsys_vnet) for route in routes: - dest, prefix, nexthop, metric = route - dest = ipaddr.IPNetwork("%s/%d" % (dest,prefix)) + dest, prefix, nexthop, metric, device = route + dest = ipaddr.IPv4Network("%s/%d" % (dest,prefix)) nexthop = ipaddr.IPAddress(nexthop) if dest not in vsys_vnet or nexthop not in vsys_vnet: return 'sliceip' @@ -624,7 +678,7 @@ class Node(object): return 'vroute' def format_route(self, route, dev, method, action): - dest, prefix, nexthop, metric = route + dest, prefix, nexthop, metric, device = route if method == 'vroute': return ( "%s %s%s gw %s %s" % ( @@ -747,7 +801,7 @@ class Node(object): "( sudo -S bash -c 'cat /vsys/%(method)s.out >&2' & ) ; sudo -S bash -c 'cat > /vsys/%(method)s.in' ; sleep 0.5" % dict( home = server.shell_escape(self.home_path), method = method), - host = self.hostname, + host = self.hostip, port = None, user = self.slicename, agent = None, @@ -764,8 +818,9 @@ class Node(object): def check_bad_host(self, out, err): badre = re.compile(r'(?:' - r"curl: [(]\d+[)] Couldn't resolve host 'download1[.]rpmfusion[.]org'" + #r"curl: [(]\d+[)] Couldn't resolve host 'download1[.]rpmfusion[.]org'" r'|Error: disk I/O error' r')', re.I) return badre.search(out) or badre.search(err) +