Validating that DNS can resolve hostname to IP in LinuxNode
[nepi.git] / src / nepi / resources / linux / node.py
index 214c4ef..62ada38 100644 (file)
@@ -28,6 +28,7 @@ import collections
 import os
 import random
 import re
+import socket
 import tempfile
 import time
 import threading
@@ -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()
 
@@ -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 = []