df781ee172c344e49f95bbbc166704edccc8504e
[doctor.git] / doctor_tests / installer / base.py
1 ##############################################################################
2 # Copyright (c) 2017 ZTE Corporation and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9 import abc
10 import getpass
11 import grp
12 import os
13 import pwd
14 import re
15 import six
16 import stat
17 import subprocess
18 import time
19
20 from doctor_tests.common import utils
21 from doctor_tests.identity_auth import get_session
22 from doctor_tests.os_clients import nova_client
23
24
25 @six.add_metaclass(abc.ABCMeta)
26 class BaseInstaller(object):
27     def __init__(self, conf, log):
28         self.conf = conf
29         self.log = log
30         self.servers = list()
31         self.use_containers = False
32
33     @abc.abstractproperty
34     def node_user_name(self):
35         """user name for login to cloud node"""
36
37     @abc.abstractmethod
38     def get_ssh_key_from_installer(self):
39         pass
40
41     @abc.abstractmethod
42     def get_host_ip_from_hostname(self, hostname):
43         pass
44
45     @abc.abstractmethod
46     def setup(self):
47         pass
48
49     @abc.abstractmethod
50     def cleanup(self):
51         pass
52
53     def create_flavor(self):
54         self.nova = \
55             nova_client(self.conf.nova_version,
56                         get_session())
57         flavors = {flavor.name: flavor for flavor in self.nova.flavors.list()}
58         if self.conf.flavor not in flavors:
59             self.nova.flavors.create(self.conf.flavor, 512, 1, 1)
60
61     def setup_stunnel(self):
62         self.log.info('Setup ssh stunnel in %s installer......'
63                       % self.conf.installer.type)
64         tunnels = [self.conf.consumer.port]
65         if self.conf.test_case == 'maintenance':
66             tunnel_uptime = 1200
67             tunnels += [self.conf.app_manager.port, self.conf.inspector.port]
68         elif self.conf.test_case == 'all':
69             tunnel_uptime = 1800
70             tunnels += [self.conf.app_manager.port, self.conf.inspector.port]
71         else:
72             tunnel_uptime = 600
73
74         for node_ip in self.controllers:
75             for port in tunnels:
76                 self.log.info('tunnel for port %s' % port)
77                 cmd = ("ssh -o UserKnownHostsFile=/dev/null"
78                        " -o StrictHostKeyChecking=no"
79                        " -i %s %s@%s -R %s:localhost:%s"
80                        " sleep %s > ssh_tunnel.%s.%s"
81                        " 2>&1 < /dev/null "
82                        % (self.key_file,
83                           self.node_user_name,
84                           node_ip,
85                           port,
86                           port,
87                           tunnel_uptime,
88                           node_ip,
89                           port))
90                 server = subprocess.Popen('exec ' + cmd, shell=True)
91                 self.servers.append(server)
92         if self.conf.admin_tool.type == 'fenix':
93             port = self.conf.admin_tool.port
94             self.log.info('tunnel for port %s' % port)
95             cmd = ("ssh -o UserKnownHostsFile=/dev/null"
96                    " -o StrictHostKeyChecking=no"
97                    " -i %s %s@%s -L %s:localhost:%s"
98                    " sleep %s > ssh_tunnel.%s.%s"
99                    " 2>&1 < /dev/null "
100                    % (self.key_file,
101                       self.node_user_name,
102                       node_ip,
103                       port,
104                       port,
105                       tunnel_uptime,
106                       node_ip,
107                       port))
108             server = subprocess.Popen('exec ' + cmd, shell=True)
109             self.servers.append(server)
110
111     def _get_ssh_key(self, client, key_path):
112         self.log.info('Get SSH keys from %s installer......'
113                       % self.conf.installer.type)
114
115         if self.key_file is not None:
116             self.log.info('Already have SSH keys from %s installer......'
117                           % self.conf.installer.type)
118             return self.key_file
119
120         ssh_key = '{0}/{1}'.format(utils.get_doctor_test_root_dir(),
121                                    'instack_key')
122         client.scp(key_path, ssh_key, method='get')
123         user = getpass.getuser()
124         uid = pwd.getpwnam(user).pw_uid
125         gid = grp.getgrnam(user).gr_gid
126         os.chown(ssh_key, uid, gid)
127         os.chmod(ssh_key, stat.S_IREAD)
128         return ssh_key
129
130     def get_transport_url(self):
131         client = utils.SSHClient(self.controllers[0], self.node_user_name,
132                                  key_filename=self.key_file)
133         if self.use_containers:
134             ncbase = "/var/lib/config-data/puppet-generated/nova"
135         else:
136             ncbase = ""
137         try:
138             cmd = 'sudo grep "^transport_url" %s/etc/nova/nova.conf' % ncbase
139             ret, url = client.ssh(cmd)
140             if ret:
141                 raise Exception('Exec command to get transport from '
142                                 'controller(%s) in Apex installer failed, '
143                                 'ret=%s, output=%s'
144                                 % (self.controllers[0], ret, url))
145             else:
146                 # need to use ip instead of hostname
147                 ret = (re.sub("@.*:", "@%s:" % self.controllers[0],
148                        url[0].split("=", 1)[1]))
149         except:
150             cmd = 'grep -i "^rabbit" %s/etc/nova/nova.conf' % ncbase
151             ret, lines = client.ssh(cmd)
152             if ret:
153                 raise Exception('Exec command to get transport from '
154                                 'controller(%s) in Apex installer failed, '
155                                 'ret=%s, output=%s'
156                                 % (self.controllers[0], ret, url))
157             else:
158                 for line in lines.split('\n'):
159                     if line.startswith("rabbit_userid"):
160                         rabbit_userid = line.split("=")
161                     if line.startswith("rabbit_port"):
162                         rabbit_port = line.split("=")
163                     if line.startswith("rabbit_password"):
164                         rabbit_password = line.split("=")
165                 ret = "rabbit://%s:%s@%s:%s/?ssl=0" % (rabbit_userid,
166                                                        rabbit_password,
167                                                        self.controllers[0],
168                                                        rabbit_port)
169         self.log.debug('get_transport_url %s' % ret)
170         return ret
171
172     def _run_cmd_remote(self, client, command):
173         self.log.info('Run command=%s in %s installer......'
174                       % (command, self.conf.installer.type))
175
176         ret, output = client.ssh(command)
177         if ret:
178             raise Exception('Exec command in %s installer failed,'
179                             'ret=%s, output=%s'
180                             % (self.conf.installer.type,
181                                ret, output))
182         self.log.info('Output=%s command=%s in %s installer'
183                       % (output, command, self.conf.installer.type))
184         return output
185
186     def _check_cmd_remote(self, client, command):
187         self.log.info('Check command=%s return in %s installer......'
188                       % (command, self.conf.installer.type))
189
190         ret, output = client.ssh(command, raise_enabled=False)
191         self.log.info('return %s' % ret)
192         if ret == 0:
193             ret = True
194         else:
195             ret = False
196         return ret
197
198     @utils.run_async
199     def _run_apply_patches(self, client, restart_cmd, script_names,
200                            python='python3'):
201         installer_dir = os.path.dirname(os.path.realpath(__file__))
202
203         if isinstance(script_names, list):
204             for script_name in script_names:
205                 script_abs_path = '{0}/{1}/{2}'.format(installer_dir,
206                                                        'common', script_name)
207                 try:
208                     client.scp(script_abs_path, script_name)
209                 except:
210                     client.scp(script_abs_path, script_name)
211                 try:
212                     cmd = 'sudo %s %s' % (python, script_name)
213                     ret, output = client.ssh(cmd)
214                 except:
215                     ret, output = client.ssh(cmd)
216
217                 if ret:
218                     raise Exception('Do the command in remote'
219                                     ' node failed, ret=%s, cmd=%s, output=%s'
220                                     % (ret, cmd, output))
221             if 'nova' in restart_cmd:
222                 # Make sure scheduler has proper cpu_allocation_ratio
223                 time.sleep(5)
224             client.ssh(restart_cmd)