modules.opnfv: fuel adapter: Switch to MCP
[releng.git] / modules / opnfv / utils / ssh_utils.py
1 ##############################################################################
2 # Copyright (c) 2015 Ericsson AB and others.
3 # Authors: George Paraskevopoulos (geopar@intracom-telecom.com)
4 #          Jose Lausuch (jose.lausuch@ericsson.com)
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
9 ##############################################################################
10
11
12 import os
13 import paramiko
14
15 from opnfv.utils import opnfv_logger as logger
16
17 logger = logger.Logger("SSH utils").getLogger()
18 SSH_TIMEOUT = 60
19
20 ''' Monkey Patch paramiko _custom_start_client '''
21 # We are using paramiko 2.1.1 and in the CI in the SFC
22 # test we are facing this issue:
23 # https://github.com/robotframework/SSHLibrary/issues/158
24 # The fix was merged in paramiko 2.1.3 in this PR:
25 # https://github.com/robotframework/SSHLibrary/pull/159/files
26 # Until we upgrade we can use this monkey patch to work
27 # around the issue
28
29
30 def _custom_start_client(self, *args, **kwargs):
31     self.banner_timeout = 45
32     self._orig_start_client(*args, **kwargs)
33
34
35 paramiko.transport.Transport._orig_start_client = \
36     paramiko.transport.Transport.start_client
37 paramiko.transport.Transport.start_client = _custom_start_client
38 ''' Monkey Patch paramiko _custom_start_client '''
39
40
41 def get_ssh_client(hostname,
42                    username,
43                    password=None,
44                    proxy=None,
45                    pkey_file=None):
46     client = None
47     try:
48         if proxy is None:
49             client = paramiko.SSHClient()
50         else:
51             client = ProxyHopClient()
52             proxy_password = proxy.get('password', None)
53             proxy_pkey_file = proxy.get('pkey_file', '/root/.ssh/id_rsa')
54             client.configure_jump_host(proxy['ip'],
55                                        proxy['username'],
56                                        proxy_password,
57                                        proxy_pkey_file)
58         if client is None:
59             raise Exception('Could not connect to client')
60
61         client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
62         if pkey_file is not None:
63             key = paramiko.RSAKey.from_private_key_file(pkey_file)
64             client.load_system_host_keys()
65             client.connect(hostname,
66                            username=username,
67                            pkey=key,
68                            timeout=SSH_TIMEOUT)
69         else:
70             client.connect(hostname,
71                            username=username,
72                            password=password,
73                            timeout=SSH_TIMEOUT)
74
75         return client
76     except Exception as e:
77         logger.error(e)
78         return None
79
80
81 def get_file(ssh_conn, src, dest):
82     try:
83         sftp = ssh_conn.open_sftp()
84         sftp.get(src, dest)
85         return True
86     except Exception as e:
87         logger.error("Error [get_file(ssh_conn, '%s', '%s']: %s" %
88                      (src, dest, e))
89         return None
90
91
92 def put_file(ssh_conn, src, dest):
93     try:
94         sftp = ssh_conn.open_sftp()
95         sftp.put(src, dest)
96         return True
97     except Exception as e:
98         logger.error("Error [put_file(ssh_conn, '%s', '%s']: %s" %
99                      (src, dest, e))
100         return None
101
102
103 class ProxyHopClient(paramiko.SSHClient):
104     '''
105     Connect to a remote server using a proxy hop
106     '''
107
108     def __init__(self, *args, **kwargs):
109         self.proxy_ssh = None
110         self.proxy_transport = None
111         self.proxy_channel = None
112         self.proxy_ip = None
113         self.proxy_ssh_key = None
114         self.local_ssh_key = os.path.join(os.getcwd(), 'id_rsa')
115         super(ProxyHopClient, self).__init__(*args, **kwargs)
116
117     def configure_jump_host(self, jh_ip, jh_user, jh_pass,
118                             jh_ssh_key='/root/.ssh/id_rsa'):
119         self.proxy_ip = jh_ip
120         self.proxy_ssh_key = jh_ssh_key
121         self.local_ssh_key = os.path.join(os.getcwd(),
122                                           jh_ssh_key.split('/')[-1])
123         self.proxy_ssh = paramiko.SSHClient()
124         self.proxy_ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
125         self.proxy_ssh.connect(jh_ip,
126                                username=jh_user,
127                                password=jh_pass,
128                                timeout=SSH_TIMEOUT)
129         self.proxy_transport = self.proxy_ssh.get_transport()
130
131     def connect(self, hostname, port=22, username='root', password=None,
132                 pkey=None, key_filename=None, timeout=None, allow_agent=True,
133                 look_for_keys=True, compress=False, sock=None, gss_auth=False,
134                 gss_kex=False, gss_deleg_creds=True, gss_host=None,
135                 banner_timeout=None):
136         try:
137             if self.proxy_ssh is None:
138                 raise Exception('You must configure the jump '
139                                 'host before calling connect')
140
141             get_file_res = get_file(self.proxy_ssh,
142                                     self.proxy_ssh_key,
143                                     self.local_ssh_key)
144             if get_file_res is None:
145                 raise Exception('Could\'t fetch SSH key from jump host')
146             if self.proxy_ssh_key.split('/')[-1] == 'id_dsa':
147                 proxy_key = (paramiko.DSSKey
148                              .from_private_key_file(self.local_ssh_key))
149             else:
150                 proxy_key = (paramiko.RSAKey
151                              .from_private_key_file(self.local_ssh_key))
152
153             self.proxy_channel = self.proxy_transport.open_channel(
154                 "direct-tcpip",
155                 (hostname, 22),
156                 (self.proxy_ip, 22))
157
158             self.set_missing_host_key_policy(paramiko.AutoAddPolicy())
159             super(ProxyHopClient, self).connect(hostname,
160                                                 username=username,
161                                                 pkey=proxy_key,
162                                                 sock=self.proxy_channel,
163                                                 timeout=timeout)
164             os.remove(self.local_ssh_key)
165         except Exception as e:
166             logger.error(e)