Merging trunk

This commit is contained in:
Rick Harris 2011-05-20 10:31:23 -05:00
commit 821ee03ced
13 changed files with 259 additions and 262 deletions

View File

@ -27,6 +27,8 @@ import datetime
import IPy
import os
import urllib
import tempfile
import shutil
from nova import compute
from nova import context
@ -316,6 +318,27 @@ class CloudController(object):
'keyMaterial': data['private_key']}
# TODO(vish): when context is no longer an object, pass it here
def import_public_key(self, context, key_name, public_key,
fingerprint=None):
LOG.audit(_("Import key %s"), key_name, context=context)
key = {}
key['user_id'] = context.user_id
key['name'] = key_name
key['public_key'] = public_key
if fingerprint is None:
tmpdir = tempfile.mkdtemp()
pubfile = os.path.join(tmpdir, 'temp.pub')
fh = open(pubfile, 'w')
fh.write(public_key)
fh.close()
(out, err) = utils.execute('ssh-keygen', '-q', '-l', '-f',
'%s' % (pubfile))
fingerprint = out.split(' ')[1]
shutil.rmtree(tmpdir)
key['fingerprint'] = fingerprint
db.key_pair_create(context, key)
return True
def delete_key_pair(self, context, key_name, **kwargs):
LOG.audit(_("Delete key pair %s"), key_name, context=context)
try:

View File

@ -105,15 +105,14 @@ class ExtensionDescriptor(object):
actions = []
return actions
def get_response_extensions(self):
"""List of extensions.ResponseExtension extension objects.
def get_request_extensions(self):
"""List of extensions.RequestException extension objects.
Response extensions are used to insert information into existing
response data.
Request extensions are used to handle custom request data.
"""
response_exts = []
return response_exts
request_exts = []
return request_exts
class ActionExtensionController(common.OpenstackController):
@ -137,7 +136,7 @@ class ActionExtensionController(common.OpenstackController):
return res
class ResponseExtensionController(common.OpenstackController):
class RequestExtensionController(common.OpenstackController):
def __init__(self, application):
self.application = application
@ -148,20 +147,9 @@ class ResponseExtensionController(common.OpenstackController):
def process(self, req, *args, **kwargs):
res = req.get_response(self.application)
content_type = req.best_match_content_type()
# currently response handlers are un-ordered
# currently request handlers are un-ordered
for handler in self.handlers:
res = handler(res)
try:
body = res.body
headers = res.headers
except AttributeError:
default_xmlns = None
body = self._serialize(res, content_type, default_xmlns)
headers = {"Content-Type": content_type}
res = webob.Response()
res.body = body
res.headers = headers
res = handler(req, res)
return res
@ -226,24 +214,24 @@ class ExtensionMiddleware(wsgi.Middleware):
return action_controllers
def _response_ext_controllers(self, application, ext_mgr, mapper):
"""Returns a dict of ResponseExtensionController-s by collection."""
response_ext_controllers = {}
for resp_ext in ext_mgr.get_response_extensions():
if not resp_ext.key in response_ext_controllers.keys():
controller = ResponseExtensionController(application)
mapper.connect(resp_ext.url_route + '.:(format)',
def _request_ext_controllers(self, application, ext_mgr, mapper):
"""Returns a dict of RequestExtensionController-s by collection."""
request_ext_controllers = {}
for req_ext in ext_mgr.get_request_extensions():
if not req_ext.key in request_ext_controllers.keys():
controller = RequestExtensionController(application)
mapper.connect(req_ext.url_route + '.:(format)',
action='process',
controller=controller,
conditions=resp_ext.conditions)
conditions=req_ext.conditions)
mapper.connect(resp_ext.url_route,
mapper.connect(req_ext.url_route,
action='process',
controller=controller,
conditions=resp_ext.conditions)
response_ext_controllers[resp_ext.key] = controller
conditions=req_ext.conditions)
request_ext_controllers[req_ext.key] = controller
return response_ext_controllers
return request_ext_controllers
def __init__(self, application, ext_mgr=None):
@ -271,13 +259,13 @@ class ExtensionMiddleware(wsgi.Middleware):
controller = action_controllers[action.collection]
controller.add_action(action.action_name, action.handler)
# extended responses
resp_controllers = self._response_ext_controllers(application, ext_mgr,
# extended requests
req_controllers = self._request_ext_controllers(application, ext_mgr,
mapper)
for response_ext in ext_mgr.get_response_extensions():
LOG.debug(_('Extended response: %s'), response_ext.key)
controller = resp_controllers[response_ext.key]
controller.add_handler(response_ext.handler)
for request_ext in ext_mgr.get_request_extensions():
LOG.debug(_('Extended request: %s'), request_ext.key)
controller = req_controllers[request_ext.key]
controller.add_handler(request_ext.handler)
self._router = routes.middleware.RoutesMiddleware(self._dispatch,
mapper)
@ -347,17 +335,17 @@ class ExtensionManager(object):
pass
return actions
def get_response_extensions(self):
"""Returns a list of ResponseExtension objects."""
response_exts = []
def get_request_extensions(self):
"""Returns a list of RequestExtension objects."""
request_exts = []
for alias, ext in self.extensions.iteritems():
try:
response_exts.extend(ext.get_response_extensions())
request_exts.extend(ext.get_request_extensions())
except AttributeError:
# NOTE(dprince): Extension aren't required to have response
# NOTE(dprince): Extension aren't required to have request
# extensions
pass
return response_exts
return request_exts
def _check_extension(self, extension):
"""Checks for required methods in extension objects."""
@ -421,9 +409,13 @@ class ExtensionManager(object):
self.extensions[alias] = ext
class ResponseExtension(object):
"""Add data to responses from core nova OpenStack API controllers."""
class RequestExtension(object):
"""Extend requests and responses of core nova OpenStack API controllers.
Provide a way to add data to responses and handle custom request data
that is sent to core nova OpenStack API controllers.
"""
def __init__(self, method, url_route, handler):
self.url_route = url_route
self.handler = handler

View File

@ -63,31 +63,33 @@ class Foxinsocks(object):
self._delete_tweedle))
return actions
def get_response_extensions(self):
response_exts = []
def get_request_extensions(self):
request_exts = []
def _goose_handler(res):
def _goose_handler(req, res):
#NOTE: This only handles JSON responses.
# You can use content type header to test for XML.
data = json.loads(res.body)
data['flavor']['googoose'] = "Gooey goo for chewy chewing!"
return data
data['flavor']['googoose'] = req.GET.get('chewing')
res.body = json.dumps(data)
return res
resp_ext = extensions.ResponseExtension('GET', '/v1.1/flavors/:(id)',
req_ext1 = extensions.RequestExtension('GET', '/v1.1/flavors/:(id)',
_goose_handler)
response_exts.append(resp_ext)
request_exts.append(req_ext1)
def _bands_handler(res):
def _bands_handler(req, res):
#NOTE: This only handles JSON responses.
# You can use content type header to test for XML.
data = json.loads(res.body)
data['big_bands'] = 'Pig Bands!'
return data
res.body = json.dumps(data)
return res
resp_ext2 = extensions.ResponseExtension('GET', '/v1.1/flavors/:(id)',
req_ext2 = extensions.RequestExtension('GET', '/v1.1/flavors/:(id)',
_bands_handler)
response_exts.append(resp_ext2)
return response_exts
request_exts.append(req_ext2)
return request_exts
def _add_tweedle(self, input_dict, req, id):

View File

@ -45,10 +45,10 @@ class StubController(nova.wsgi.Controller):
class StubExtensionManager(object):
def __init__(self, resource_ext=None, action_ext=None, response_ext=None):
def __init__(self, resource_ext=None, action_ext=None, request_ext=None):
self.resource_ext = resource_ext
self.action_ext = action_ext
self.response_ext = response_ext
self.request_ext = request_ext
def get_name(self):
return "Tweedle Beetle Extension"
@ -71,11 +71,11 @@ class StubExtensionManager(object):
action_exts.append(self.action_ext)
return action_exts
def get_response_extensions(self):
response_exts = []
if self.response_ext:
response_exts.append(self.response_ext)
return response_exts
def get_request_extensions(self):
request_extensions = []
if self.request_ext:
request_extensions.append(self.request_ext)
return request_extensions
class ExtensionControllerTest(unittest.TestCase):
@ -183,10 +183,10 @@ class ActionExtensionTest(unittest.TestCase):
self.assertEqual(404, response.status_int)
class ResponseExtensionTest(unittest.TestCase):
class RequestExtensionTest(unittest.TestCase):
def setUp(self):
super(ResponseExtensionTest, self).setUp()
super(RequestExtensionTest, self).setUp()
self.stubs = stubout.StubOutForTesting()
fakes.FakeAuthManager.reset_fake_data()
fakes.FakeAuthDatabase.data = {}
@ -195,42 +195,39 @@ class ResponseExtensionTest(unittest.TestCase):
def tearDown(self):
self.stubs.UnsetAll()
super(ResponseExtensionTest, self).tearDown()
super(RequestExtensionTest, self).tearDown()
def test_get_resources_with_stub_mgr(self):
test_resp = "Gooey goo for chewy chewing!"
def _resp_handler(res):
def _req_handler(req, res):
# only handle JSON responses
data = json.loads(res.body)
data['flavor']['googoose'] = test_resp
return data
data['flavor']['googoose'] = req.GET.get('chewing')
res.body = json.dumps(data)
return res
resp_ext = extensions.ResponseExtension('GET',
req_ext = extensions.RequestExtension('GET',
'/v1.1/flavors/:(id)',
_resp_handler)
_req_handler)
manager = StubExtensionManager(None, None, resp_ext)
manager = StubExtensionManager(None, None, req_ext)
app = fakes.wsgi_app()
ext_midware = extensions.ExtensionMiddleware(app, manager)
request = webob.Request.blank("/v1.1/flavors/1")
request = webob.Request.blank("/v1.1/flavors/1?chewing=bluegoo")
request.environ['api.version'] = '1.1'
response = request.get_response(ext_midware)
self.assertEqual(200, response.status_int)
response_data = json.loads(response.body)
self.assertEqual(test_resp, response_data['flavor']['googoose'])
self.assertEqual('bluegoo', response_data['flavor']['googoose'])
def test_get_resources_with_mgr(self):
test_resp = "Gooey goo for chewy chewing!"
app = fakes.wsgi_app()
ext_midware = extensions.ExtensionMiddleware(app)
request = webob.Request.blank("/v1.1/flavors/1")
request = webob.Request.blank("/v1.1/flavors/1?chewing=newblue")
request.environ['api.version'] = '1.1'
response = request.get_response(ext_midware)
self.assertEqual(200, response.status_int)
response_data = json.loads(response.body)
self.assertEqual(test_resp, response_data['flavor']['googoose'])
self.assertEqual('newblue', response_data['flavor']['googoose'])
self.assertEqual("Pig Bands!", response_data['big_bands'])

View File

@ -0,0 +1 @@
1c:87:d1:d9:32:fd:62:3c:78:2b:c0:ad:c0:15:88:df

View File

@ -0,0 +1 @@
ssh-dss AAAAB3NzaC1kc3MAAACBAMGJlY9XEIm2X234pdO5yFWMp2JuOQx8U0E815IVXhmKxYCBK9ZakgZOIQmPbXoGYyV+mziDPp6HJ0wKYLQxkwLEFr51fAZjWQvRss0SinURRuLkockDfGFtD4pYJthekr/rlqMKlBSDUSpGq8jUWW60UJ18FGooFpxR7ESqQRx/AAAAFQC96LRglaUeeP+E8U/yblEJocuiWwAAAIA3XiMR8Skiz/0aBm5K50SeQznQuMJTyzt9S9uaz5QZWiFu69hOyGSFGw8fqgxEkXFJIuHobQQpGYQubLW0NdaYRqyE/Vud3JUJUb8Texld6dz8vGemyB5d1YvtSeHIo8/BGv2msOqR3u5AZTaGCBD9DhpSGOKHEdNjTtvpPd8S8gAAAIBociGZ5jf09iHLVENhyXujJbxfGRPsyNTyARJfCOGl0oFV6hEzcQyw8U/ePwjgvjc2UizMWLl8tsb2FXKHRdc2v+ND3Us+XqKQ33X3ADP4FZ/+Oj213gMyhCmvFTP0u5FmHog9My4CB7YcIWRuUR42WlhQ2IfPvKwUoTk3R+T6Og== www-data@mk

View File

@ -354,6 +354,36 @@ class CloudTestCase(test.TestCase):
self.assertTrue(filter(lambda k: k['keyName'] == 'test1', keys))
self.assertTrue(filter(lambda k: k['keyName'] == 'test2', keys))
def test_import_public_key(self):
# test when user provides all values
result1 = self.cloud.import_public_key(self.context,
'testimportkey1',
'mytestpubkey',
'mytestfprint')
self.assertTrue(result1)
keydata = db.key_pair_get(self.context,
self.context.user.id,
'testimportkey1')
self.assertEqual('mytestpubkey', keydata['public_key'])
self.assertEqual('mytestfprint', keydata['fingerprint'])
# test when user omits fingerprint
pubkey_path = os.path.join(os.path.dirname(__file__), 'public_key')
f = open(pubkey_path + '/dummy.pub', 'r')
dummypub = f.readline().rstrip()
f.close
f = open(pubkey_path + '/dummy.fingerprint', 'r')
dummyfprint = f.readline().rstrip()
f.close
result2 = self.cloud.import_public_key(self.context,
'testimportkey2',
dummypub)
self.assertTrue(result2)
keydata = db.key_pair_get(self.context,
self.context.user.id,
'testimportkey2')
self.assertEqual(dummypub, keydata['public_key'])
self.assertEqual(dummyfprint, keydata['fingerprint'])
def test_delete_key_pair(self):
self._create_key('test')
self.cloud.delete_key_pair(self.context, 'test')

View File

@ -81,34 +81,36 @@ def inject_data(image, key=None, net=None, partition=None, nbd=False):
else:
mapped_device = device
# We can only loopback mount raw images. If the device isn't there,
# it's normally because it's a .vmdk or a .vdi etc
if not os.path.exists(mapped_device):
raise exception.Error('Mapped device was not found (we can'
' only inject raw disk images): %s' %
mapped_device)
# Configure ext2fs so that it doesn't auto-check every N boots
out, err = utils.execute('sudo', 'tune2fs',
'-c', 0, '-i', 0, mapped_device)
tmpdir = tempfile.mkdtemp()
try:
# mount loopback to dir
out, err = utils.execute(
'sudo', 'mount', mapped_device, tmpdir)
if err:
raise exception.Error(_('Failed to mount filesystem: %s')
% err)
# We can only loopback mount raw images. If the device isn't there,
# it's normally because it's a .vmdk or a .vdi etc
if not os.path.exists(mapped_device):
raise exception.Error('Mapped device was not found (we can'
' only inject raw disk images): %s' %
mapped_device)
# Configure ext2fs so that it doesn't auto-check every N boots
out, err = utils.execute('sudo', 'tune2fs',
'-c', 0, '-i', 0, mapped_device)
tmpdir = tempfile.mkdtemp()
try:
inject_data_into_fs(tmpdir, key, net, utils.execute)
# mount loopback to dir
out, err = utils.execute(
'sudo', 'mount', mapped_device, tmpdir)
if err:
raise exception.Error(_('Failed to mount filesystem: %s')
% err)
try:
inject_data_into_fs(tmpdir, key, net, utils.execute)
finally:
# unmount device
utils.execute('sudo', 'umount', mapped_device)
finally:
# unmount device
utils.execute('sudo', 'umount', mapped_device)
# remove temporary directory
utils.execute('rmdir', tmpdir)
finally:
# remove temporary directory
utils.execute('rmdir', tmpdir)
if not partition is None:
# remove partitions
utils.execute('sudo', 'kpartx', '-d', device)

View File

@ -21,19 +21,10 @@
Handling of VM disk images.
"""
import os.path
import shutil
import sys
import time
import urllib2
import urlparse
from nova import context
from nova import flags
from nova import log as logging
from nova import utils
from nova.auth import manager
from nova.auth import signer
FLAGS = flags.FLAGS
@ -52,66 +43,6 @@ def fetch(image_id, path, _user, _project):
return metadata
# NOTE(vish): The methods below should be unnecessary, but I'm leaving
# them in case the glance client does not work on windows.
def _fetch_image_no_curl(url, path, headers):
request = urllib2.Request(url)
for (k, v) in headers.iteritems():
request.add_header(k, v)
def urlretrieve(urlfile, fpath):
chunk = 1 * 1024 * 1024
f = open(fpath, "wb")
while 1:
data = urlfile.read(chunk)
if not data:
break
f.write(data)
urlopened = urllib2.urlopen(request)
urlretrieve(urlopened, path)
LOG.debug(_("Finished retreving %(url)s -- placed in %(path)s") % locals())
def _fetch_s3_image(image, path, user, project):
url = image_url(image)
# This should probably move somewhere else, like e.g. a download_as
# method on User objects and at the same time get rewritten to use
# a web client.
headers = {}
headers['Date'] = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime())
(_, _, url_path, _, _, _) = urlparse.urlparse(url)
access = manager.AuthManager().get_access_key(user, project)
signature = signer.Signer(user.secret.encode()).s3_authorization(headers,
'GET',
url_path)
headers['Authorization'] = 'AWS %s:%s' % (access, signature)
if sys.platform.startswith('win'):
return _fetch_image_no_curl(url, path, headers)
else:
cmd = ['/usr/bin/curl', '--fail', '--silent', url]
for (k, v) in headers.iteritems():
cmd += ['-H', '\'%s: %s\'' % (k, v)]
cmd += ['-o', path]
return utils.execute(*cmd)
def _fetch_local_image(image, path, user, project):
source = _image_path(os.path.join(image, 'image'))
if sys.platform.startswith('win'):
return shutil.copy(source, path)
else:
return utils.execute('cp', source, path)
def _image_path(path):
return os.path.join(FLAGS.images_path, path)
# TODO(vish): xenapi should use the glance client code directly instead
# of retrieving the image using this method.
def image_url(image):

View File

@ -48,6 +48,8 @@ FLAGS = flags.FLAGS
flags.DEFINE_string('default_os_type', 'linux', 'Default OS type')
flags.DEFINE_integer('block_device_creation_timeout', 10,
'time to wait for a block device to be created')
flags.DEFINE_integer('max_kernel_ramdisk_size', 16 * 1024 * 1024,
'maximum size in bytes of kernel or ramdisk images')
XENAPI_POWER_STATE = {
'Halted': power_state.SHUTDOWN,
@ -444,6 +446,12 @@ class VMHelper(HelperBase):
if image_type == ImageType.DISK:
# Make room for MBR.
vdi_size += MBR_SIZE_BYTES
elif image_type == ImageType.KERNEL_RAMDISK and \
vdi_size > FLAGS.max_kernel_ramdisk_size:
max_size = FLAGS.max_kernel_ramdisk_size
raise exception.Error(
_("Kernel/Ramdisk image is too large: %(vdi_size)d bytes, "
"max %(max_size)d bytes") % locals())
name_label = get_name_label_for_image(image)
vdi_ref = cls.create_vdi(session, sr_ref, name_label, vdi_size, False)

View File

@ -25,7 +25,6 @@ import M2Crypto
import os
import pickle
import subprocess
import tempfile
import uuid
from nova import context
@ -1163,18 +1162,17 @@ class SimpleDH(object):
return mpi
def _run_ssl(self, text, which):
base_cmd = ('cat %(tmpfile)s | openssl enc -aes-128-cbc '
'-a -pass pass:%(shared)s -nosalt %(dec_flag)s')
base_cmd = ('openssl enc -aes-128-cbc -a -pass pass:%(shared)s '
'-nosalt %(dec_flag)s')
if which.lower()[0] == 'd':
dec_flag = ' -d'
else:
dec_flag = ''
fd, tmpfile = tempfile.mkstemp()
os.close(fd)
file(tmpfile, 'w').write(text)
shared = self._shared
cmd = base_cmd % locals()
proc = _runproc(cmd)
proc.stdin.write(text)
proc.stdin.close()
proc.wait()
err = proc.stderr.read()
if err:

View File

@ -59,7 +59,13 @@ function run_tests {
function run_pep8 {
echo "Running pep8 ..."
# Opt-out files from pep8
ignore_scripts="*.sh:*nova-debug:*clean-vlans"
ignore_files="*eventlet-patch:*pip-requires"
ignore_dirs="*ajaxterm*"
GLOBIGNORE="$ignore_scripts:$ignore_files:$ignore_dirs"
srcfiles=`find bin -type f ! -name "nova.conf*"`
srcfiles+=" `find tools/*`"
srcfiles+=" nova setup.py plugins/xenserver/xenapi/etc/xapi.d/plugins/glance"
pep8 --repeat --show-pep8 --show-source --exclude=vcsversion.py ${srcfiles}
}

View File

@ -31,119 +31,125 @@ import sys
ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
VENV = os.path.join(ROOT, '.nova-venv')
PIP_REQUIRES = os.path.join(ROOT, 'tools', 'pip-requires')
TWISTED_NOVA='http://nova.openstack.org/Twisted-10.0.0Nova.tar.gz'
PY_VERSION = "python" + str(sys.version_info[0]) + '.' + str(sys.version_info[1])
TWISTED_NOVA = 'http://nova.openstack.org/Twisted-10.0.0Nova.tar.gz'
PY_VERSION = "python%s.%s" % (sys.version_info[0], sys.version_info[1])
def die(message, *args):
print >>sys.stderr, message % args
sys.exit(1)
print >>sys.stderr, message % args
sys.exit(1)
def check_python_version():
if sys.version_info < (2, 6):
die("Need Python Version >= 2.6")
if sys.version_info < (2, 6):
die("Need Python Version >= 2.6")
def run_command(cmd, redirect_output=True, check_exit_code=True):
"""
Runs a command in an out-of-process shell, returning the
output of that command. Working directory is ROOT.
"""
if redirect_output:
stdout = subprocess.PIPE
else:
stdout = None
"""
Runs a command in an out-of-process shell, returning the
output of that command. Working directory is ROOT.
"""
if redirect_output:
stdout = subprocess.PIPE
else:
stdout = None
proc = subprocess.Popen(cmd, cwd=ROOT, stdout=stdout)
output = proc.communicate()[0]
if check_exit_code and proc.returncode != 0:
die('Command "%s" failed.\n%s', ' '.join(cmd), output)
return output
proc = subprocess.Popen(cmd, cwd=ROOT, stdout=stdout)
output = proc.communicate()[0]
if check_exit_code and proc.returncode != 0:
die('Command "%s" failed.\n%s', ' '.join(cmd), output)
return output
HAS_EASY_INSTALL = bool(run_command(['which', 'easy_install'], check_exit_code=False).strip())
HAS_VIRTUALENV = bool(run_command(['which', 'virtualenv'], check_exit_code=False).strip())
HAS_EASY_INSTALL = bool(run_command(['which', 'easy_install'],
check_exit_code=False).strip())
HAS_VIRTUALENV = bool(run_command(['which', 'virtualenv'],
check_exit_code=False).strip())
def check_dependencies():
"""Make sure virtualenv is in the path."""
"""Make sure virtualenv is in the path."""
if not HAS_VIRTUALENV:
print 'not found.'
# Try installing it via easy_install...
if HAS_EASY_INSTALL:
print 'Installing virtualenv via easy_install...',
if not (run_command(['which', 'easy_install']) and
run_command(['easy_install', 'virtualenv'])):
die('ERROR: virtualenv not found.\n\nNova development requires virtualenv,'
' please install it using your favorite package management tool')
print 'done.'
print 'done.'
if not HAS_VIRTUALENV:
print 'not found.'
# Try installing it via easy_install...
if HAS_EASY_INSTALL:
print 'Installing virtualenv via easy_install...',
if not (run_command(['which', 'easy_install']) and
run_command(['easy_install', 'virtualenv'])):
die('ERROR: virtualenv not found.\n\nNova development'
' requires virtualenv, please install it using your'
' favorite package management tool')
print 'done.'
print 'done.'
def create_virtualenv(venv=VENV):
"""Creates the virtual environment and installs PIP only into the
virtual environment
"""
print 'Creating venv...',
run_command(['virtualenv', '-q', '--no-site-packages', VENV])
print 'done.'
print 'Installing pip in virtualenv...',
if not run_command(['tools/with_venv.sh', 'easy_install', 'pip']).strip():
die("Failed to install pip.")
print 'done.'
"""Creates the virtual environment and installs PIP only into the
virtual environment
"""
print 'Creating venv...',
run_command(['virtualenv', '-q', '--no-site-packages', VENV])
print 'done.'
print 'Installing pip in virtualenv...',
if not run_command(['tools/with_venv.sh', 'easy_install', 'pip']).strip():
die("Failed to install pip.")
print 'done.'
def install_dependencies(venv=VENV):
print 'Installing dependencies with pip (this can take a while)...'
# Install greenlet by hand - just listing it in the requires file does not
# get it in stalled in the right order
run_command(['tools/with_venv.sh', 'pip', 'install', '-E', venv, 'greenlet'],
redirect_output=False)
run_command(['tools/with_venv.sh', 'pip', 'install', '-E', venv, '-r', PIP_REQUIRES],
redirect_output=False)
run_command(['tools/with_venv.sh', 'pip', 'install', '-E', venv, TWISTED_NOVA],
redirect_output=False)
print 'Installing dependencies with pip (this can take a while)...'
# Install greenlet by hand - just listing it in the requires file does not
# get it in stalled in the right order
run_command(['tools/with_venv.sh', 'pip', 'install', '-E', venv,
'greenlet'], redirect_output=False)
run_command(['tools/with_venv.sh', 'pip', 'install', '-E', venv, '-r',
PIP_REQUIRES], redirect_output=False)
run_command(['tools/with_venv.sh', 'pip', 'install', '-E', venv,
TWISTED_NOVA], redirect_output=False)
# Tell the virtual env how to "import nova"
pthfile = os.path.join(venv, "lib", PY_VERSION, "site-packages", "nova.pth")
f = open(pthfile, 'w')
f.write("%s\n" % ROOT)
# Patch eventlet (see FAQ # 1485)
patchsrc = os.path.join(ROOT, 'tools', 'eventlet-patch')
patchfile = os.path.join(venv, "lib", PY_VERSION, "site-packages", "eventlet",
"green", "subprocess.py")
patch_cmd = "patch %s %s" % (patchfile, patchsrc)
os.system(patch_cmd)
# Tell the virtual env how to "import nova"
pthfile = os.path.join(venv, "lib", PY_VERSION, "site-packages",
"nova.pth")
f = open(pthfile, 'w')
f.write("%s\n" % ROOT)
# Patch eventlet (see FAQ # 1485)
patchsrc = os.path.join(ROOT, 'tools', 'eventlet-patch')
patchfile = os.path.join(venv, "lib", PY_VERSION, "site-packages",
"eventlet", "green", "subprocess.py")
patch_cmd = "patch %s %s" % (patchfile, patchsrc)
os.system(patch_cmd)
def print_help():
help = """
Nova development environment setup is complete.
help = """
Nova development environment setup is complete.
Nova development uses virtualenv to track and manage Python dependencies
while in development and testing.
Nova development uses virtualenv to track and manage Python dependencies
while in development and testing.
To activate the Nova virtualenv for the extent of your current shell session
you can run:
To activate the Nova virtualenv for the extent of your current shell
session you can run:
$ source .nova-venv/bin/activate
$ source .nova-venv/bin/activate
Or, if you prefer, you can run commands in the virtualenv on a case by case
basis by running:
Or, if you prefer, you can run commands in the virtualenv on a case by case
basis by running:
$ tools/with_venv.sh <your command>
$ tools/with_venv.sh <your command>
Also, make test will automatically use the virtualenv.
"""
print help
Also, make test will automatically use the virtualenv.
"""
print help
def main(argv):
check_python_version()
check_dependencies()
create_virtualenv()
install_dependencies()
print_help()
check_python_version()
check_dependencies()
create_virtualenv()
install_dependencies()
print_help()
if __name__ == '__main__':
main(sys.argv)
main(sys.argv)