Refactor the underlay.ssh update process for VCP minions

fuel-devops node names in the underlay.yaml can be
different from actual hostnames configured on hosts:
  underlay.yaml: ctl01
  hostname -f: ctl01.cookied-cicd-k8s-calico.local

Shorter names are connected to qemu limitation for
monitor.lock path and how the fuel-devops creates
unique names for the environment nodes.

1. To not double the same nodes in the underlay.ssh, match
   the VCP nodes to underlay.ssh nodes not by name, but by
   IP address and address_pool.
   Add new method update_ssh_data_from_minions() to
   SaltManager with this functional.

2. Add new attribute to underlay.ssh:  minion_id , which will
   provide mapping from underlay.ssh to the minion_id for the
   nodes.

3. Add helper method host_by_minion_id() to UnderlayManager
   to get host IP by minion_id

Change-Id: I510d9a777df8f308c1a7fede7b4ec2feb314c5bd
diff --git a/tcp_tests/managers/envmanager_devops.py b/tcp_tests/managers/envmanager_devops.py
index f776221..17ad452 100644
--- a/tcp_tests/managers/envmanager_devops.py
+++ b/tcp_tests/managers/envmanager_devops.py
@@ -129,6 +129,7 @@
         for d_node in self.__env.get_nodes(role__in=roles):
             ssh_data = {
                 'node_name': d_node.name,
+                'minion_id': d_node.name,
                 'roles': [d_node.role],
                 'address_pool': self._get_network_pool(
                     ext.NETWORK_TYPE.admin).address_pool.name,
diff --git a/tcp_tests/managers/saltmanager.py b/tcp_tests/managers/saltmanager.py
index 6fad0e4..a468b02 100644
--- a/tcp_tests/managers/saltmanager.py
+++ b/tcp_tests/managers/saltmanager.py
@@ -188,13 +188,14 @@
         if len(hosts) == 0:
             raise LookupError("Hosts is empty or absent")
 
-        def host(node_name, ip):
+        def host(minion_id, ip):
             return {
                 'roles': ['salt_minion'],
                 'keys': [
                     k['private'] for k in self.__config.underlay.ssh_keys
                 ],
-                'node_name': node_name,
+                'node_name': minion_id,
+                'minion_id': minion_id,
                 'host': ip,
                 'address_pool': pool_name,
                 'login': settings.SSH_NODE_CREDENTIALS['login'],
@@ -216,6 +217,25 @@
                        host_list={k: v['ipv4'] for k, v in hosts.items()}))
             raise StopIteration(msg)
 
+    def update_ssh_data_from_minions(self):
+        """Combine existing underlay.ssh with VCP salt minions"""
+        salt_nodes = self.get_ssh_data()
+
+        for salt_node in salt_nodes:
+            nodes = [n for n in self.__config.underlay.ssh
+                     if salt_node['host'] == n['host']
+                     and salt_node['address_pool'] == n['address_pool']]
+            if nodes:
+                # Assume that there can be only one node with such IP address
+                # Just update minion_id for this node
+                nodes[0]['minion_id'] = salt_node['minion_id']
+            else:
+                # New node, add to config.underlay.ssh
+                self.__config.underlay.ssh.append(salt_node)
+
+        self.__underlay.config_ssh = []
+        self.__underlay.add_config_ssh(self.__config.underlay.ssh)
+
     def service_status(self, tgt, service):
         result = self.local(tgt=tgt, fun='service.status', args=service)
         return result['return']
diff --git a/tcp_tests/managers/underlay_ssh_manager.py b/tcp_tests/managers/underlay_ssh_manager.py
index 0bfb463..66f686b 100644
--- a/tcp_tests/managers/underlay_ssh_manager.py
+++ b/tcp_tests/managers/underlay_ssh_manager.py
@@ -39,6 +39,7 @@
           [
             {
               node_name: node1,
+              minion_id: node1.local,
               address_pool: 'public-pool01',
               host: ,
               port: ,
@@ -50,6 +51,7 @@
             },
             {
               node_name: node1,
+              minion_id: node1.local,
               address_pool: 'private-pool01',
               host:
               port:
@@ -61,6 +63,7 @@
             },
             {
               node_name: node2,
+              minion_id: node2.local,
               address_pool: 'public-pool01',
               keys_source_host: node1
               ...
@@ -96,6 +99,7 @@
             ssh_data = {
                 # Required keys:
                 'node_name': ssh['node_name'],
+                'minion_id': ssh['minion_id'],
                 'host': ssh['host'],
                 'login': ssh['login'],
                 'password': ssh['password'],
@@ -122,6 +126,7 @@
             ssh_data = {
                 # Required keys:
                 'node_name': ssh['node_name'],
+                'minion_id': ssh['minion_id'],
                 'host': ssh['host'],
                 'login': ssh['login'],
                 'password': ssh['password'],
@@ -143,7 +148,7 @@
         return keys
 
     def __ssh_data(self, node_name=None, host=None, address_pool=None,
-                   node_role=None):
+                   node_role=None, minion_id=None):
 
         ssh_data = None
 
@@ -171,6 +176,16 @@
                             break
                     else:
                         ssh_data = ssh
+        elif minion_id is not None:
+            for ssh in self.config_ssh:
+                if minion_id == ssh['minion_id']:
+                    if address_pool is not None:
+                        if address_pool == ssh['address_pool']:
+                            ssh_data = ssh
+                            break
+                    else:
+                        ssh_data = ssh
+
         if ssh_data is None:
             LOG.debug("config_ssh - {}".format(self.config_ssh))
             raise Exception('Auth data for node was not found using '
@@ -187,6 +202,15 @@
                 names.append(ssh['node_name'])
         return names
 
+    def minion_ids(self):
+        """Get list of minion ids registered in config.underlay.ssh"""
+
+        ids = []  # List is used to keep the original order of ids
+        for ssh in self.config_ssh:
+            if ssh['minion_id'] not in ids:
+                ids.append(ssh['minion_id'])
+        return ids
+
     def host_by_node_name(self, node_name, address_pool=None):
         ssh_data = self.__ssh_data(node_name=node_name,
                                    address_pool=address_pool)
@@ -197,6 +221,11 @@
                                    address_pool=address_pool)
         return ssh_data['host']
 
+    def host_by_minion_id(self, minion_id, address_pool=None):
+        ssh_data = self.__ssh_data(minion_id=minion_id,
+                                   address_pool=address_pool)
+        return ssh_data['host']
+
     def remote(self, node_name=None, host=None, address_pool=None,
                username=None):
         """Get SSHClient by a node name or hostname.