Merge Trunk
This commit is contained in:
@@ -135,8 +135,38 @@ class VpnCommands(object):
|
|||||||
|
|
||||||
|
|
||||||
class ShellCommands(object):
|
class ShellCommands(object):
|
||||||
def run(self):
|
def bpython(self):
|
||||||
"Runs a Python interactive interpreter. Tries to use IPython, if it's available."
|
"""Runs a bpython shell.
|
||||||
|
|
||||||
|
Falls back to Ipython/python shell if unavailable"""
|
||||||
|
self.run('bpython')
|
||||||
|
|
||||||
|
def ipython(self):
|
||||||
|
"""Runs an Ipython shell.
|
||||||
|
|
||||||
|
Falls back to Python shell if unavailable"""
|
||||||
|
self.run('ipython')
|
||||||
|
|
||||||
|
def python(self):
|
||||||
|
"""Runs a python shell.
|
||||||
|
|
||||||
|
Falls back to Python shell if unavailable"""
|
||||||
|
self.run('python')
|
||||||
|
|
||||||
|
def run(self, shell=None):
|
||||||
|
"""Runs a Python interactive interpreter.
|
||||||
|
|
||||||
|
args: [shell=bpython]"""
|
||||||
|
if not shell:
|
||||||
|
shell = 'bpython'
|
||||||
|
|
||||||
|
if shell == 'bpython':
|
||||||
|
try:
|
||||||
|
import bpython
|
||||||
|
bpython.embed()
|
||||||
|
except ImportError:
|
||||||
|
shell = 'ipython'
|
||||||
|
if shell == 'ipython':
|
||||||
try:
|
try:
|
||||||
import IPython
|
import IPython
|
||||||
# Explicitly pass an empty list as arguments, because otherwise IPython
|
# Explicitly pass an empty list as arguments, because otherwise IPython
|
||||||
@@ -144,6 +174,9 @@ class ShellCommands(object):
|
|||||||
shell = IPython.Shell.IPShell(argv=[])
|
shell = IPython.Shell.IPShell(argv=[])
|
||||||
shell.mainloop()
|
shell.mainloop()
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
shell = 'python'
|
||||||
|
|
||||||
|
if shell == 'python':
|
||||||
import code
|
import code
|
||||||
try: # Try activating rlcompleter, because it's handy.
|
try: # Try activating rlcompleter, because it's handy.
|
||||||
import readline
|
import readline
|
||||||
@@ -156,6 +189,11 @@ class ShellCommands(object):
|
|||||||
readline.parse_and_bind("tab:complete")
|
readline.parse_and_bind("tab:complete")
|
||||||
code.interact()
|
code.interact()
|
||||||
|
|
||||||
|
def script(self, path):
|
||||||
|
"""Runs the script from the specifed path with flags set properly.
|
||||||
|
arguments: path"""
|
||||||
|
exec(compile(open(path).read(), path, 'exec'), locals(), globals())
|
||||||
|
|
||||||
|
|
||||||
class RoleCommands(object):
|
class RoleCommands(object):
|
||||||
"""Class for managing roles."""
|
"""Class for managing roles."""
|
||||||
@@ -266,7 +304,7 @@ class ProjectCommands(object):
|
|||||||
def environment(self, project_id, user_id, filename='novarc'):
|
def environment(self, project_id, user_id, filename='novarc'):
|
||||||
"""Exports environment variables to an sourcable file
|
"""Exports environment variables to an sourcable file
|
||||||
arguments: project_id user_id [filename='novarc]"""
|
arguments: project_id user_id [filename='novarc]"""
|
||||||
rc = self.manager.get_environment_rc(project_id, user_id)
|
rc = self.manager.get_environment_rc(user_id, project_id)
|
||||||
with open(filename, 'w') as f:
|
with open(filename, 'w') as f:
|
||||||
f.write(rc)
|
f.write(rc)
|
||||||
|
|
||||||
@@ -329,7 +367,7 @@ class FloatingIpCommands(object):
|
|||||||
for floating_ip in floating_ips:
|
for floating_ip in floating_ips:
|
||||||
instance = None
|
instance = None
|
||||||
if floating_ip['fixed_ip']:
|
if floating_ip['fixed_ip']:
|
||||||
instance = floating_ip['fixed_ip']['instance']['str_id']
|
instance = floating_ip['fixed_ip']['instance']['ec2_id']
|
||||||
print "%s\t%s\t%s" % (floating_ip['host'],
|
print "%s\t%s\t%s" % (floating_ip['host'],
|
||||||
floating_ip['address'],
|
floating_ip['address'],
|
||||||
instance)
|
instance)
|
||||||
|
|||||||
@@ -20,11 +20,17 @@ Nova User API client library.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
import boto
|
import boto
|
||||||
|
import httplib
|
||||||
from boto.ec2.regioninfo import RegionInfo
|
from boto.ec2.regioninfo import RegionInfo
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_CLC_URL='http://127.0.0.1:8773'
|
||||||
|
DEFAULT_REGION='nova'
|
||||||
|
DEFAULT_ACCESS_KEY='admin'
|
||||||
|
DEFAULT_SECRET_KEY='admin'
|
||||||
|
|
||||||
|
|
||||||
class UserInfo(object):
|
class UserInfo(object):
|
||||||
"""
|
"""
|
||||||
Information about a Nova user, as parsed through SAX
|
Information about a Nova user, as parsed through SAX
|
||||||
@@ -171,36 +177,57 @@ class HostInfo(object):
|
|||||||
|
|
||||||
|
|
||||||
class NovaAdminClient(object):
|
class NovaAdminClient(object):
|
||||||
def __init__(self, clc_ip='127.0.0.1', region='nova', access_key='admin',
|
def __init__(self, clc_url=DEFAULT_CLC_URL, region=DEFAULT_REGION,
|
||||||
secret_key='admin', **kwargs):
|
access_key=DEFAULT_ACCESS_KEY, secret_key=DEFAULT_SECRET_KEY,
|
||||||
self.clc_ip = clc_ip
|
**kwargs):
|
||||||
|
parts = self.split_clc_url(clc_url)
|
||||||
|
|
||||||
|
self.clc_url = clc_url
|
||||||
self.region = region
|
self.region = region
|
||||||
self.access = access_key
|
self.access = access_key
|
||||||
self.secret = secret_key
|
self.secret = secret_key
|
||||||
self.apiconn = boto.connect_ec2(aws_access_key_id=access_key,
|
self.apiconn = boto.connect_ec2(aws_access_key_id=access_key,
|
||||||
aws_secret_access_key=secret_key,
|
aws_secret_access_key=secret_key,
|
||||||
is_secure=False,
|
is_secure=parts['is_secure'],
|
||||||
region=RegionInfo(None, region, clc_ip),
|
region=RegionInfo(None,
|
||||||
port=8773,
|
region,
|
||||||
|
parts['ip']),
|
||||||
|
port=parts['port'],
|
||||||
path='/services/Admin',
|
path='/services/Admin',
|
||||||
**kwargs)
|
**kwargs)
|
||||||
self.apiconn.APIVersion = 'nova'
|
self.apiconn.APIVersion = 'nova'
|
||||||
|
|
||||||
def connection_for(self, username, project, **kwargs):
|
def connection_for(self, username, project, clc_url=None, region=None,
|
||||||
|
**kwargs):
|
||||||
"""
|
"""
|
||||||
Returns a boto ec2 connection for the given username.
|
Returns a boto ec2 connection for the given username.
|
||||||
"""
|
"""
|
||||||
|
if not clc_url:
|
||||||
|
clc_url = self.clc_url
|
||||||
|
if not region:
|
||||||
|
region = self.region
|
||||||
|
parts = self.split_clc_url(clc_url)
|
||||||
user = self.get_user(username)
|
user = self.get_user(username)
|
||||||
access_key = '%s:%s' % (user.accesskey, project)
|
access_key = '%s:%s' % (user.accesskey, project)
|
||||||
return boto.connect_ec2(
|
return boto.connect_ec2(aws_access_key_id=access_key,
|
||||||
aws_access_key_id=access_key,
|
|
||||||
aws_secret_access_key=user.secretkey,
|
aws_secret_access_key=user.secretkey,
|
||||||
is_secure=False,
|
is_secure=parts['is_secure'],
|
||||||
region=RegionInfo(None, self.region, self.clc_ip),
|
region=RegionInfo(None,
|
||||||
port=8773,
|
self.region,
|
||||||
|
parts['ip']),
|
||||||
|
port=parts['port'],
|
||||||
path='/services/Cloud',
|
path='/services/Cloud',
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
|
def split_clc_url(self, clc_url):
|
||||||
|
"""
|
||||||
|
Splits a cloud controller endpoint url.
|
||||||
|
"""
|
||||||
|
parts = httplib.urlsplit(clc_url)
|
||||||
|
is_secure = parts.scheme == 'https'
|
||||||
|
ip, port = parts.netloc.split(':')
|
||||||
|
return {'ip': ip, 'port': int(port), 'is_secure': is_secure}
|
||||||
|
|
||||||
def get_users(self):
|
def get_users(self):
|
||||||
""" grabs the list of all users """
|
""" grabs the list of all users """
|
||||||
return self.apiconn.get_list('DescribeUsers', {}, [('item', UserInfo)])
|
return self.apiconn.get_list('DescribeUsers', {}, [('item', UserInfo)])
|
||||||
|
|||||||
45
nova/rpc.py
45
nova/rpc.py
@@ -84,19 +84,6 @@ class Consumer(messaging.Consumer):
|
|||||||
self.failed_connection = False
|
self.failed_connection = False
|
||||||
super(Consumer, self).__init__(*args, **kwargs)
|
super(Consumer, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
# TODO(termie): it would be nice to give these some way of automatically
|
|
||||||
# cleaning up after themselves
|
|
||||||
def attach_to_tornado(self, io_inst=None):
|
|
||||||
"""Attach a callback to tornado that fires 10 times a second"""
|
|
||||||
from tornado import ioloop
|
|
||||||
if io_inst is None:
|
|
||||||
io_inst = ioloop.IOLoop.instance()
|
|
||||||
|
|
||||||
injected = ioloop.PeriodicCallback(
|
|
||||||
lambda: self.fetch(enable_callbacks=True), 100, io_loop=io_inst)
|
|
||||||
injected.start()
|
|
||||||
return injected
|
|
||||||
|
|
||||||
def fetch(self, no_ack=None, auto_ack=None, enable_callbacks=False):
|
def fetch(self, no_ack=None, auto_ack=None, enable_callbacks=False):
|
||||||
"""Wraps the parent fetch with some logic for failed connections"""
|
"""Wraps the parent fetch with some logic for failed connections"""
|
||||||
# TODO(vish): the logic for failed connections and logging should be
|
# TODO(vish): the logic for failed connections and logging should be
|
||||||
@@ -124,6 +111,7 @@ class Consumer(messaging.Consumer):
|
|||||||
"""Attach a callback to twisted that fires 10 times a second"""
|
"""Attach a callback to twisted that fires 10 times a second"""
|
||||||
loop = task.LoopingCall(self.fetch, enable_callbacks=True)
|
loop = task.LoopingCall(self.fetch, enable_callbacks=True)
|
||||||
loop.start(interval=0.1)
|
loop.start(interval=0.1)
|
||||||
|
return loop
|
||||||
|
|
||||||
|
|
||||||
class Publisher(messaging.Publisher):
|
class Publisher(messaging.Publisher):
|
||||||
@@ -294,6 +282,37 @@ def call(topic, msg):
|
|||||||
return wait_msg.result
|
return wait_msg.result
|
||||||
|
|
||||||
|
|
||||||
|
def call_twisted(topic, msg):
|
||||||
|
"""Sends a message on a topic and wait for a response"""
|
||||||
|
LOG.debug("Making asynchronous call...")
|
||||||
|
msg_id = uuid.uuid4().hex
|
||||||
|
msg.update({'_msg_id': msg_id})
|
||||||
|
LOG.debug("MSG_ID is %s" % (msg_id))
|
||||||
|
|
||||||
|
conn = Connection.instance()
|
||||||
|
d = defer.Deferred()
|
||||||
|
consumer = DirectConsumer(connection=conn, msg_id=msg_id)
|
||||||
|
|
||||||
|
def deferred_receive(data, message):
|
||||||
|
"""Acks message and callbacks or errbacks"""
|
||||||
|
message.ack()
|
||||||
|
if data['failure']:
|
||||||
|
return d.errback(RemoteError(*data['failure']))
|
||||||
|
else:
|
||||||
|
return d.callback(data['result'])
|
||||||
|
|
||||||
|
consumer.register_callback(deferred_receive)
|
||||||
|
injected = consumer.attach_to_twisted()
|
||||||
|
|
||||||
|
# clean up after the injected listened and return x
|
||||||
|
d.addCallback(lambda x: injected.stop() and x or x)
|
||||||
|
|
||||||
|
publisher = TopicPublisher(connection=conn, topic=topic)
|
||||||
|
publisher.send(msg)
|
||||||
|
publisher.close()
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
def cast(topic, msg):
|
def cast(topic, msg):
|
||||||
"""Sends a message on a topic without waiting for a response"""
|
"""Sends a message on a topic without waiting for a response"""
|
||||||
LOG.debug("Making asynchronous cast...")
|
LOG.debug("Making asynchronous cast...")
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ FLAGS = flags.FLAGS
|
|||||||
class Context(object):
|
class Context(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class AccessTestCase(test.BaseTestCase):
|
class AccessTestCase(test.TrialTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(AccessTestCase, self).setUp()
|
super(AccessTestCase, self).setUp()
|
||||||
um = manager.AuthManager()
|
um = manager.AuthManager()
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ class user_and_project_generator(object):
|
|||||||
self.manager.delete_user(self.user)
|
self.manager.delete_user(self.user)
|
||||||
self.manager.delete_project(self.project)
|
self.manager.delete_project(self.project)
|
||||||
|
|
||||||
class AuthManagerTestCase(test.BaseTestCase):
|
class AuthManagerTestCase(test.TrialTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(AuthManagerTestCase, self).setUp()
|
super(AuthManagerTestCase, self).setUp()
|
||||||
self.flags(connection_type='fake')
|
self.flags(connection_type='fake')
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ from nova.api.ec2 import cloud
|
|||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
|
|
||||||
|
|
||||||
class CloudTestCase(test.BaseTestCase):
|
class CloudTestCase(test.TrialTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(CloudTestCase, self).setUp()
|
super(CloudTestCase, self).setUp()
|
||||||
self.flags(connection_type='fake')
|
self.flags(connection_type='fake')
|
||||||
@@ -57,7 +57,7 @@ class CloudTestCase(test.BaseTestCase):
|
|||||||
self.compute_consumer = rpc.AdapterConsumer(connection=self.conn,
|
self.compute_consumer = rpc.AdapterConsumer(connection=self.conn,
|
||||||
topic=FLAGS.compute_topic,
|
topic=FLAGS.compute_topic,
|
||||||
proxy=self.compute)
|
proxy=self.compute)
|
||||||
self.injected.append(self.compute_consumer.attach_to_tornado(self.ioloop))
|
self.compute_consumer.attach_to_twisted()
|
||||||
|
|
||||||
self.manager = manager.AuthManager()
|
self.manager = manager.AuthManager()
|
||||||
self.user = self.manager.create_user('admin', 'admin', 'admin', True)
|
self.user = self.manager.create_user('admin', 'admin', 'admin', True)
|
||||||
@@ -68,7 +68,7 @@ class CloudTestCase(test.BaseTestCase):
|
|||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.manager.delete_project(self.project)
|
self.manager.delete_project(self.project)
|
||||||
self.manager.delete_user(self.user)
|
self.manager.delete_user(self.user)
|
||||||
super(CloudTestCase, self).setUp()
|
super(CloudTestCase, self).tearDown()
|
||||||
|
|
||||||
def _create_key(self, name):
|
def _create_key(self, name):
|
||||||
# NOTE(vish): create depends on pool, so just call helper directly
|
# NOTE(vish): create depends on pool, so just call helper directly
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ os.makedirs(os.path.join(OSS_TEMPDIR, 'images'))
|
|||||||
os.makedirs(os.path.join(OSS_TEMPDIR, 'buckets'))
|
os.makedirs(os.path.join(OSS_TEMPDIR, 'buckets'))
|
||||||
|
|
||||||
|
|
||||||
class ObjectStoreTestCase(test.BaseTestCase):
|
class ObjectStoreTestCase(test.TrialTestCase):
|
||||||
"""Test objectstore API directly."""
|
"""Test objectstore API directly."""
|
||||||
|
|
||||||
def setUp(self): # pylint: disable-msg=C0103
|
def setUp(self): # pylint: disable-msg=C0103
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ from nova import test
|
|||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
|
|
||||||
|
|
||||||
class RpcTestCase(test.BaseTestCase):
|
class RpcTestCase(test.TrialTestCase):
|
||||||
"""Test cases for rpc"""
|
"""Test cases for rpc"""
|
||||||
def setUp(self): # pylint: disable-msg=C0103
|
def setUp(self): # pylint: disable-msg=C0103
|
||||||
super(RpcTestCase, self).setUp()
|
super(RpcTestCase, self).setUp()
|
||||||
@@ -39,13 +39,12 @@ class RpcTestCase(test.BaseTestCase):
|
|||||||
self.consumer = rpc.AdapterConsumer(connection=self.conn,
|
self.consumer = rpc.AdapterConsumer(connection=self.conn,
|
||||||
topic='test',
|
topic='test',
|
||||||
proxy=self.receiver)
|
proxy=self.receiver)
|
||||||
|
self.consumer.attach_to_twisted()
|
||||||
self.injected.append(self.consumer.attach_to_tornado(self.ioloop))
|
|
||||||
|
|
||||||
def test_call_succeed(self):
|
def test_call_succeed(self):
|
||||||
"""Get a value through rpc call"""
|
"""Get a value through rpc call"""
|
||||||
value = 42
|
value = 42
|
||||||
result = yield rpc.call('test', {"method": "echo",
|
result = yield rpc.call_twisted('test', {"method": "echo",
|
||||||
"args": {"value": value}})
|
"args": {"value": value}})
|
||||||
self.assertEqual(value, result)
|
self.assertEqual(value, result)
|
||||||
|
|
||||||
@@ -57,11 +56,11 @@ class RpcTestCase(test.BaseTestCase):
|
|||||||
to an int in the test.
|
to an int in the test.
|
||||||
"""
|
"""
|
||||||
value = 42
|
value = 42
|
||||||
self.assertFailure(rpc.call('test', {"method": "fail",
|
self.assertFailure(rpc.call_twisted('test', {"method": "fail",
|
||||||
"args": {"value": value}}),
|
"args": {"value": value}}),
|
||||||
rpc.RemoteError)
|
rpc.RemoteError)
|
||||||
try:
|
try:
|
||||||
yield rpc.call('test', {"method": "fail",
|
yield rpc.call_twisted('test', {"method": "fail",
|
||||||
"args": {"value": value}})
|
"args": {"value": value}})
|
||||||
self.fail("should have thrown rpc.RemoteError")
|
self.fail("should have thrown rpc.RemoteError")
|
||||||
except rpc.RemoteError as exc:
|
except rpc.RemoteError as exc:
|
||||||
|
|||||||
Reference in New Issue
Block a user