Merge Trunk

This commit is contained in:
Todd Willey
2010-09-28 23:23:41 -04:00
8 changed files with 147 additions and 64 deletions

View File

@@ -135,15 +135,48 @@ class VpnCommands(object):
class ShellCommands(object):
def run(self):
"Runs a Python interactive interpreter. Tries to use IPython, if it's available."
try:
import IPython
# Explicitly pass an empty list as arguments, because otherwise IPython
# would use sys.argv from this script.
shell = IPython.Shell.IPShell(argv=[])
shell.mainloop()
except ImportError:
def bpython(self):
"""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:
import IPython
# Explicitly pass an empty list as arguments, because otherwise IPython
# would use sys.argv from this script.
shell = IPython.Shell.IPShell(argv=[])
shell.mainloop()
except ImportError:
shell = 'python'
if shell == 'python':
import code
try: # Try activating rlcompleter, because it's handy.
import readline
@@ -156,6 +189,11 @@ class ShellCommands(object):
readline.parse_and_bind("tab:complete")
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 for managing roles."""
@@ -266,7 +304,7 @@ class ProjectCommands(object):
def environment(self, project_id, user_id, filename='novarc'):
"""Exports environment variables to an sourcable file
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:
f.write(rc)
@@ -329,7 +367,7 @@ class FloatingIpCommands(object):
for floating_ip in floating_ips:
instance = None
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'],
floating_ip['address'],
instance)

View File

@@ -20,11 +20,17 @@ Nova User API client library.
"""
import base64
import boto
import httplib
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):
"""
Information about a Nova user, as parsed through SAX
@@ -68,13 +74,13 @@ class UserRole(object):
def __init__(self, connection=None):
self.connection = connection
self.role = None
def __repr__(self):
return 'UserRole:%s' % self.role
def startElement(self, name, attrs, connection):
return None
def endElement(self, name, value, connection):
if name == 'role':
self.role = value
@@ -128,20 +134,20 @@ class ProjectMember(object):
def __init__(self, connection=None):
self.connection = connection
self.memberId = None
def __repr__(self):
return 'ProjectMember:%s' % self.memberId
def startElement(self, name, attrs, connection):
return None
def endElement(self, name, value, connection):
if name == 'member':
self.memberId = value
else:
setattr(self, name, str(value))
class HostInfo(object):
"""
Information about a Nova Host, as parsed through SAX:
@@ -171,35 +177,56 @@ class HostInfo(object):
class NovaAdminClient(object):
def __init__(self, clc_ip='127.0.0.1', region='nova', access_key='admin',
secret_key='admin', **kwargs):
self.clc_ip = clc_ip
def __init__(self, clc_url=DEFAULT_CLC_URL, region=DEFAULT_REGION,
access_key=DEFAULT_ACCESS_KEY, secret_key=DEFAULT_SECRET_KEY,
**kwargs):
parts = self.split_clc_url(clc_url)
self.clc_url = clc_url
self.region = region
self.access = access_key
self.secret = secret_key
self.apiconn = boto.connect_ec2(aws_access_key_id=access_key,
aws_secret_access_key=secret_key,
is_secure=False,
region=RegionInfo(None, region, clc_ip),
port=8773,
is_secure=parts['is_secure'],
region=RegionInfo(None,
region,
parts['ip']),
port=parts['port'],
path='/services/Admin',
**kwargs)
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.
"""
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)
access_key = '%s:%s' % (user.accesskey, project)
return boto.connect_ec2(
aws_access_key_id=access_key,
aws_secret_access_key=user.secretkey,
is_secure=False,
region=RegionInfo(None, self.region, self.clc_ip),
port=8773,
path='/services/Cloud',
**kwargs)
return boto.connect_ec2(aws_access_key_id=access_key,
aws_secret_access_key=user.secretkey,
is_secure=parts['is_secure'],
region=RegionInfo(None,
self.region,
parts['ip']),
port=parts['port'],
path='/services/Cloud',
**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):
""" grabs the list of all users """
@@ -289,7 +316,7 @@ class NovaAdminClient(object):
if project.projectname != None:
return project
def create_project(self, projectname, manager_user, description=None,
member_users=None):
"""
@@ -322,7 +349,7 @@ class NovaAdminClient(object):
Adds a user to a project.
"""
return self.modify_project_member(user, project, operation='add')
def remove_project_member(self, user, project):
"""
Removes a user from a project.

View File

@@ -84,19 +84,6 @@ class Consumer(messaging.Consumer):
self.failed_connection = False
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):
"""Wraps the parent fetch with some logic for failed connections"""
# 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"""
loop = task.LoopingCall(self.fetch, enable_callbacks=True)
loop.start(interval=0.1)
return loop
class Publisher(messaging.Publisher):
@@ -294,6 +282,37 @@ def call(topic, msg):
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):
"""Sends a message on a topic without waiting for a response"""
LOG.debug("Making asynchronous cast...")

View File

@@ -31,7 +31,7 @@ FLAGS = flags.FLAGS
class Context(object):
pass
class AccessTestCase(test.BaseTestCase):
class AccessTestCase(test.TrialTestCase):
def setUp(self):
super(AccessTestCase, self).setUp()
um = manager.AuthManager()

View File

@@ -75,7 +75,7 @@ class user_and_project_generator(object):
self.manager.delete_user(self.user)
self.manager.delete_project(self.project)
class AuthManagerTestCase(test.BaseTestCase):
class AuthManagerTestCase(test.TrialTestCase):
def setUp(self):
super(AuthManagerTestCase, self).setUp()
self.flags(connection_type='fake')

View File

@@ -41,7 +41,7 @@ from nova.api.ec2 import cloud
FLAGS = flags.FLAGS
class CloudTestCase(test.BaseTestCase):
class CloudTestCase(test.TrialTestCase):
def setUp(self):
super(CloudTestCase, self).setUp()
self.flags(connection_type='fake')
@@ -55,9 +55,9 @@ class CloudTestCase(test.BaseTestCase):
# set up a service
self.compute = utils.import_class(FLAGS.compute_manager)
self.compute_consumer = rpc.AdapterConsumer(connection=self.conn,
topic=FLAGS.compute_topic,
proxy=self.compute)
self.injected.append(self.compute_consumer.attach_to_tornado(self.ioloop))
topic=FLAGS.compute_topic,
proxy=self.compute)
self.compute_consumer.attach_to_twisted()
self.manager = manager.AuthManager()
self.user = self.manager.create_user('admin', 'admin', 'admin', True)
@@ -68,7 +68,7 @@ class CloudTestCase(test.BaseTestCase):
def tearDown(self):
self.manager.delete_project(self.project)
self.manager.delete_user(self.user)
super(CloudTestCase, self).setUp()
super(CloudTestCase, self).tearDown()
def _create_key(self, name):
# NOTE(vish): create depends on pool, so just call helper directly

View File

@@ -53,7 +53,7 @@ os.makedirs(os.path.join(OSS_TEMPDIR, 'images'))
os.makedirs(os.path.join(OSS_TEMPDIR, 'buckets'))
class ObjectStoreTestCase(test.BaseTestCase):
class ObjectStoreTestCase(test.TrialTestCase):
"""Test objectstore API directly."""
def setUp(self): # pylint: disable-msg=C0103

View File

@@ -30,7 +30,7 @@ from nova import test
FLAGS = flags.FLAGS
class RpcTestCase(test.BaseTestCase):
class RpcTestCase(test.TrialTestCase):
"""Test cases for rpc"""
def setUp(self): # pylint: disable-msg=C0103
super(RpcTestCase, self).setUp()
@@ -39,14 +39,13 @@ class RpcTestCase(test.BaseTestCase):
self.consumer = rpc.AdapterConsumer(connection=self.conn,
topic='test',
proxy=self.receiver)
self.injected.append(self.consumer.attach_to_tornado(self.ioloop))
self.consumer.attach_to_twisted()
def test_call_succeed(self):
"""Get a value through rpc call"""
value = 42
result = yield rpc.call('test', {"method": "echo",
"args": {"value": value}})
result = yield rpc.call_twisted('test', {"method": "echo",
"args": {"value": value}})
self.assertEqual(value, result)
def test_call_exception(self):
@@ -57,12 +56,12 @@ class RpcTestCase(test.BaseTestCase):
to an int in the test.
"""
value = 42
self.assertFailure(rpc.call('test', {"method": "fail",
"args": {"value": value}}),
self.assertFailure(rpc.call_twisted('test', {"method": "fail",
"args": {"value": value}}),
rpc.RemoteError)
try:
yield rpc.call('test', {"method": "fail",
"args": {"value": value}})
yield rpc.call_twisted('test', {"method": "fail",
"args": {"value": value}})
self.fail("should have thrown rpc.RemoteError")
except rpc.RemoteError as exc:
self.assertEqual(int(exc.value), value)