Merging trunk
This commit is contained in:
commit
821ee03ced
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
||||
|
@ -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'])
|
||||
|
1
nova/tests/public_key/dummy.fingerprint
Normal file
1
nova/tests/public_key/dummy.fingerprint
Normal file
@ -0,0 +1 @@
|
||||
1c:87:d1:d9:32:fd:62:3c:78:2b:c0:ad:c0:15:88:df
|
1
nova/tests/public_key/dummy.pub
Normal file
1
nova/tests/public_key/dummy.pub
Normal file
@ -0,0 +1 @@
|
||||
ssh-dss AAAAB3NzaC1kc3MAAACBAMGJlY9XEIm2X234pdO5yFWMp2JuOQx8U0E815IVXhmKxYCBK9ZakgZOIQmPbXoGYyV+mziDPp6HJ0wKYLQxkwLEFr51fAZjWQvRss0SinURRuLkockDfGFtD4pYJthekr/rlqMKlBSDUSpGq8jUWW60UJ18FGooFpxR7ESqQRx/AAAAFQC96LRglaUeeP+E8U/yblEJocuiWwAAAIA3XiMR8Skiz/0aBm5K50SeQznQuMJTyzt9S9uaz5QZWiFu69hOyGSFGw8fqgxEkXFJIuHobQQpGYQubLW0NdaYRqyE/Vud3JUJUb8Texld6dz8vGemyB5d1YvtSeHIo8/BGv2msOqR3u5AZTaGCBD9DhpSGOKHEdNjTtvpPd8S8gAAAIBociGZ5jf09iHLVENhyXujJbxfGRPsyNTyARJfCOGl0oFV6hEzcQyw8U/ePwjgvjc2UizMWLl8tsb2FXKHRdc2v+ND3Us+XqKQ33X3ADP4FZ/+Oj213gMyhCmvFTP0u5FmHog9My4CB7YcIWRuUR42WlhQ2IfPvKwUoTk3R+T6Og== www-data@mk
|
@ -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')
|
||||
|
@ -81,6 +81,7 @@ def inject_data(image, key=None, net=None, partition=None, nbd=False):
|
||||
else:
|
||||
mapped_device = device
|
||||
|
||||
try:
|
||||
# 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):
|
||||
@ -109,6 +110,7 @@ def inject_data(image, key=None, net=None, partition=None, nbd=False):
|
||||
finally:
|
||||
# remove temporary directory
|
||||
utils.execute('rmdir', tmpdir)
|
||||
finally:
|
||||
if not partition is None:
|
||||
# remove partitions
|
||||
utils.execute('sudo', 'kpartx', '-d', device)
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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}
|
||||
}
|
||||
|
@ -32,16 +32,19 @@ 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])
|
||||
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)
|
||||
|
||||
|
||||
def check_python_version():
|
||||
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
|
||||
@ -59,8 +62,10 @@ def run_command(cmd, redirect_output=True, check_exit_code=True):
|
||||
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():
|
||||
@ -73,8 +78,9 @@ def check_dependencies():
|
||||
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')
|
||||
die('ERROR: virtualenv not found.\n\nNova development'
|
||||
' requires virtualenv, please install it using your'
|
||||
' favorite package management tool')
|
||||
print 'done.'
|
||||
print 'done.'
|
||||
|
||||
@ -96,22 +102,22 @@ 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)
|
||||
|
||||
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")
|
||||
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")
|
||||
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)
|
||||
|
||||
@ -123,8 +129,8 @@ def print_help():
|
||||
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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user