merged trunk rev569
This commit is contained in:
6
Authors
6
Authors
@@ -4,8 +4,8 @@ Anthony Young <sleepsonthefloor@gmail.com>
|
||||
Antony Messerli <ant@openstack.org>
|
||||
Armando Migliaccio <Armando.Migliaccio@eu.citrix.com>
|
||||
Chiradeep Vittal <chiradeep@cloud.com>
|
||||
Chris Behrens <cbehrens@codestud.com>
|
||||
Chmouel Boudjnah <chmouel@chmouel.com>
|
||||
Chris Behrens <cbehrens@codestud.com>
|
||||
Cory Wright <corywright@gmail.com>
|
||||
David Pravec <David.Pravec@danix.org>
|
||||
Dean Troyer <dtroyer@gmail.com>
|
||||
@@ -14,6 +14,7 @@ Ed Leafe <ed@leafe.com>
|
||||
Eldar Nugaev <enugaev@griddynamics.com>
|
||||
Eric Day <eday@oddments.org>
|
||||
Ewan Mellor <ewan.mellor@citrix.com>
|
||||
Hisaharu Ishii <ishii.hisaharu@lab.ntt.co.jp>
|
||||
Hisaki Ohara <hisaki.ohara@intel.com>
|
||||
Ilya Alekseyev <ialekseev@griddynamics.com>
|
||||
Jay Pipes <jaypipes@gmail.com>
|
||||
@@ -27,12 +28,15 @@ Joshua McKenty <jmckenty@gmail.com>
|
||||
Justin Santa Barbara <justin@fathomdb.com>
|
||||
Kei Masumoto <masumotok@nttdata.co.jp>
|
||||
Ken Pepple <ken.pepple@gmail.com>
|
||||
Koji Iida <iida.koji@lab.ntt.co.jp>
|
||||
Lorin Hochstein <lorin@isi.edu>
|
||||
Matt Dietz <matt.dietz@rackspace.com>
|
||||
Michael Gundlach <michael.gundlach@rackspace.com>
|
||||
Monsyne Dragon <mdragon@rackspace.com>
|
||||
Monty Taylor <mordred@inaugust.com>
|
||||
MORITA Kazutaka <morita.kazutaka@gmail.com>
|
||||
Muneyuki Noguchi <noguchimn@nttdata.co.jp>
|
||||
Nachi Ueno <ueno.nachi@lab.ntt.co.jp> <openstack@lab.ntt.co.jp> <nati.ueno@gmail.com> <nova@u4>
|
||||
Paul Voccio <paul@openstack.org>
|
||||
Rick Clark <rick@openstack.org>
|
||||
Rick Harris <rconradharris@gmail.com>
|
||||
|
61
bin/nova-direct-api
Executable file
61
bin/nova-direct-api
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable-msg=C0103
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Starter script for Nova Direct API."""
|
||||
|
||||
import gettext
|
||||
import os
|
||||
import sys
|
||||
|
||||
# If ../nova/__init__.py exists, add ../ to Python search path, so that
|
||||
# it will override what happens to be installed in /usr/(local/)lib/python...
|
||||
possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
|
||||
os.pardir,
|
||||
os.pardir))
|
||||
if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
|
||||
sys.path.insert(0, possible_topdir)
|
||||
|
||||
gettext.install('nova', unicode=1)
|
||||
|
||||
from nova import flags
|
||||
from nova import utils
|
||||
from nova import wsgi
|
||||
from nova.api import direct
|
||||
from nova.compute import api as compute_api
|
||||
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
flags.DEFINE_integer('direct_port', 8001, 'Direct API port')
|
||||
flags.DEFINE_string('direct_host', '0.0.0.0', 'Direct API host')
|
||||
|
||||
if __name__ == '__main__':
|
||||
utils.default_flagfile()
|
||||
FLAGS(sys.argv)
|
||||
|
||||
direct.register_service('compute', compute_api.ComputeAPI())
|
||||
direct.register_service('reflect', direct.Reflection())
|
||||
router = direct.Router()
|
||||
with_json = direct.JsonParamsMiddleware(router)
|
||||
with_req = direct.PostParamsMiddleware(with_json)
|
||||
with_auth = direct.DelegatedAuthMiddleware(with_req)
|
||||
|
||||
server = wsgi.Server()
|
||||
server.start(with_auth, FLAGS.direct_port, host=FLAGS.direct_host)
|
||||
server.wait()
|
@@ -93,6 +93,7 @@ flags.DECLARE('num_networks', 'nova.network.manager')
|
||||
flags.DECLARE('network_size', 'nova.network.manager')
|
||||
flags.DECLARE('vlan_start', 'nova.network.manager')
|
||||
flags.DECLARE('vpn_start', 'nova.network.manager')
|
||||
flags.DECLARE('fixed_range_v6', 'nova.network.manager')
|
||||
|
||||
|
||||
class VpnCommands(object):
|
||||
@@ -441,11 +442,12 @@ class NetworkCommands(object):
|
||||
"""Class for managing networks."""
|
||||
|
||||
def create(self, fixed_range=None, num_networks=None,
|
||||
network_size=None, vlan_start=None, vpn_start=None):
|
||||
network_size=None, vlan_start=None, vpn_start=None,
|
||||
fixed_range_v6=None):
|
||||
"""Creates fixed ips for host by range
|
||||
arguments: [fixed_range=FLAG], [num_networks=FLAG],
|
||||
[network_size=FLAG], [vlan_start=FLAG],
|
||||
[vpn_start=FLAG]"""
|
||||
[vpn_start=FLAG], [fixed_range_v6=FLAG]"""
|
||||
if not fixed_range:
|
||||
fixed_range = FLAGS.fixed_range
|
||||
if not num_networks:
|
||||
@@ -456,11 +458,13 @@ class NetworkCommands(object):
|
||||
vlan_start = FLAGS.vlan_start
|
||||
if not vpn_start:
|
||||
vpn_start = FLAGS.vpn_start
|
||||
if not fixed_range_v6:
|
||||
fixed_range_v6 = FLAGS.fixed_range_v6
|
||||
net_manager = utils.import_object(FLAGS.network_manager)
|
||||
net_manager.create_networks(context.get_admin_context(),
|
||||
fixed_range, int(num_networks),
|
||||
int(network_size), int(vlan_start),
|
||||
int(vpn_start))
|
||||
int(vpn_start), fixed_range_v6)
|
||||
|
||||
|
||||
class InstanceCommands(object):
|
||||
@@ -477,7 +481,7 @@ class InstanceCommands(object):
|
||||
raise exception.Error(msg)
|
||||
|
||||
if FLAGS.volume_driver != 'nova.volume.driver.AOEDriver':
|
||||
instance_ref = db.instance_get(instance_id)
|
||||
instance_ref = db.instance_get(ctxt, instance_id)
|
||||
if len(instance_ref['volumes']) != 0:
|
||||
msg = _(("""Volumes attached by ISCSIDriver"""
|
||||
""" are not supported. Sorry!"""))
|
||||
|
145
bin/stack
Executable file
145
bin/stack
Executable file
@@ -0,0 +1,145 @@
|
||||
#!/usr/bin/env python
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""CLI for the Direct API."""
|
||||
|
||||
import eventlet
|
||||
eventlet.monkey_patch()
|
||||
|
||||
import os
|
||||
import pprint
|
||||
import sys
|
||||
import textwrap
|
||||
import urllib
|
||||
import urllib2
|
||||
|
||||
# If ../nova/__init__.py exists, add ../ to Python search path, so that
|
||||
# it will override what happens to be installed in /usr/(local/)lib/python...
|
||||
possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
|
||||
os.pardir,
|
||||
os.pardir))
|
||||
if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
|
||||
sys.path.insert(0, possible_topdir)
|
||||
|
||||
import gflags
|
||||
from nova import utils
|
||||
|
||||
|
||||
FLAGS = gflags.FLAGS
|
||||
gflags.DEFINE_string('host', '127.0.0.1', 'Direct API host')
|
||||
gflags.DEFINE_integer('port', 8001, 'Direct API host')
|
||||
gflags.DEFINE_string('user', 'user1', 'Direct API username')
|
||||
gflags.DEFINE_string('project', 'proj1', 'Direct API project')
|
||||
|
||||
|
||||
USAGE = """usage: stack [options] <controller> <method> [arg1=value arg2=value]
|
||||
|
||||
`stack help` should output the list of available controllers
|
||||
`stack <controller>` should output the available methods for that controller
|
||||
`stack help <controller>` should do the same
|
||||
`stack help <controller> <method>` should output info for a method
|
||||
"""
|
||||
|
||||
|
||||
def format_help(d):
|
||||
"""Format help text, keys are labels and values are descriptions."""
|
||||
indent = max([len(k) for k in d])
|
||||
out = []
|
||||
for k, v in d.iteritems():
|
||||
t = textwrap.TextWrapper(initial_indent=' %s ' % k.ljust(indent),
|
||||
subsequent_indent=' ' * (indent + 6))
|
||||
out.extend(t.wrap(v))
|
||||
return out
|
||||
|
||||
|
||||
def help_all():
|
||||
rv = do_request('reflect', 'get_controllers')
|
||||
out = format_help(rv)
|
||||
return (USAGE + str(FLAGS.MainModuleHelp()) +
|
||||
'\n\nAvailable controllers:\n' +
|
||||
'\n'.join(out) + '\n')
|
||||
|
||||
|
||||
def help_controller(controller):
|
||||
rv = do_request('reflect', 'get_methods')
|
||||
methods = dict([(k.split('/')[2], v) for k, v in rv.iteritems()
|
||||
if k.startswith('/%s' % controller)])
|
||||
return ('Available methods for %s:\n' % controller +
|
||||
'\n'.join(format_help(methods)))
|
||||
|
||||
|
||||
def help_method(controller, method):
|
||||
rv = do_request('reflect',
|
||||
'get_method_info',
|
||||
{'method': '/%s/%s' % (controller, method)})
|
||||
|
||||
sig = '%s(%s):' % (method, ', '.join(['='.join(x) for x in rv['args']]))
|
||||
out = textwrap.wrap(sig, subsequent_indent=' ' * len('%s(' % method))
|
||||
out.append('\n' + rv['doc'])
|
||||
return '\n'.join(out)
|
||||
|
||||
|
||||
def do_request(controller, method, params=None):
|
||||
if params:
|
||||
data = urllib.urlencode(params)
|
||||
else:
|
||||
data = None
|
||||
|
||||
url = 'http://%s:%s/%s/%s' % (FLAGS.host, FLAGS.port, controller, method)
|
||||
headers = {'X-OpenStack-User': FLAGS.user,
|
||||
'X-OpenStack-Project': FLAGS.project}
|
||||
|
||||
req = urllib2.Request(url, data, headers)
|
||||
resp = urllib2.urlopen(req)
|
||||
return utils.loads(resp.read())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = FLAGS(sys.argv)
|
||||
|
||||
cmd = args.pop(0)
|
||||
if not args:
|
||||
print help_all()
|
||||
sys.exit()
|
||||
|
||||
first = args.pop(0)
|
||||
if first == 'help':
|
||||
action = help_all
|
||||
params = []
|
||||
if args:
|
||||
params.append(args.pop(0))
|
||||
action = help_controller
|
||||
if args:
|
||||
params.append(args.pop(0))
|
||||
action = help_method
|
||||
print action(*params)
|
||||
sys.exit(0)
|
||||
|
||||
controller = first
|
||||
if not args:
|
||||
print help_controller(controller)
|
||||
sys.exit()
|
||||
|
||||
method = args.pop(0)
|
||||
params = {}
|
||||
for x in args:
|
||||
key, value = x.split('=', 1)
|
||||
params[key] = value
|
||||
|
||||
pprint.pprint(do_request(controller, method, params))
|
@@ -76,6 +76,10 @@ class InvalidInputException(Error):
|
||||
pass
|
||||
|
||||
|
||||
class TimeoutException(Error):
|
||||
pass
|
||||
|
||||
|
||||
def wrap_exception(f):
|
||||
def _wrap(*args, **kw):
|
||||
try:
|
||||
|
@@ -111,7 +111,8 @@ class Scheduler(object):
|
||||
ec2_id = instance_ref['hostname']
|
||||
raise exception.Invalid(msg % ec2_id)
|
||||
|
||||
# Checing volume node is running when any volumes are mounted to the instance.
|
||||
# Checing volume node is running when any volumes are mounted
|
||||
# to the instance.
|
||||
if len(instance_ref['volumes']) != 0:
|
||||
services = db.service_get_all_by_topic(context, 'volume')
|
||||
if len(services) < 1 or not self.service_is_up(services[0]):
|
||||
@@ -126,7 +127,6 @@ class Scheduler(object):
|
||||
msg = _('%s is not alive(time synchronize problem?)')
|
||||
raise exception.Invalid(msg % src)
|
||||
|
||||
|
||||
def _live_migration_dest_check(self, context, instance_ref, dest):
|
||||
"""Live migration check routine (for destination host)"""
|
||||
|
||||
@@ -203,7 +203,8 @@ class Scheduler(object):
|
||||
"args": {'cpu_info': cpu_info}})
|
||||
|
||||
except rpc.RemoteError, e:
|
||||
msg = _('%s doesnt have compatibility to %s(where %s launching at)')
|
||||
msg = _(("""%s doesnt have compatibility to %s"""
|
||||
"""(where %s was launched at)"""))
|
||||
ec2_id = instance_ref['hostname']
|
||||
src = instance_ref['host']
|
||||
logging.error(msg % (dest, src, ec2_id))
|
||||
|
@@ -75,12 +75,9 @@ class SchedulerManager(manager.Manager):
|
||||
def show_host_resource(self, context, host, *args):
|
||||
""" show the physical/usage resource given by hosts."""
|
||||
|
||||
try:
|
||||
services = db.service_get_all_by_host(context, host)
|
||||
except exception.NotFound:
|
||||
if len(services) == 0:
|
||||
return {'ret': False, 'msg': 'No such Host'}
|
||||
except:
|
||||
raise
|
||||
|
||||
compute = [ s for s in services if s['topic'] == 'compute']
|
||||
if 0 == len(compute):
|
||||
@@ -93,6 +90,7 @@ class SchedulerManager(manager.Manager):
|
||||
'memory_mb': service_ref['memory_mb'],
|
||||
'local_gb': service_ref['local_gb']}
|
||||
|
||||
|
||||
# Getting usage resource information
|
||||
u_resource = {}
|
||||
instances_ref = db.instance_get_all_by_host(context,
|
||||
|
99
nova/test.py
99
nova/test.py
@@ -23,14 +23,10 @@ and some black magic for inline callbacks.
|
||||
"""
|
||||
|
||||
import datetime
|
||||
import sys
|
||||
import time
|
||||
import unittest
|
||||
|
||||
import mox
|
||||
import stubout
|
||||
from twisted.internet import defer
|
||||
from twisted.trial import unittest as trial_unittest
|
||||
|
||||
from nova import context
|
||||
from nova import db
|
||||
@@ -74,7 +70,8 @@ class TestCase(unittest.TestCase):
|
||||
FLAGS.fixed_range,
|
||||
5, 16,
|
||||
FLAGS.vlan_start,
|
||||
FLAGS.vpn_start)
|
||||
FLAGS.vpn_start,
|
||||
FLAGS.fixed_range_v6)
|
||||
|
||||
# emulate some of the mox stuff, we can't use the metaclass
|
||||
# because it screws with our generators
|
||||
@@ -139,95 +136,3 @@ class TestCase(unittest.TestCase):
|
||||
|
||||
_wrapped.func_name = self.originalAttach.func_name
|
||||
rpc.Consumer.attach_to_eventlet = _wrapped
|
||||
|
||||
|
||||
class TrialTestCase(trial_unittest.TestCase):
|
||||
"""Test case base class for all unit tests"""
|
||||
def setUp(self):
|
||||
"""Run before each test method to initialize test environment"""
|
||||
super(TrialTestCase, self).setUp()
|
||||
# NOTE(vish): We need a better method for creating fixtures for tests
|
||||
# now that we have some required db setup for the system
|
||||
# to work properly.
|
||||
self.start = datetime.datetime.utcnow()
|
||||
ctxt = context.get_admin_context()
|
||||
if db.network_count(ctxt) != 5:
|
||||
network_manager.VlanManager().create_networks(ctxt,
|
||||
FLAGS.fixed_range,
|
||||
5, 16,
|
||||
FLAGS.vlan_start,
|
||||
FLAGS.vpn_start)
|
||||
|
||||
# emulate some of the mox stuff, we can't use the metaclass
|
||||
# because it screws with our generators
|
||||
self.mox = mox.Mox()
|
||||
self.stubs = stubout.StubOutForTesting()
|
||||
self.flag_overrides = {}
|
||||
self.injected = []
|
||||
self._original_flags = FLAGS.FlagValuesDict()
|
||||
|
||||
def tearDown(self):
|
||||
"""Runs after each test method to finalize/tear down test
|
||||
environment."""
|
||||
try:
|
||||
self.mox.UnsetStubs()
|
||||
self.stubs.UnsetAll()
|
||||
self.stubs.SmartUnsetAll()
|
||||
self.mox.VerifyAll()
|
||||
# NOTE(vish): Clean up any ips associated during the test.
|
||||
ctxt = context.get_admin_context()
|
||||
db.fixed_ip_disassociate_all_by_timeout(ctxt, FLAGS.host,
|
||||
self.start)
|
||||
db.network_disassociate_all(ctxt)
|
||||
for x in self.injected:
|
||||
try:
|
||||
x.stop()
|
||||
except AssertionError:
|
||||
pass
|
||||
|
||||
if FLAGS.fake_rabbit:
|
||||
fakerabbit.reset_all()
|
||||
|
||||
db.security_group_destroy_all(ctxt)
|
||||
super(TrialTestCase, self).tearDown()
|
||||
finally:
|
||||
self.reset_flags()
|
||||
|
||||
def flags(self, **kw):
|
||||
"""Override flag variables for a test"""
|
||||
for k, v in kw.iteritems():
|
||||
if k in self.flag_overrides:
|
||||
self.reset_flags()
|
||||
raise Exception(
|
||||
'trying to override already overriden flag: %s' % k)
|
||||
self.flag_overrides[k] = getattr(FLAGS, k)
|
||||
setattr(FLAGS, k, v)
|
||||
|
||||
def reset_flags(self):
|
||||
"""Resets all flag variables for the test. Runs after each test"""
|
||||
FLAGS.Reset()
|
||||
for k, v in self._original_flags.iteritems():
|
||||
setattr(FLAGS, k, v)
|
||||
|
||||
def run(self, result=None):
|
||||
test_method = getattr(self, self._testMethodName)
|
||||
setattr(self,
|
||||
self._testMethodName,
|
||||
self._maybeInlineCallbacks(test_method, result))
|
||||
rv = super(TrialTestCase, self).run(result)
|
||||
setattr(self, self._testMethodName, test_method)
|
||||
return rv
|
||||
|
||||
def _maybeInlineCallbacks(self, func, result):
|
||||
def _wrapped():
|
||||
g = func()
|
||||
if isinstance(g, defer.Deferred):
|
||||
return g
|
||||
if not hasattr(g, 'send'):
|
||||
return defer.succeed(g)
|
||||
|
||||
inlined = defer.inlineCallbacks(func)
|
||||
d = inlined()
|
||||
return d
|
||||
_wrapped.func_name = func.func_name
|
||||
return _wrapped
|
||||
|
@@ -79,7 +79,7 @@ class FakeHttplibConnection(object):
|
||||
pass
|
||||
|
||||
|
||||
class XmlConversionTestCase(test.TrialTestCase):
|
||||
class XmlConversionTestCase(test.TestCase):
|
||||
"""Unit test api xml conversion"""
|
||||
def test_number_conversion(self):
|
||||
conv = apirequest._try_convert
|
||||
@@ -96,7 +96,7 @@ class XmlConversionTestCase(test.TrialTestCase):
|
||||
self.assertEqual(conv('-0'), 0)
|
||||
|
||||
|
||||
class ApiEc2TestCase(test.TrialTestCase):
|
||||
class ApiEc2TestCase(test.TestCase):
|
||||
"""Unit test for the cloud controller on an EC2 API"""
|
||||
def setUp(self):
|
||||
super(ApiEc2TestCase, self).setUp()
|
||||
@@ -265,6 +265,72 @@ class ApiEc2TestCase(test.TrialTestCase):
|
||||
|
||||
return
|
||||
|
||||
def test_authorize_revoke_security_group_cidr_v6(self):
|
||||
"""
|
||||
Test that we can add and remove CIDR based rules
|
||||
to a security group for IPv6
|
||||
"""
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
user = self.manager.create_user('fake', 'fake', 'fake')
|
||||
project = self.manager.create_project('fake', 'fake', 'fake')
|
||||
|
||||
# At the moment, you need both of these to actually be netadmin
|
||||
self.manager.add_role('fake', 'netadmin')
|
||||
project.add_role('fake', 'netadmin')
|
||||
|
||||
security_group_name = "".join(random.choice("sdiuisudfsdcnpaqwertasd")
|
||||
for x in range(random.randint(4, 8)))
|
||||
|
||||
group = self.ec2.create_security_group(security_group_name,
|
||||
'test group')
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
group.connection = self.ec2
|
||||
|
||||
group.authorize('tcp', 80, 81, '::/0')
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
|
||||
rv = self.ec2.get_all_security_groups()
|
||||
# I don't bother checkng that we actually find it here,
|
||||
# because the create/delete unit test further up should
|
||||
# be good enough for that.
|
||||
for group in rv:
|
||||
if group.name == security_group_name:
|
||||
self.assertEquals(len(group.rules), 1)
|
||||
self.assertEquals(int(group.rules[0].from_port), 80)
|
||||
self.assertEquals(int(group.rules[0].to_port), 81)
|
||||
self.assertEquals(len(group.rules[0].grants), 1)
|
||||
self.assertEquals(str(group.rules[0].grants[0]), '::/0')
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
group.connection = self.ec2
|
||||
|
||||
group.revoke('tcp', 80, 81, '::/0')
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.ec2.delete_security_group(security_group_name)
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
group.connection = self.ec2
|
||||
|
||||
rv = self.ec2.get_all_security_groups()
|
||||
|
||||
self.assertEqual(len(rv), 1)
|
||||
self.assertEqual(rv[0].name, 'default')
|
||||
|
||||
self.manager.delete_project(project)
|
||||
self.manager.delete_user(user)
|
||||
|
||||
return
|
||||
|
||||
def test_authorize_revoke_security_group_foreign_group(self):
|
||||
"""
|
||||
Test that we can grant and revoke another security group access
|
||||
|
@@ -21,6 +21,7 @@ import json
|
||||
from M2Crypto import BIO
|
||||
from M2Crypto import RSA
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
@@ -50,6 +51,8 @@ IMAGES_PATH = os.path.join(OSS_TEMPDIR, 'images')
|
||||
os.makedirs(IMAGES_PATH)
|
||||
|
||||
|
||||
# TODO(termie): these tests are rather fragile, they should at the lest be
|
||||
# wiping database state after each run
|
||||
class CloudTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(CloudTestCase, self).setUp()
|
||||
@@ -287,6 +290,7 @@ class CloudTestCase(test.TestCase):
|
||||
db.service_destroy(self.context, comp1['id'])
|
||||
|
||||
def test_instance_update_state(self):
|
||||
# TODO(termie): what is this code even testing?
|
||||
def instance(num):
|
||||
return {
|
||||
'reservation_id': 'r-1',
|
||||
@@ -305,7 +309,8 @@ class CloudTestCase(test.TestCase):
|
||||
'state': 0x01,
|
||||
'user_data': ''}
|
||||
rv = self.cloud._format_describe_instances(self.context)
|
||||
self.assert_(len(rv['reservationSet']) == 0)
|
||||
logging.error(str(rv))
|
||||
self.assertEqual(len(rv['reservationSet']), 0)
|
||||
|
||||
# simulate launch of 5 instances
|
||||
# self.cloud.instances['pending'] = {}
|
||||
@@ -368,6 +373,7 @@ class CloudTestCase(test.TestCase):
|
||||
self.assertEqual('Foo Img', img.metadata['description'])
|
||||
self._fake_set_image_description(self.context, 'ami-testing', '')
|
||||
self.assertEqual('', img.metadata['description'])
|
||||
shutil.rmtree(pathdir)
|
||||
|
||||
def test_update_of_instance_display_fields(self):
|
||||
inst = db.instance_create(self.context, {})
|
||||
|
@@ -75,7 +75,7 @@ class ComputeTestCase(test.TestCase):
|
||||
ref = self.compute_api.create(self.context,
|
||||
FLAGS.default_instance_type, None, **instance)
|
||||
try:
|
||||
self.assertNotEqual(ref[0].display_name, None)
|
||||
self.assertNotEqual(ref[0]['display_name'], None)
|
||||
finally:
|
||||
db.instance_destroy(self.context, ref[0]['id'])
|
||||
|
||||
@@ -86,10 +86,14 @@ class ComputeTestCase(test.TestCase):
|
||||
'user_id': self.user.id,
|
||||
'project_id': self.project.id}
|
||||
group = db.security_group_create(self.context, values)
|
||||
ref = self.compute_api.create(self.context,
|
||||
FLAGS.default_instance_type, None, security_group=['default'])
|
||||
ref = self.compute_api.create(
|
||||
self.context,
|
||||
instance_type=FLAGS.default_instance_type,
|
||||
image_id=None,
|
||||
security_group=['default'])
|
||||
try:
|
||||
self.assertEqual(len(ref[0]['security_groups']), 1)
|
||||
self.assertEqual(len(db.security_group_get_by_instance(
|
||||
self.context, ref[0]['id'])), 1)
|
||||
finally:
|
||||
db.security_group_destroy(self.context, group['id'])
|
||||
db.instance_destroy(self.context, ref[0]['id'])
|
||||
@@ -151,6 +155,13 @@ class ComputeTestCase(test.TestCase):
|
||||
self.compute.reboot_instance(self.context, instance_id)
|
||||
self.compute.terminate_instance(self.context, instance_id)
|
||||
|
||||
def test_set_admin_password(self):
|
||||
"""Ensure instance can have its admin password set"""
|
||||
instance_id = self._create_instance()
|
||||
self.compute.run_instance(self.context, instance_id)
|
||||
self.compute.set_admin_password(self.context, instance_id)
|
||||
self.compute.terminate_instance(self.context, instance_id)
|
||||
|
||||
def test_snapshot(self):
|
||||
"""Ensure instance can be snapshotted"""
|
||||
instance_id = self._create_instance()
|
||||
|
@@ -111,12 +111,14 @@ class ConsoleTestCase(test.TestCase):
|
||||
|
||||
console_instances = [con['instance_id'] for con in pool.consoles]
|
||||
self.assert_(instance_id in console_instances)
|
||||
db.instance_destroy(self.context, instance_id)
|
||||
|
||||
def test_add_console_does_not_duplicate(self):
|
||||
instance_id = self._create_instance()
|
||||
cons1 = self.console.add_console(self.context, instance_id)
|
||||
cons2 = self.console.add_console(self.context, instance_id)
|
||||
self.assertEqual(cons1, cons2)
|
||||
db.instance_destroy(self.context, instance_id)
|
||||
|
||||
def test_remove_console(self):
|
||||
instance_id = self._create_instance()
|
||||
@@ -127,3 +129,4 @@ class ConsoleTestCase(test.TestCase):
|
||||
db.console_get,
|
||||
self.context,
|
||||
console_id)
|
||||
db.instance_destroy(self.context, instance_id)
|
||||
|
103
nova/tests/test_direct.py
Normal file
103
nova/tests/test_direct.py
Normal file
@@ -0,0 +1,103 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Tests for Direct API."""
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
import webob
|
||||
|
||||
from nova import compute
|
||||
from nova import context
|
||||
from nova import exception
|
||||
from nova import test
|
||||
from nova import utils
|
||||
from nova.api import direct
|
||||
from nova.tests import test_cloud
|
||||
|
||||
|
||||
class FakeService(object):
|
||||
def echo(self, context, data):
|
||||
return {'data': data}
|
||||
|
||||
def context(self, context):
|
||||
return {'user': context.user_id,
|
||||
'project': context.project_id}
|
||||
|
||||
|
||||
class DirectTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(DirectTestCase, self).setUp()
|
||||
direct.register_service('fake', FakeService())
|
||||
self.router = direct.PostParamsMiddleware(
|
||||
direct.JsonParamsMiddleware(
|
||||
direct.Router()))
|
||||
self.auth_router = direct.DelegatedAuthMiddleware(self.router)
|
||||
self.context = context.RequestContext('user1', 'proj1')
|
||||
|
||||
def tearDown(self):
|
||||
direct.ROUTES = {}
|
||||
|
||||
def test_delegated_auth(self):
|
||||
req = webob.Request.blank('/fake/context')
|
||||
req.headers['X-OpenStack-User'] = 'user1'
|
||||
req.headers['X-OpenStack-Project'] = 'proj1'
|
||||
resp = req.get_response(self.auth_router)
|
||||
data = json.loads(resp.body)
|
||||
self.assertEqual(data['user'], 'user1')
|
||||
self.assertEqual(data['project'], 'proj1')
|
||||
|
||||
def test_json_params(self):
|
||||
req = webob.Request.blank('/fake/echo')
|
||||
req.environ['openstack.context'] = self.context
|
||||
req.method = 'POST'
|
||||
req.body = 'json=%s' % json.dumps({'data': 'foo'})
|
||||
resp = req.get_response(self.router)
|
||||
resp_parsed = json.loads(resp.body)
|
||||
self.assertEqual(resp_parsed['data'], 'foo')
|
||||
|
||||
def test_post_params(self):
|
||||
req = webob.Request.blank('/fake/echo')
|
||||
req.environ['openstack.context'] = self.context
|
||||
req.method = 'POST'
|
||||
req.body = 'data=foo'
|
||||
resp = req.get_response(self.router)
|
||||
resp_parsed = json.loads(resp.body)
|
||||
self.assertEqual(resp_parsed['data'], 'foo')
|
||||
|
||||
def test_proxy(self):
|
||||
proxy = direct.Proxy(self.router)
|
||||
rv = proxy.fake.echo(self.context, data='baz')
|
||||
self.assertEqual(rv['data'], 'baz')
|
||||
|
||||
|
||||
class DirectCloudTestCase(test_cloud.CloudTestCase):
|
||||
def setUp(self):
|
||||
super(DirectCloudTestCase, self).setUp()
|
||||
compute_handle = compute.API(image_service=self.cloud.image_service,
|
||||
network_api=self.cloud.network_api,
|
||||
volume_api=self.cloud.volume_api)
|
||||
direct.register_service('compute', compute_handle)
|
||||
self.router = direct.JsonParamsMiddleware(direct.Router())
|
||||
proxy = direct.Proxy(self.router)
|
||||
self.cloud.compute_api = proxy.compute
|
||||
|
||||
def tearDown(self):
|
||||
super(DirectCloudTestCase, self).tearDown()
|
||||
direct.ROUTES = {}
|
@@ -9,7 +9,7 @@ def _fake_context():
|
||||
return context.RequestContext(1, 1)
|
||||
|
||||
|
||||
class RootLoggerTestCase(test.TrialTestCase):
|
||||
class RootLoggerTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(RootLoggerTestCase, self).setUp()
|
||||
self.log = log.logging.root
|
||||
@@ -46,7 +46,7 @@ class RootLoggerTestCase(test.TrialTestCase):
|
||||
self.assert_(True) # didn't raise exception
|
||||
|
||||
|
||||
class NovaFormatterTestCase(test.TrialTestCase):
|
||||
class NovaFormatterTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(NovaFormatterTestCase, self).setUp()
|
||||
self.flags(logging_context_format_string="HAS CONTEXT "\
|
||||
@@ -78,7 +78,7 @@ class NovaFormatterTestCase(test.TrialTestCase):
|
||||
self.assertEqual("NOCTXT: baz --DBG\n", self.stream.getvalue())
|
||||
|
||||
|
||||
class NovaLoggerTestCase(test.TrialTestCase):
|
||||
class NovaLoggerTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(NovaLoggerTestCase, self).setUp()
|
||||
self.flags(default_log_levels=["nova-test=AUDIT"], verbose=False)
|
||||
@@ -96,7 +96,7 @@ class NovaLoggerTestCase(test.TrialTestCase):
|
||||
self.assertEqual(log.AUDIT, l.level)
|
||||
|
||||
|
||||
class VerboseLoggerTestCase(test.TrialTestCase):
|
||||
class VerboseLoggerTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(VerboseLoggerTestCase, self).setUp()
|
||||
self.flags(default_log_levels=["nova.test=AUDIT"], verbose=True)
|
||||
|
@@ -38,7 +38,7 @@ def conditional_forbid(req):
|
||||
return 'OK'
|
||||
|
||||
|
||||
class LockoutTestCase(test.TrialTestCase):
|
||||
class LockoutTestCase(test.TestCase):
|
||||
"""Test case for the Lockout middleware."""
|
||||
def setUp(self): # pylint: disable-msg=C0103
|
||||
super(LockoutTestCase, self).setUp()
|
||||
|
@@ -96,6 +96,28 @@ class NetworkTestCase(test.TestCase):
|
||||
self.context.project_id = self.projects[project_num].id
|
||||
self.network.deallocate_fixed_ip(self.context, address)
|
||||
|
||||
def test_private_ipv6(self):
|
||||
"""Make sure ipv6 is OK"""
|
||||
if FLAGS.use_ipv6:
|
||||
instance_ref = self._create_instance(0)
|
||||
address = self._create_address(0, instance_ref['id'])
|
||||
network_ref = db.project_get_network(
|
||||
context.get_admin_context(),
|
||||
self.context.project_id)
|
||||
address_v6 = db.instance_get_fixed_address_v6(
|
||||
context.get_admin_context(),
|
||||
instance_ref['id'])
|
||||
self.assertEqual(instance_ref['mac_address'],
|
||||
utils.to_mac(address_v6))
|
||||
instance_ref2 = db.fixed_ip_get_instance_v6(
|
||||
context.get_admin_context(),
|
||||
address_v6)
|
||||
self.assertEqual(instance_ref['id'], instance_ref2['id'])
|
||||
self.assertEqual(address_v6,
|
||||
utils.to_global_ipv6(
|
||||
network_ref['cidr_v6'],
|
||||
instance_ref['mac_address']))
|
||||
|
||||
def test_public_network_association(self):
|
||||
"""Makes sure that we can allocaate a public ip"""
|
||||
# TODO(vish): better way of adding floating ips
|
||||
|
@@ -28,7 +28,7 @@ from nova import test
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
|
||||
class TwistdTestCase(test.TrialTestCase):
|
||||
class TwistdTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(TwistdTestCase, self).setUp()
|
||||
self.Options = twistd.WrapTwistedOptions(twistd.TwistdServerOptions)
|
||||
|
@@ -31,6 +31,7 @@ from nova.compute import power_state
|
||||
from nova.virt import xenapi_conn
|
||||
from nova.virt.xenapi import fake as xenapi_fake
|
||||
from nova.virt.xenapi import volume_utils
|
||||
from nova.virt.xenapi.vmops import SimpleDH
|
||||
from nova.tests.db import fakes as db_fakes
|
||||
from nova.tests.xenapi import stubs
|
||||
|
||||
@@ -262,3 +263,29 @@ class XenAPIVMTestCase(test.TestCase):
|
||||
instance = db.instance_create(values)
|
||||
self.conn.spawn(instance)
|
||||
return instance
|
||||
|
||||
|
||||
class XenAPIDiffieHellmanTestCase(test.TestCase):
|
||||
"""
|
||||
Unit tests for Diffie-Hellman code
|
||||
"""
|
||||
def setUp(self):
|
||||
super(XenAPIDiffieHellmanTestCase, self).setUp()
|
||||
self.alice = SimpleDH()
|
||||
self.bob = SimpleDH()
|
||||
|
||||
def test_shared(self):
|
||||
alice_pub = self.alice.get_public()
|
||||
bob_pub = self.bob.get_public()
|
||||
alice_shared = self.alice.compute_shared(bob_pub)
|
||||
bob_shared = self.bob.compute_shared(alice_pub)
|
||||
self.assertEquals(alice_shared, bob_shared)
|
||||
|
||||
def test_encryption(self):
|
||||
msg = "This is a top-secret message"
|
||||
enc = self.alice.encrypt(msg)
|
||||
dec = self.bob.decrypt(enc)
|
||||
self.assertEquals(dec, msg)
|
||||
|
||||
def tearDown(self):
|
||||
super(XenAPIDiffieHellmanTestCase, self).tearDown()
|
||||
|
@@ -22,6 +22,7 @@ System-level utilities and helper functions.
|
||||
|
||||
import datetime
|
||||
import inspect
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import subprocess
|
||||
@@ -30,6 +31,8 @@ import struct
|
||||
import sys
|
||||
import time
|
||||
from xml.sax import saxutils
|
||||
import re
|
||||
import netaddr
|
||||
|
||||
from eventlet import event
|
||||
from eventlet import greenthread
|
||||
@@ -200,6 +203,40 @@ def last_octet(address):
|
||||
return int(address.split(".")[-1])
|
||||
|
||||
|
||||
def get_my_linklocal(interface):
|
||||
try:
|
||||
if_str = execute("ip -f inet6 -o addr show %s" % interface)
|
||||
condition = "\s+inet6\s+([0-9a-f:]+/\d+)\s+scope\s+link"
|
||||
links = [re.search(condition, x) for x in if_str[0].split('\n')]
|
||||
address = [w.group(1) for w in links if w is not None]
|
||||
if address[0] is not None:
|
||||
return address[0]
|
||||
else:
|
||||
return 'fe00::'
|
||||
except IndexError as ex:
|
||||
LOG.warn(_("Couldn't get Link Local IP of %s :%s"), interface, ex)
|
||||
except ProcessExecutionError as ex:
|
||||
LOG.warn(_("Couldn't get Link Local IP of %s :%s"), interface, ex)
|
||||
except:
|
||||
return 'fe00::'
|
||||
|
||||
|
||||
def to_global_ipv6(prefix, mac):
|
||||
mac64 = netaddr.EUI(mac).eui64().words
|
||||
int_addr = int(''.join(['%02x' % i for i in mac64]), 16)
|
||||
mac64_addr = netaddr.IPAddress(int_addr)
|
||||
maskIP = netaddr.IPNetwork(prefix).ip
|
||||
return (mac64_addr ^ netaddr.IPAddress('::0200:0:0:0') | maskIP).format()
|
||||
|
||||
|
||||
def to_mac(ipv6_address):
|
||||
address = netaddr.IPAddress(ipv6_address)
|
||||
mask1 = netaddr.IPAddress("::ffff:ffff:ffff:ffff")
|
||||
mask2 = netaddr.IPAddress("::0200:0:0:0")
|
||||
mac64 = netaddr.EUI(int(address & mask1 ^ mask2)).words
|
||||
return ":".join(["%02x" % i for i in mac64[0:3] + mac64[5:8]])
|
||||
|
||||
|
||||
def utcnow():
|
||||
"""Overridable version of datetime.datetime.utcnow."""
|
||||
if utcnow.override_time:
|
||||
@@ -355,3 +392,36 @@ def utf8(value):
|
||||
return value.encode("utf-8")
|
||||
assert isinstance(value, str)
|
||||
return value
|
||||
|
||||
|
||||
def to_primitive(value):
|
||||
if type(value) is type([]) or type(value) is type((None,)):
|
||||
o = []
|
||||
for v in value:
|
||||
o.append(to_primitive(v))
|
||||
return o
|
||||
elif type(value) is type({}):
|
||||
o = {}
|
||||
for k, v in value.iteritems():
|
||||
o[k] = to_primitive(v)
|
||||
return o
|
||||
elif isinstance(value, datetime.datetime):
|
||||
return str(value)
|
||||
elif hasattr(value, 'iteritems'):
|
||||
return to_primitive(dict(value.iteritems()))
|
||||
elif hasattr(value, '__iter__'):
|
||||
return to_primitive(list(value))
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
def dumps(value):
|
||||
try:
|
||||
return json.dumps(value)
|
||||
except TypeError:
|
||||
pass
|
||||
return json.dumps(to_primitive(value))
|
||||
|
||||
|
||||
def loads(s):
|
||||
return json.loads(s)
|
||||
|
36
nova/wsgi.py
36
nova/wsgi.py
@@ -21,7 +21,6 @@
|
||||
Utility methods for working with WSGI servers
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from xml.dom import minidom
|
||||
|
||||
@@ -35,6 +34,7 @@ import webob.dec
|
||||
import webob.exc
|
||||
|
||||
from nova import log as logging
|
||||
from nova import utils
|
||||
|
||||
|
||||
class WritableLogger(object):
|
||||
@@ -117,20 +117,38 @@ class Application(object):
|
||||
|
||||
|
||||
class Middleware(Application):
|
||||
"""
|
||||
Base WSGI middleware wrapper. These classes require an application to be
|
||||
"""Base WSGI middleware.
|
||||
|
||||
These classes require an application to be
|
||||
initialized that will be called next. By default the middleware will
|
||||
simply call its wrapped app, or you can override __call__ to customize its
|
||||
behavior.
|
||||
"""
|
||||
|
||||
def __init__(self, application): # pylint: disable-msg=W0231
|
||||
def __init__(self, application):
|
||||
self.application = application
|
||||
|
||||
def process_request(self, req):
|
||||
"""Called on each request.
|
||||
|
||||
If this returns None, the next application down the stack will be
|
||||
executed. If it returns a response then that response will be returned
|
||||
and execution will stop here.
|
||||
|
||||
"""
|
||||
return None
|
||||
|
||||
def process_response(self, response):
|
||||
"""Do whatever you'd like to the response."""
|
||||
return response
|
||||
|
||||
@webob.dec.wsgify
|
||||
def __call__(self, req): # pylint: disable-msg=W0221
|
||||
"""Override to implement middleware behavior."""
|
||||
return self.application
|
||||
def __call__(self, req):
|
||||
response = self.process_request(req)
|
||||
if response:
|
||||
return response
|
||||
response = req.get_response(self.application)
|
||||
return self.process_response(response)
|
||||
|
||||
|
||||
class Debug(Middleware):
|
||||
@@ -316,7 +334,7 @@ class Serializer(object):
|
||||
try:
|
||||
is_xml = (datastring[0] == '<')
|
||||
if not is_xml:
|
||||
return json.loads(datastring)
|
||||
return utils.loads(datastring)
|
||||
return self._from_xml(datastring)
|
||||
except:
|
||||
return None
|
||||
@@ -349,7 +367,7 @@ class Serializer(object):
|
||||
return result
|
||||
|
||||
def _to_json(self, data):
|
||||
return json.dumps(data)
|
||||
return utils.dumps(data)
|
||||
|
||||
def _to_xml(self, data):
|
||||
metadata = self.metadata.get('application/xml', {})
|
||||
|
Reference in New Issue
Block a user