large commit. new code, with sensors, line count dropped, etc
diff --git a/nodes/ceph.py b/nodes/ceph.py
index 38ce177..793c021 100644
--- a/nodes/ceph.py
+++ b/nodes/ceph.py
@@ -1,6 +1,7 @@
 """ Collect data about ceph nodes"""
 import json
 import logging
+import subprocess
 
 
 from node import Node
@@ -10,14 +11,29 @@
 logger = logging.getLogger("io-perf-tool")
 
 
-def discover_ceph_node(ip):
+def local_execute(cmd):
+    return subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
+
+
+def ssh_execute(ssh):
+    def closure(cmd):
+        _, chan, _ = ssh.exec_command(cmd)
+        return chan.read()
+    return closure
+
+
+def discover_ceph_nodes(ip):
     """ Return list of ceph's nodes ips """
     ips = {}
-    ssh = connect(ip)
 
-    osd_ips = get_osds_ips(ssh, get_osds_list(ssh))
-    mon_ips = get_mons_or_mds_ips(ssh, "mon")
-    mds_ips = get_mons_or_mds_ips(ssh, "mds")
+    if ip != 'local':
+        executor = ssh_execute(connect(ip))
+    else:
+        executor = local_execute
+
+    osd_ips = get_osds_ips(executor, get_osds_list(executor))
+    mon_ips = get_mons_or_mds_ips(executor, "mon")
+    mds_ips = get_mons_or_mds_ips(executor, "mds")
 
     for ip in osd_ips:
         url = "ssh://%s" % ip
@@ -31,29 +47,24 @@
         url = "ssh://%s" % ip
         ips.setdefault(url, []).append("ceph-mds")
 
-    return [Node(ip=url, roles=list(roles)) for url, roles in ips.items()]
+    return [Node(url, list(roles)) for url, roles in ips.items()]
 
 
-def get_osds_list(ssh):
+def get_osds_list(executor):
     """ Get list of osds id"""
-    _, chan, _ = ssh.exec_command("ceph osd ls")
-    return filter(None, chan.read().split("\n"))
+    return filter(None, executor("ceph osd ls").split("\n"))
 
 
-def get_mons_or_mds_ips(ssh, who):
+def get_mons_or_mds_ips(executor, who):
     """ Return mon ip list
         :param who - "mon" or "mds" """
-    if who == "mon":
-        _, chan, _ = ssh.exec_command("ceph mon dump")
-    elif who == "mds":
-        _, chan, _ = ssh.exec_command("ceph mds dump")
-    else:
+    if who not in ("mon", "mds"):
         raise ValueError(("'%s' in get_mons_or_mds_ips instead" +
                           "of mon/mds") % who)
 
-    line_res = chan.read().split("\n")
-    ips = set()
+    line_res = executor("ceph {0} dump".format(who)).split("\n")
 
+    ips = set()
     for line in line_res:
         fields = line.split()
 
@@ -67,12 +78,12 @@
     return ips
 
 
-def get_osds_ips(ssh, osd_list):
+def get_osds_ips(executor, osd_list):
     """ Get osd's ips
         :param osd_list - list of osd names from osd ls command"""
     ips = set()
     for osd_id in osd_list:
-        _, chan, _ = ssh.exec_command("ceph osd find {0}".format(osd_id))
-        ip = json.loads(chan.read())["ip"]
-        ips.add(ip.split(":")[0])
+        out = executor("ceph osd find {0}".format(osd_id))
+        ip = json.loads(out)["ip"]
+        ips.add(str(ip.split(":")[0]))
     return ips
diff --git a/nodes/discover.py b/nodes/discover.py
index ec98890..b95d306 100644
--- a/nodes/discover.py
+++ b/nodes/discover.py
@@ -50,5 +50,6 @@
             nodes_to_run.extend(fuel.discover_fuel_nodes(url, creads, roles))
 
         if cluster == "ceph":
-            nodes_to_run.extend(ceph.discover_ceph_node(cluster_info["ip"]))
+            nodes_to_run.extend(ceph.discover_ceph_nodes(cluster_info))
+
     return nodes_to_run
diff --git a/nodes/node.py b/nodes/node.py
index d7cae40..138d123 100644
--- a/nodes/node.py
+++ b/nodes/node.py
@@ -1,41 +1,16 @@
 class Node(object):
 
-    def __init__(self, ip, roles, username=None,
-                 password=None, key_path=None, port=None):
+    def __init__(self, conn_url, roles):
         self.roles = roles
-        self.ip = ip
-        self.username = username
-        self.password = password
-        self.port = port
-        self.key_path = key_path
+        self.conn_url = conn_url
         self.connection = None
 
     def __str__(self):
-        return "<Node: url={0!r} roles={1} >".format(self.ip,
-                                                     ", ".join(self.roles))
+        templ = "<Node: url={conn_url!r} roles={roles}" + \
+                " connected={is_connected}>"
+        return templ.format(conn_url=self.conn_url,
+                            roles=", ".join(self.roles),
+                            is_connected=self.connection is not None)
 
     def __repr__(self):
         return str(self)
-
-    def set_conn_attr(self, name, value):
-        setattr(self, name, value)
-
-    @property
-    def connection_url(self):
-        connection = []
-
-        if self.username:
-            connection.append(self.username)
-            if self.password:
-                connection.extend([":", self.password, "@"])
-            connection.append("@")
-
-        connection.append(self.ip)
-        if self.port:
-            connection.extend([":", self.port])
-            if self.key_path:
-                connection.extend([":", self.key_path])
-        else:
-            if self.key_path:
-                connection.extend([":", ":", self.key_path])
-        return "".join(connection)