2.0 is on the way
diff --git a/wally/discover/discover.py b/wally/discover/discover.py
index e0d7dab..35ddc62 100644
--- a/wally/discover/discover.py
+++ b/wally/discover/discover.py
@@ -13,6 +13,7 @@
 from ..node_interfaces import NodeInfo
 from ..node import connect, setup_rpc
 from ..ssh_utils import parse_ssh_uri
+from ..test_run_class import TestRun
 
 
 logger = logging.getLogger("wally.discover")
@@ -39,7 +40,10 @@
 DiscoveryResult = NamedTuple("DiscoveryResult", [("os_creds", Optional[OSCreds]), ("nodes", List[NodeInfo])])
 
 
-def discover(discover_list: List[str], clusters_info: ConfigBlock, discover_nodes: bool = True) -> DiscoveryResult:
+def discover(ctx: TestRun,
+             discover_list: List[str],
+             clusters_info: ConfigBlock,
+             discover_nodes: bool = True) -> DiscoveryResult:
     """Discover nodes in clusters"""
 
     new_nodes = []  # type: List[NodeInfo]
@@ -52,21 +56,7 @@
                 continue
 
             cluster_info = clusters_info["openstack"]  # type: ConfigBlock
-
-            conn = cluster_info['connection']  # type: ConfigBlock
-            if not conn:
-                logger.error("No connection provided for %s. Skipping", cluster)
-                continue
-
-            user, passwd, tenant = parse_creds(conn['creds'])
-
-            auth_data = dict(auth_url=conn['auth_url'],
-                             username=user,
-                             api_key=passwd,
-                             project_id=tenant)  # type: Dict[str, str]
-
-            logger.debug("Discovering openstack nodes with connection details: %r", conn)
-            new_nodes.extend(openstack.discover_openstack_nodes(auth_data, cluster_info))
+            new_nodes.extend(openstack.discover_openstack_nodes(ctx.os_connection, cluster_info))
 
         elif cluster == "fuel" or cluster == "fuel_openrc_only":
             if cluster == "fuel_openrc_only":
@@ -74,15 +64,17 @@
 
             fuel_node_info = NodeInfo(parse_ssh_uri(clusters_info['fuel']['ssh_creds']), {'fuel_master'})
             try:
-                fuel_rpc_conn = setup_rpc(connect(fuel_node_info))
+                fuel_rpc_conn = setup_rpc(connect(fuel_node_info), ctx.rpc_code)
             except AuthenticationException:
                 raise StopTestError("Wrong fuel credentials")
             except Exception:
                 logger.exception("While connection to FUEL")
                 raise StopTestError("Failed to connect to FUEL")
 
+            # TODO(koder): keep FUEL rpc in context? Maybe open this connection on upper stack level?
             with fuel_rpc_conn:
-                nodes, fuel_info = fuel.discover_fuel_nodes(fuel_rpc_conn, clusters_info['fuel'], discover_nodes)
+                nodes, fuel_info = fuel.discover_fuel_nodes(
+                    fuel_rpc_conn, ctx.fuel_conn, clusters_info['fuel'], discover_nodes)
                 new_nodes.extend(nodes)
 
                 if fuel_info.openrc:
@@ -105,7 +97,7 @@
                 conf = clusters_info["ceph"].get("conf")
                 key = clusters_info["ceph"].get("key")
                 info = NodeInfo(parse_ssh_uri(root_node_uri), set())
-                with setup_rpc(connect(info)) as ceph_root_conn:
+                with setup_rpc(connect(info), ctx.rpc_code) as ceph_root_conn:
                     new_nodes.extend(ceph.discover_ceph_nodes(ceph_root_conn, cluster=cluster, conf=conf, key=key))
             else:
                 logger.warning("Skip ceph cluster discovery")
diff --git a/wally/discover/fuel.py b/wally/discover/fuel.py
index 119cbd0..7b4f90f 100644
--- a/wally/discover/fuel.py
+++ b/wally/discover/fuel.py
@@ -1,12 +1,12 @@
 import logging
 import socket
-from typing import Dict, Any, Tuple, List, NamedTuple, Union
+from typing import Dict, Any, Tuple, List, NamedTuple, Union, cast
 from urllib.parse import urlparse
 
 from .. import fuel_rest_api
 from ..node_interfaces import NodeInfo, IRPCNode
 from ..ssh_utils import ConnCreds
-from ..utils import parse_creds, check_input_param
+from ..utils import check_input_param
 
 logger = logging.getLogger("wally.discover")
 
@@ -18,50 +18,41 @@
 
 
 def discover_fuel_nodes(fuel_master_node: IRPCNode,
+                        fuel_conn: fuel_rest_api.Connection,
                         fuel_data: Dict[str, Any],
                         discover_nodes: bool = True) -> Tuple[List[NodeInfo], FuelNodeInfo]:
     """Discover nodes in fuel cluster, get openrc for selected cluster"""
 
-    # parse FUEL REST credentials
-    username, tenant_name, password = parse_creds(fuel_data['creds'])
-    creds = {"username": username,
-             "tenant_name": tenant_name,
-             "password": password}
-
-    # connect to FUEL
-    conn = fuel_rest_api.KeystoneAuth(fuel_data['url'], creds, headers=None)
     msg = "openstack_env should be provided in fuel config"
     check_input_param('openstack_env' in fuel_data, msg)
 
     # get cluster information from REST API
-    cluster_id = fuel_rest_api.get_cluster_id(conn, fuel_data['openstack_env'])
-    cluster = fuel_rest_api.reflect_cluster(conn, cluster_id)
-    version = fuel_rest_api.FuelInfo(conn).get_version()
+    cluster_id = fuel_rest_api.get_cluster_id(fuel_conn, fuel_data['openstack_env'])
+    cluster = fuel_rest_api.reflect_cluster(fuel_conn, cluster_id)
+    version = fuel_rest_api.FuelInfo(fuel_conn).get_version()
 
     if not discover_nodes:
         logger.warning("Skip fuel cluster discovery")
-        return [], FuelNodeInfo(version, None, cluster.get_openrc())
+        return [], FuelNodeInfo(version, None, cluster.get_openrc())  # type: ignore
 
-    fuel_nodes = list(cluster.get_nodes())
-
-    logger.info("Found FUEL {0}".format(".".join(map(str, version))))
-
-    network = 'fuelweb_admin' if version >= [6, 0] else 'admin'
-
-    fuel_host = urlparse(fuel_data['url']).hostname
-    fuel_ip = socket.gethostbyname(fuel_host)
-    fuel_ext_iface = fuel_master_node.get_interface(fuel_ip)
+    logger.info("Found fuel {0}".format(".".join(map(str, version))))
 
     # get FUEL master key to connect to cluster nodes via ssh
     logger.debug("Downloading fuel master key")
     fuel_key = fuel_master_node.get_file_content('/root/.ssh/id_rsa')
 
+    network = 'fuelweb_admin' if version >= [6, 0] else 'admin'
+    fuel_ip = socket.gethostbyname(fuel_conn.host)
+    fuel_ext_iface = fuel_master_node.get_interface(fuel_ip)
+
     nodes = []
-    for fuel_node in fuel_nodes:
+    for fuel_node in list(cluster.get_nodes()):
         ip = str(fuel_node.get_ip(network))
-        nodes.append(NodeInfo(ConnCreds(ip, "root", key=fuel_key), roles=set(fuel_node.get_roles())))
+        creds = ConnCreds(ip, "root", key=fuel_key)
+        nodes.append(NodeInfo(creds, roles=set(fuel_node.get_roles())))
 
     logger.debug("Found {} fuel nodes for env {}".format(len(nodes), fuel_data['openstack_env']))
 
-    return nodes, FuelNodeInfo(version, fuel_ext_iface, cluster.get_openrc())
+    return nodes, FuelNodeInfo(version, fuel_ext_iface,
+                               cast(Dict[str, Union[str, bool]], cluster.get_openrc()))
 
diff --git a/wally/discover/openstack.py b/wally/discover/openstack.py
index 88e8656..f590359 100644
--- a/wally/discover/openstack.py
+++ b/wally/discover/openstack.py
@@ -1,13 +1,11 @@
 import socket
 import logging
-from typing import Dict, Any, List
-
-
-from novaclient.client import Client
+from typing import Dict, Any, List, Optional, cast
 
 from ..node_interfaces import NodeInfo
 from ..config import ConfigBlock
-from ..utils import parse_creds
+from ..ssh_utils import ConnCreds
+from ..start_vms import OSConnection, NovaClient
 
 
 logger = logging.getLogger("wally.discover")
@@ -24,73 +22,45 @@
     raise ValueError("VM {} has no floating ip".format(vm))
 
 
-def get_ssh_url(user: str, password: str, ip: str, key: str) -> str:
-    """Get ssh connection URL from parts"""
-
-    if password is not None:
-        assert key is None, "Both key and password provided"
-        return "ssh://{}:{}@{}".format(user, password, ip)
-    else:
-        assert key is not None, "None of key/password provided"
-        return "ssh://{}@{}::{}".format(user, ip, key)
-
-
-def discover_vms(client: Client, search_opts: Dict) -> List[NodeInfo]:
+def discover_vms(client: NovaClient, search_data: str) -> List[NodeInfo]:
     """Discover virtual machines"""
-    user, password, key = parse_creds(search_opts.pop('auth'))
-
-    servers = client.servers.list(search_opts=search_opts)
+    name, user, key_file = search_data.split(",")
+    servers = client.servers.list(search_opts={"name": name})
     logger.debug("Found %s openstack vms" % len(servers))
 
     nodes = []  # type: List[NodeInfo]
     for server in servers:
         ip = get_floating_ip(server)
-        nodes.append(NodeInfo(get_ssh_url(user, password, ip, key), roles={"test_vm"}))
+        creds = ConnCreds(host=ip, user=user, key_file=key_file)
+        nodes.append(NodeInfo(creds, roles={"test_vm"}))
+
     return nodes
 
 
-def discover_services(client: Client, opts: Dict[str, Any]) -> List[NodeInfo]:
+def discover_openstack_nodes(conn: OSConnection, conf: ConfigBlock) -> List[NodeInfo]:
     """Discover openstack services for given cluster"""
-    user, password, key = parse_creds(opts.pop('auth'))
+    os_nodes_auth = conf['auth']  # type: str
 
-    services = []
-    if opts['service'] == "all":
-        services = client.services.list()
+    if os_nodes_auth.count(":") == 2:
+        user, password, key_file = os_nodes_auth.split(":")  # type: str, Optional[str], Optional[str]
+        if not password:
+            password = None
     else:
-        if isinstance(opts['service'], str):
-            opts['service'] = [opts['service']]
+        user, password = os_nodes_auth.split(":")
+        key_file = None
 
-        for s in opts['service']:
-            services.extend(client.services.list(binary=s))
-
-    host_services_mapping = {}  # type: Dict[str, [str]]
+    services = conn.nova.services.list()  # type: List[Any]
+    host_services_mapping = {}  # type: Dict[str, List[str]]
 
     for service in services:
-        ip = socket.gethostbyname(service.host)
+        ip = cast(str, socket.gethostbyname(service.host))
         host_services_mapping.get(ip, []).append(service.binary)
 
-    logger.debug("Found %s openstack service nodes" %
-                 len(host_services_mapping))
+    logger.debug("Found %s openstack service nodes" % len(host_services_mapping))
 
     nodes = []  # type: List[NodeInfo]
     for host, services in host_services_mapping.items():
-        ssh_url = get_ssh_url(user, password, host, key)
-        nodes.append(NodeInfo(ssh_url, services))
+        creds = ConnCreds(host=host, user=user, passwd=password, key_file=key_file)
+        nodes.append(NodeInfo(creds, set(services)))
 
     return nodes
-
-
-def discover_openstack_nodes(conn_details: Dict[str, str], conf: ConfigBlock) -> List[NodeInfo]:
-    """Discover vms running in openstack
-    conn_details - dict with openstack connection details -
-        auth_url, api_key (password), username
-    conf - test configuration object
-    """
-    client = Client(version='1.1', **conn_details)
-
-    if conf.get('discover'):
-        services_to_discover = conf['discover'].get('nodes')
-        if services_to_discover:
-            return discover_services(client, services_to_discover)
-
-    return []