blob: 8f91251dd91e7d894aa90cf27a1fddf0b6fdf88b [file] [log] [blame]
Matthew Treinish51dfee72013-01-28 15:50:29 -05001# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2013 OpenStack, LLC
4# Copyright 2013 IBM Corp.
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17
18"""Provides methods needed by installation script for OpenStack development
19virtual environments.
20
21Synced in from openstack-common
22"""
23
24import os
25import subprocess
26import sys
27
Matthew Treinish7682cde2013-02-06 16:34:40 -050028
29possible_topdir = os.getcwd()
30if os.path.exists(os.path.join(possible_topdir, "tempest",
31 "__init__.py")):
32 sys.path.insert(0, possible_topdir)
33
34
Matthew Treinish51dfee72013-01-28 15:50:29 -050035from tempest.openstack.common import cfg
36
37
38class InstallVenv(object):
39
40 def __init__(self, root, venv, pip_requires, test_requires, py_version,
41 project):
42 self.root = root
43 self.venv = venv
44 self.pip_requires = pip_requires
45 self.test_requires = test_requires
46 self.py_version = py_version
47 self.project = project
48
49 def die(self, message, *args):
50 print >> sys.stderr, message % args
51 sys.exit(1)
52
53 def check_python_version(self):
54 if sys.version_info < (2, 6):
55 self.die("Need Python Version >= 2.6")
56
57 def run_command_with_code(self, cmd, redirect_output=True,
58 check_exit_code=True):
59 """Runs a command in an out-of-process shell.
60
Joe Gordon2b0591d2013-02-14 23:18:39 +000061 Returns the output of that command. Working directory is self.root.
Matthew Treinish51dfee72013-01-28 15:50:29 -050062 """
63 if redirect_output:
64 stdout = subprocess.PIPE
65 else:
66 stdout = None
67
68 proc = subprocess.Popen(cmd, cwd=self.root, stdout=stdout)
69 output = proc.communicate()[0]
70 if check_exit_code and proc.returncode != 0:
71 self.die('Command "%s" failed.\n%s', ' '.join(cmd), output)
72 return (output, proc.returncode)
73
74 def run_command(self, cmd, redirect_output=True, check_exit_code=True):
75 return self.run_command_with_code(cmd, redirect_output,
76 check_exit_code)[0]
77
78 def get_distro(self):
79 if (os.path.exists('/etc/fedora-release') or
80 os.path.exists('/etc/redhat-release')):
81 return Fedora(self.root, self.venv, self.pip_requires,
82 self.test_requires, self.py_version, self.project)
83 else:
84 return Distro(self.root, self.venv, self.pip_requires,
85 self.test_requires, self.py_version, self.project)
86
87 def check_dependencies(self):
88 self.get_distro().install_virtualenv()
89
90 def create_virtualenv(self, no_site_packages=True):
91 """Creates the virtual environment and installs PIP.
92
93 Creates the virtual environment and installs PIP only into the
94 virtual environment.
95 """
96 if not os.path.isdir(self.venv):
97 print 'Creating venv...',
98 if no_site_packages:
99 self.run_command(['virtualenv', '-q', '--no-site-packages',
100 self.venv])
101 else:
102 self.run_command(['virtualenv', '-q', self.venv])
103 print 'done.'
Joe Gordon2b0591d2013-02-14 23:18:39 +0000104 print 'Installing pip in venv...',
Matthew Treinish51dfee72013-01-28 15:50:29 -0500105 if not self.run_command(['tools/with_venv.sh', 'easy_install',
106 'pip>1.0']).strip():
107 self.die("Failed to install pip.")
108 print 'done.'
109 else:
110 print "venv already exists..."
111 pass
112
113 def pip_install(self, *args):
114 self.run_command(['tools/with_venv.sh',
115 'pip', 'install', '--upgrade'] + list(args),
116 redirect_output=False)
117
118 def install_dependencies(self):
119 print 'Installing dependencies with pip (this can take a while)...'
120
121 # First things first, make sure our venv has the latest pip and
122 # distribute.
123 # NOTE: we keep pip at version 1.1 since the most recent version causes
124 # the .venv creation to fail. See:
125 # https://bugs.launchpad.net/nova/+bug/1047120
126 self.pip_install('pip==1.1')
127 self.pip_install('distribute')
128
129 # Install greenlet by hand - just listing it in the requires file does
130 # not
131 # get it installed in the right order
132 self.pip_install('greenlet')
133
134 self.pip_install('-r', self.pip_requires)
135 self.pip_install('-r', self.test_requires)
136
137 def post_process(self):
138 self.get_distro().post_process()
139
140 def parse_args(self, argv):
141 """Parses command-line arguments."""
142 cli_opts = [
143 cfg.BoolOpt('no-site-packages',
144 default=False,
145 short='n',
146 help="Do not inherit packages from global Python"
147 "install"),
148 ]
149 CLI = cfg.ConfigOpts()
150 CLI.register_cli_opts(cli_opts)
151 CLI(argv[1:])
152 return CLI
153
154
155class Distro(InstallVenv):
156
157 def check_cmd(self, cmd):
158 return bool(self.run_command(['which', cmd],
159 check_exit_code=False).strip())
160
161 def install_virtualenv(self):
162 if self.check_cmd('virtualenv'):
163 return
164
165 if self.check_cmd('easy_install'):
166 print 'Installing virtualenv via easy_install...',
167 if self.run_command(['easy_install', 'virtualenv']):
168 print 'Succeeded'
169 return
170 else:
171 print 'Failed'
172
173 self.die('ERROR: virtualenv not found.\n\n%s development'
174 ' requires virtualenv, please install it using your'
175 ' favorite package management tool' % self.project)
176
177 def post_process(self):
178 """Any distribution-specific post-processing gets done here.
179
180 In particular, this is useful for applying patches to code inside
181 the venv.
182 """
183 pass
184
185
186class Fedora(Distro):
187 """This covers all Fedora-based distributions.
188
189 Includes: Fedora, RHEL, CentOS, Scientific Linux
190 """
191
192 def check_pkg(self, pkg):
193 return self.run_command_with_code(['rpm', '-q', pkg],
194 check_exit_code=False)[1] == 0
195
196 def yum_install(self, pkg, **kwargs):
197 print "Attempting to install '%s' via yum" % pkg
198 self.run_command(['sudo', 'yum', 'install', '-y', pkg], **kwargs)
199
200 def apply_patch(self, originalfile, patchfile):
201 self.run_command(['patch', originalfile, patchfile])
202
203 def install_virtualenv(self):
204 if self.check_cmd('virtualenv'):
205 return
206
207 if not self.check_pkg('python-virtualenv'):
208 self.yum_install('python-virtualenv', check_exit_code=False)
209
210 super(Fedora, self).install_virtualenv()
211
212 def post_process(self):
213 """Workaround for a bug in eventlet.
214
215 This currently affects RHEL6.1, but the fix can safely be
216 applied to all RHEL and Fedora distributions.
217
218 This can be removed when the fix is applied upstream.
219
220 Nova: https://bugs.launchpad.net/nova/+bug/884915
221 Upstream: https://bitbucket.org/which_linden/eventlet/issue/89
222 """
223
224 # Install "patch" program if it's not there
225 if not self.check_pkg('patch'):
226 self.yum_install('patch')
227
228 # Apply the eventlet patch
229 self.apply_patch(os.path.join(self.venv, 'lib', self.py_version,
230 'site-packages',
231 'eventlet/green/subprocess.py'),
232 'contrib/redhat-eventlet.patch')