X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=src%2Fnepi%2Fresources%2Flinux%2Fnode.py;h=e63a92e9c655c203d99715f02321db632c48885a;hb=23d041fe2f0d9badf6d637009e2d42a4794325c1;hp=214c4ef05b05ea6a674acd2f60784d4419e4787d;hpb=0cff9603cef884887e19b6f594745284e54a2b19;p=nepi.git diff --git a/src/nepi/resources/linux/node.py b/src/nepi/resources/linux/node.py index 214c4ef0..e63a92e9 100644 --- a/src/nepi/resources/linux/node.py +++ b/src/nepi/resources/linux/node.py @@ -19,7 +19,7 @@ from nepi.execution.attribute import Attribute, Flags, Types from nepi.execution.resource import ResourceManager, clsinit_copy, \ - ResourceState, reschedule_delay + ResourceState from nepi.resources.linux import rpmfuncs, debfuncs from nepi.util import sshfuncs, execfuncs from nepi.util.sshfuncs import ProcStatus @@ -28,6 +28,7 @@ import collections import os import random import re +import socket import tempfile import time import threading @@ -141,10 +142,10 @@ class LinuxNode(ResourceManager): source compilation, file download, etc) """ - _rtype = "LinuxNode" + _rtype = "linux::Node" _help = "Controls Linux host machines ( either localhost or a host " \ "that can be accessed using a SSH key)" - _backend_type = "linux" + _platform = "linux" @classmethod def _register_attributes(cls): @@ -194,6 +195,10 @@ class LinuxNode(ResourceManager): gateway = Attribute("gateway", "Hostname of the gateway machine", flags = Flags.Design) + ip = Attribute("ip", "Linux host public IP address. " + "Must not be modified by the user unless hostname is 'localhost'", + flags = Flags.Design) + cls._register_attribute(hostname) cls._register_attribute(username) cls._register_attribute(port) @@ -206,6 +211,7 @@ class LinuxNode(ResourceManager): cls._register_attribute(tear_down) cls._register_attribute(gateway_user) cls._register_attribute(gateway) + cls._register_attribute(ip) def __init__(self, ec, guid): super(LinuxNode, self).__init__(ec, guid) @@ -233,9 +239,13 @@ class LinuxNode(ResourceManager): home = os.path.join(self._home_dir, home) return home + @property + def nepi_home(self): + return os.path.join(self.home_dir, ".nepi") + @property def usr_dir(self): - return os.path.join(self.home_dir, "nepi-usr") + return os.path.join(self.nepi_home, "nepi-usr") @property def lib_dir(self): @@ -255,7 +265,7 @@ class LinuxNode(ResourceManager): @property def exp_dir(self): - return os.path.join(self.home_dir, "nepi-exp") + return os.path.join(self.nepi_home, "nepi-exp") @property def exp_home(self): @@ -274,8 +284,7 @@ class LinuxNode(ResourceManager): if self._os: return self._os - if self.get("hostname") not in ["localhost", "127.0.0.1"] and \ - not self.get("username"): + if not self.localhost and not self.get("username"): msg = "Can't resolve OS, insufficient data " self.error(msg) raise RuntimeError, msg @@ -329,7 +338,7 @@ class LinuxNode(ResourceManager): @property def localhost(self): - return self.get("hostname") in ['localhost', '127.0.0.7', '::1'] + return self.get("hostname") in ['localhost', '127.0.0.1', '::1'] def do_provision(self): # check if host is alive @@ -349,14 +358,29 @@ class LinuxNode(ResourceManager): if self.get("cleanExperiment"): self.clean_experiment() - # Create shared directory structure - self.mkdir(self.lib_dir) - self.mkdir(self.bin_dir) - self.mkdir(self.src_dir) - self.mkdir(self.share_dir) + # Create shared directory structure and node home directory + paths = [self.lib_dir, + self.bin_dir, + self.src_dir, + self.share_dir, + self.node_home] + + self.mkdir(paths) + + # Get Public IP address if possible + if not self.get("ip"): + ip = None + + if self.localhost: + ip = socket.gethostbyname(socket.gethostname()) + else: + try: + ip = socket.gethostbyname(self.get("hostname")) + except: + msg = "DNS can not resolve hostname %s" % self.get("hostname") + self.debug(msg) - # Create experiment node home directory - self.mkdir(self.node_home) + self.set("ip", ip) super(LinuxNode, self).do_provision() @@ -372,7 +396,7 @@ class LinuxNode(ResourceManager): ifaces = self.get_connected(LinuxInterface.get_rtype()) for iface in ifaces: if iface.state < ResourceState.READY: - self.ec.schedule(reschedule_delay, self.deploy) + self.ec.schedule(self.reschedule_delay, self.deploy) return super(LinuxNode, self).do_deploy() @@ -383,7 +407,7 @@ class LinuxNode(ResourceManager): # Node needs to wait until all associated RMs are released # before it can be released if rm.state != ResourceState.RELEASED: - self.ec.schedule(reschedule_delay, self.release) + self.ec.schedule(self.reschedule_delay, self.release) return tear_down = self.get("tearDown") @@ -400,13 +424,12 @@ class LinuxNode(ResourceManager): def clean_processes(self): self.info("Cleaning up processes") - - if self.get("hostname") in ["localhost", "127.0.0.2"]: + + if self.localhost: return if self.get("username") != 'root': cmd = ("sudo -S killall tcpdump || /bin/true ; " + - "sudo -S kill $(ps aux | grep '[n]epi' | awk '{print $2}') || /bin/true ; " + "sudo -S killall -u %s || /bin/true ; " % self.get("username")) else: if self.state >= ResourceState.READY: @@ -415,15 +438,19 @@ class LinuxNode(ResourceManager): pids_temp = dict() ps_aux = "ps aux |awk '{print $2,$11}'" (out, err), proc = self.execute(ps_aux) - for line in out.strip().split("\n"): - parts = line.strip().split(" ") - pids_temp[parts[0]] = parts[1] - kill_pids = set(pids_temp.items()) - set(pids.items()) - kill_pids = ' '.join(dict(kill_pids).keys()) - - cmd = ("killall tcpdump || /bin/true ; " + - "kill $(ps aux | grep '[n]epi' | awk '{print $2}') || /bin/true ; " + - "kill %s || /bin/true ; " % kill_pids) + if len(out) != 0: + for line in out.strip().split("\n"): + parts = line.strip().split(" ") + pids_temp[parts[0]] = parts[1] + kill_pids = set(pids_temp.items()) - set(pids.items()) + kill_pids = ' '.join(dict(kill_pids).keys()) + + cmd = ("killall tcpdump || /bin/true ; " + + "kill $(ps aux | grep '[n]epi' | awk '{print $2}') || /bin/true ; " + + "kill %s || /bin/true ; " % kill_pids) + else: + cmd = ("killall tcpdump || /bin/true ; " + + "kill $(ps aux | grep '[n]epi' | awk '{print $2}') || /bin/true ; ") else: cmd = ("killall tcpdump || /bin/true ; " + "kill $(ps aux | grep '[n]epi' | awk '{print $2}') || /bin/true ; ") @@ -435,7 +462,7 @@ class LinuxNode(ResourceManager): """ self.info("Cleaning up home") - cmd = "cd %s ; find . -maxdepth 1 \( -name 'nepi-usr' -o -name 'nepi-exp' \) -execdir rm -rf {} + " % ( + cmd = "cd %s ; find . -maxdepth 1 -name \.nepi -execdir rm -rf {} + " % ( self.home_dir ) return self.execute(cmd, with_lock = True) @@ -532,7 +559,8 @@ class LinuxNode(ResourceManager): stdout = 'stdout', stderr = 'stderr', sudo = False, - tty = False): + tty = False, + strict_host_checking = False): self.debug("Running command '%s'" % command) @@ -563,7 +591,8 @@ class LinuxNode(ResourceManager): agent = True, identity = self.get("identity"), server_key = self.get("serverKey"), - tty = tty + tty = tty, + strict_host_checking = strict_host_checking ) return (out, err), proc @@ -582,7 +611,8 @@ class LinuxNode(ResourceManager): gw = self.get("gateway"), agent = True, identity = self.get("identity"), - server_key = self.get("serverKey") + server_key = self.get("serverKey"), + strict_host_checking = False ) return pidtuple @@ -601,7 +631,8 @@ class LinuxNode(ResourceManager): gw = self.get("gateway"), agent = True, identity = self.get("identity"), - server_key = self.get("serverKey") + server_key = self.get("serverKey"), + strict_host_checking = False ) return status @@ -626,7 +657,8 @@ class LinuxNode(ResourceManager): agent = True, sudo = sudo, identity = self.get("identity"), - server_key = self.get("serverKey") + server_key = self.get("serverKey"), + strict_host_checking = False ) return (out, err), proc @@ -698,7 +730,8 @@ class LinuxNode(ResourceManager): if err: msg = " Failed to upload files - src: %s dst: %s" % (";".join(src), dst) self.error(msg, out, err) - + + msg = "%s out: %s err: %s" % (msg, out, err) if raise_on_error: raise RuntimeError, msg @@ -784,14 +817,31 @@ class LinuxNode(ResourceManager): return (out, err), proc - def mkdir(self, path, clean = False): + def mkdir(self, paths, clean = False): + """ Paths is either a single remote directory path to create, + or a list of directories to create. + """ if clean: - self.rmdir(path) + self.rmdir(paths) + + if isinstance(paths, str): + paths = [paths] - return self.execute("mkdir -p %s" % path, with_lock = True) + cmd = " ; ".join(map(lambda path: "mkdir -p %s" % path, paths)) - def rmdir(self, path): - return self.execute("rm -rf %s" % path, with_lock = True) + return self.execute(cmd, with_lock = True) + + def rmdir(self, paths): + """ Paths is either a single remote directory path to delete, + or a list of directories to delete. + """ + + if isinstance(paths, str): + paths = [paths] + + cmd = " ; ".join(map(lambda path: "rm -rf %s" % path, paths)) + + return self.execute(cmd, with_lock = True) def run_and_wait(self, command, home, shfile = "cmd.sh", @@ -1058,8 +1108,7 @@ class LinuxNode(ResourceManager): """ Removes files that already exist in the Linux host from src list """ # construct a dictionary with { dst: src } - dests = dict(map( - lambda s: (os.path.join(dst, os.path.basename(s)), s ), s)) \ + dests = dict(map(lambda s: (os.path.join(dst, os.path.basename(s)), s), src)) \ if len(src) > 1 else dict({dst: src[0]}) command = []