merged trunk

This commit is contained in:
Vishvananda Ishaya
2010-11-29 21:19:31 +00:00
24 changed files with 283 additions and 76 deletions

29
.mailmap Normal file
View File

@@ -0,0 +1,29 @@
# Format is:
# <preferred e-mail> <other e-mail>
<code@term.ie> <github@anarkystic.com>
<code@term.ie> <termie@preciousroy.local>
<Armando.Migliaccio@eu.citrix.com> <armando.migliaccio@citrix.com>
<matt.dietz@rackspace.com> <matthewdietz@Matthew-Dietzs-MacBook-Pro.local>
<matt.dietz@rackspace.com> <mdietz@openstack>
<cbehrens@codestud.com> <chris.behrens@rackspace.com>
<devin.carlen@gmail.com> <devcamcar@illian.local>
<ewan.mellor@citrix.com> <emellor@silver>
<jaypipes@gmail.com> <jpipes@serialcoder>
<anotherjesse@gmail.com> <jesse@dancelamb>
<anotherjesse@gmail.com> <jesse@gigantor.local>
<anotherjesse@gmail.com> <jesse@ubuntu>
<jmckenty@gmail.com> <jmckenty@yyj-dhcp171.corp.flock.com>
<jmckenty@gmail.com> <jmckenty@joshua-mckentys-macbook-pro.local>
<jmckenty@gmail.com> <joshua.mckenty@nasa.gov>
<justin@fathomdb.com> <justinsb@justinsb-desktop>
<mordred@inaugust.com> <mordred@hudson>
<paul@openstack.org> <pvoccio@castor.local>
<paul@openstack.org> <paul.voccio@rackspace.com>
<todd@ansolabs.com> <todd@lapex>
<todd@ansolabs.com> <todd@rubidine.com>
<vishvananda@gmail.com> <vishvananda@yahoo.com>
<vishvananda@gmail.com> <root@mirror.nasanebula.net>
# These are from people who failed to set a proper committer
. <root@tonbuntu>
. <laner@controller>
. <root@ubuntu>

View File

@@ -1,6 +1,9 @@
Andy Smith <code@term.ie>
Anne Gentle <anne@openstack.org>
Anthony Young <sleepsonthefloor@gmail.com>
Armando Migliaccio <Armando.Migliaccio@eu.citrix.com>
Chris Behrens <cbehrens@codestud.com>
Dean Troyer <dtroyer@gmail.com>
Devin Carlen <devin.carlen@gmail.com>
Eric Day <eday@oddments.org>
Ewan Mellor <ewan.mellor@citrix.com>
@@ -8,7 +11,8 @@ Hisaki Ohara <hisaki.ohara@intel.com>
Jay Pipes <jaypipes@gmail.com>
Jesse Andrews <anotherjesse@gmail.com>
Joe Heck <heckj@mac.com>
Joel Moore joelbm24@gmail.com
Joel Moore <joelbm24@gmail.com>
Josh Kearney <josh.kearney@rackspace.com>
Joshua McKenty <jmckenty@gmail.com>
Justin Santa Barbara <justin@fathomdb.com>
Matt Dietz <matt.dietz@rackspace.com>
@@ -19,3 +23,5 @@ Rick Clark <rick@openstack.org>
Soren Hansen <soren.hansen@rackspace.com>
Todd Willey <todd@ansolabs.com>
Vishvananda Ishaya <vishvananda@gmail.com>
Youcef Laribi <Youcef.Laribi@eu.citrix.com>
Zhixue Wu <Zhixue.Wu@citrix.com>

View File

@@ -13,9 +13,7 @@ include nova/cloudpipe/client.ovpn.template
include nova/compute/fakevirtinstance.xml
include nova/compute/interfaces.template
include nova/virt/interfaces.template
include nova/virt/libvirt.qemu.xml.template
include nova/virt/libvirt.uml.xml.template
include nova/virt/libvirt.xen.xml.template
include nova/virt/libvirt.*.xml.template
include nova/tests/CA/
include nova/tests/CA/cacert.pem
include nova/tests/CA/private/

View File

@@ -38,15 +38,17 @@ from nova import server
FLAGS = flags.FLAGS
flags.DEFINE_integer('osapi_port', 8774, 'OpenStack API port')
flags.DEFINE_string('osapi_host', '0.0.0.0', 'OpenStack API host')
flags.DEFINE_integer('ec2api_port', 8773, 'EC2 API port')
flags.DEFINE_string('ec2api_host', '0.0.0.0', 'EC2 API host')
def main(_args):
from nova import api
from nova import wsgi
server = wsgi.Server()
server.start(api.API('os'), FLAGS.osapi_port)
server.start(api.API('ec2'), FLAGS.ec2api_port)
server.start(api.API('os'), FLAGS.osapi_port, host=FLAGS.osapi_host)
server.start(api.API('ec2'), FLAGS.ec2api_port, host=FLAGS.ec2api_host)
server.wait()

View File

@@ -34,10 +34,12 @@ if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
from nova import service
from nova import twistd
from nova import utils
if __name__ == '__main__':
twistd.serve(__file__)
if __name__ == '__builtin__':
utils.default_flagfile()
application = service.Service.create() # pylint: disable=C0103

View File

@@ -34,6 +34,7 @@ possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
sys.path.insert(0, possible_topdir)
from nova import utils
from nova import twistd
from nova.compute import monitor
@@ -44,6 +45,7 @@ if __name__ == '__main__':
twistd.serve(__file__)
if __name__ == '__builtin__':
utils.default_flagfile()
logging.warn('Starting instance monitor')
# pylint: disable-msg=C0103
monitor = monitor.InstanceMonitor()

View File

@@ -487,7 +487,7 @@ def methods_of(obj):
def main():
"""Parse options and call the appropriate class/method."""
utils.default_flagfile('/etc/nova/nova-manage.conf')
utils.default_flagfile()
argv = FLAGS(sys.argv)
if FLAGS.verbose:

View File

@@ -34,10 +34,12 @@ if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
from nova import service
from nova import twistd
from nova import utils
if __name__ == '__main__':
twistd.serve(__file__)
if __name__ == '__builtin__':
utils.default_flagfile()
application = service.Service.create() # pylint: disable-msg=C0103

View File

@@ -34,10 +34,12 @@ if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
from nova import service
from nova import twistd
from nova import utils
if __name__ == '__main__':
twistd.serve(__file__)
if __name__ == '__builtin__':
utils.default_flagfile()
application = service.Service.create()

View File

@@ -34,10 +34,12 @@ if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
from nova import service
from nova import twistd
from nova import utils
if __name__ == '__main__':
twistd.serve(__file__)
if __name__ == '__builtin__':
utils.default_flagfile()
application = service.Service.create() # pylint: disable-msg=C0103

View File

@@ -22,25 +22,28 @@ Nova User API client library.
import base64
import boto
import httplib
from nova import flags
from boto.ec2.regioninfo import RegionInfo
FLAGS = flags.FLAGS
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
fields include:
username
accesskey
secretkey
Information about a Nova user, as parsed through SAX.
**Fields Include**
* username
* accesskey
* secretkey
* file (optional) containing zip of X509 cert & rc file
and an optional field containing a zip with X509 cert & rc
file
"""
def __init__(self, connection=None, username=None, endpoint=None):
@@ -68,9 +71,13 @@ class UserInfo(object):
class UserRole(object):
"""
Information about a Nova user's role, as parsed through SAX.
Fields include:
role
**Fields include**
* role
"""
def __init__(self, connection=None):
self.connection = connection
self.role = None
@@ -90,12 +97,15 @@ class UserRole(object):
class ProjectInfo(object):
"""
Information about a Nova project, as parsed through SAX
Fields include:
projectname
description
projectManagerId
memberIds
Information about a Nova project, as parsed through SAX.
**Fields include**
* projectname
* description
* projectManagerId
* memberIds
"""
def __init__(self, connection=None):
@@ -127,8 +137,11 @@ class ProjectInfo(object):
class ProjectMember(object):
"""
Information about a Nova project member, as parsed through SAX.
Fields include:
memberId
**Fields include**
* memberId
"""
def __init__(self, connection=None):
@@ -150,14 +163,18 @@ class ProjectMember(object):
class HostInfo(object):
"""
Information about a Nova Host, as parsed through SAX:
Disk stats
Running Instances
Memory stats
CPU stats
Network address info
Firewall info
Bridge and devices
Information about a Nova Host, as parsed through SAX.
**Fields Include**
* Disk stats
* Running Instances
* Memory stats
* CPU stats
* Network address info
* Firewall info
* Bridge and devices
"""
def __init__(self, connection=None):
@@ -177,9 +194,13 @@ class HostInfo(object):
class NovaAdminClient(object):
def __init__(self, clc_url=DEFAULT_CLC_URL, region=DEFAULT_REGION,
access_key=DEFAULT_ACCESS_KEY, secret_key=DEFAULT_SECRET_KEY,
**kwargs):
def __init__(
self,
clc_url=DEFAULT_CLC_URL,
region=DEFAULT_REGION,
access_key=FLAGS.aws_access_key_id,
secret_key=FLAGS.aws_secret_access_key,
**kwargs):
parts = self.split_clc_url(clc_url)
self.clc_url = clc_url
@@ -257,9 +278,12 @@ class NovaAdminClient(object):
[('item', UserRole)])
def get_user_roles(self, user, project=None):
"""Returns a list of roles for the given user. Omitting project will
return any global roles that the user has. Specifying project will
return only project specific roles."""
"""Returns a list of roles for the given user.
Omitting project will return any global roles that the user has.
Specifying project will return only project specific roles.
"""
params = {'User': user}
if project:
params['Project'] = project

View File

@@ -15,12 +15,12 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
Fake LDAP server for test harnesses.
"""Fake LDAP server for test harness, backs to ReDIS.
This class does very little error checking, and knows nothing about ldap
class definitions. It implements the minimum emulation of the python ldap
class definitions. It implements the minimum emulation of the python ldap
library to work with nova.
"""
import json
@@ -77,9 +77,8 @@ def initialize(_uri):
def _match_query(query, attrs):
"""Match an ldap query to an attribute dictionary.
&, |, and ! are supported in the query. No syntax checking is performed,
so malformed querys will not work correctly.
The characters &, |, and ! are supported in the query. No syntax checking
is performed, so malformed querys will not work correctly.
"""
# cut off the parentheses
inner = query[1:-1]

View File

@@ -80,12 +80,11 @@ class AuthBase(object):
@classmethod
def safe_id(cls, obj):
"""Safe get object id
"""Safely get object id.
This method will return the id of the object if the object
is of this class, otherwise it will return the original object.
This allows methods to accept objects or ids as paramaters.
"""
if isinstance(obj, cls):
return obj.id

View File

@@ -24,6 +24,7 @@ where they're used.
import getopt
import os
import socket
import string
import sys
import gflags
@@ -38,11 +39,12 @@ class FlagValues(gflags.FlagValues):
"""
def __init__(self):
def __init__(self, extra_context=None):
gflags.FlagValues.__init__(self)
self.__dict__['__dirty'] = []
self.__dict__['__was_already_parsed'] = False
self.__dict__['__stored_argv'] = []
self.__dict__['__extra_context'] = extra_context
def __call__(self, argv):
# We're doing some hacky stuff here so that we don't have to copy
@@ -112,7 +114,7 @@ class FlagValues(gflags.FlagValues):
def ParseNewFlags(self):
if '__stored_argv' not in self.__dict__:
return
new_flags = FlagValues()
new_flags = FlagValues(self)
for k in self.__dict__['__dirty']:
new_flags[k] = gflags.FlagValues.__getitem__(self, k)
@@ -134,9 +136,29 @@ class FlagValues(gflags.FlagValues):
def __getattr__(self, name):
if self.IsDirty(name):
self.ParseNewFlags()
return gflags.FlagValues.__getattr__(self, name)
val = gflags.FlagValues.__getattr__(self, name)
if type(val) is str:
tmpl = string.Template(val)
context = [self, self.__dict__['__extra_context']]
return tmpl.substitute(StrWrapper(context))
return val
class StrWrapper(object):
"""Wrapper around FlagValues objects
Wraps FlagValues objects for string.Template so that we're
sure to return strings."""
def __init__(self, context_objs):
self.context_objs = context_objs
def __getitem__(self, name):
for context in self.context_objs:
val = getattr(context, name, False)
if val:
return str(val)
raise KeyError(name)
FLAGS = FlagValues()
gflags.FLAGS = FLAGS
gflags.DEFINE_flag(gflags.HelpFlag(), FLAGS)
@@ -179,6 +201,8 @@ DEFINE_list('region_list',
[],
'list of region=url pairs separated by commas')
DEFINE_string('connection_type', 'libvirt', 'libvirt, xenapi or fake')
DEFINE_string('aws_access_key_id', 'admin', 'AWS Access ID')
DEFINE_string('aws_secret_access_key', 'admin', 'AWS Access Key')
DEFINE_integer('s3_port', 3333, 's3 port')
DEFINE_string('s3_host', '127.0.0.1', 's3 host (for infrastructure)')
DEFINE_string('s3_dmz', '127.0.0.1', 's3 dmz ip (for instances)')
@@ -197,6 +221,8 @@ DEFINE_integer('rabbit_port', 5672, 'rabbit port')
DEFINE_string('rabbit_userid', 'guest', 'rabbit userid')
DEFINE_string('rabbit_password', 'guest', 'rabbit password')
DEFINE_string('rabbit_virtual_host', '/', 'rabbit virtual host')
DEFINE_integer('rabbit_retry_interval', 10, 'rabbit connection retry interval')
DEFINE_integer('rabbit_max_retries', 12, 'rabbit connection attempts')
DEFINE_string('control_exchange', 'nova', 'the main exchange to connect to')
DEFINE_string('cc_host', '127.0.0.1', 'ip of api server (for infrastructure')
DEFINE_string('cc_dmz', '127.0.0.1', 'ip of api server (for instances)')
@@ -220,8 +246,11 @@ DEFINE_string('vpn_key_suffix',
DEFINE_integer('auth_token_ttl', 3600, 'Seconds for auth tokens to linger')
DEFINE_string('state_path', os.path.join(os.path.dirname(__file__), '../'),
"Top-level directory for maintaining nova's state")
DEFINE_string('sql_connection',
'sqlite:///%s/nova.sqlite' % os.path.abspath("./"),
'sqlite:///$state_path/nova.sqlite',
'connection string for sql database')
DEFINE_string('compute_manager', 'nova.compute.manager.ComputeManager',
@@ -234,7 +263,7 @@ DEFINE_string('scheduler_manager', 'nova.scheduler.manager.SchedulerManager',
'Manager for scheduler')
# The service to use for image search and retrieval
DEFINE_string('image_service', 'nova.image.service.LocalImageService',
DEFINE_string('image_service', 'nova.image.local.LocalImageService',
'The service to use for retrieving and searching for images.')
DEFINE_string('host', socket.gethostname(),

View File

@@ -24,6 +24,7 @@ No fan-out support yet.
import json
import logging
import sys
import time
import uuid
from carrot import connection as carrot_connection
@@ -37,8 +38,8 @@ from nova import fakerabbit
from nova import flags
from nova import context
FLAGS = flags.FLAGS
FLAGS = flags.FLAGS
LOG = logging.getLogger('amqplib')
LOG.setLevel(logging.DEBUG)
@@ -82,8 +83,24 @@ class Consumer(messaging.Consumer):
Contains methods for connecting the fetch method to async loops
"""
def __init__(self, *args, **kwargs):
self.failed_connection = False
super(Consumer, self).__init__(*args, **kwargs)
for i in xrange(FLAGS.rabbit_max_retries):
if i > 0:
time.sleep(FLAGS.rabbit_retry_interval)
try:
super(Consumer, self).__init__(*args, **kwargs)
self.failed_connection = False
break
except: # Catching all because carrot sucks
logging.exception("AMQP server on %s:%d is unreachable." \
" Trying again in %d seconds." % (
FLAGS.rabbit_host,
FLAGS.rabbit_port,
FLAGS.rabbit_retry_interval))
self.failed_connection = True
if self.failed_connection:
logging.exception("Unable to connect to AMQP server" \
" after %d tries. Shutting down." % FLAGS.rabbit_max_retries)
sys.exit(1)
def fetch(self, no_ack=None, auto_ack=None, enable_callbacks=False):
"""Wraps the parent fetch with some logic for failed connections"""
@@ -91,11 +108,12 @@ class Consumer(messaging.Consumer):
# refactored into some sort of connection manager object
try:
if self.failed_connection:
# NOTE(vish): conn is defined in the parent class, we can
# NOTE(vish): connection is defined in the parent class, we can
# recreate it as long as we create the backend too
# pylint: disable-msg=W0201
self.conn = Connection.recreate()
self.backend = self.conn.create_backend()
self.connection = Connection.recreate()
self.backend = self.connection.create_backend()
self.declare()
super(Consumer, self).fetch(no_ack, auto_ack, enable_callbacks)
if self.failed_connection:
logging.error("Reconnected to queue")

View File

@@ -42,6 +42,8 @@ flags.DEFINE_bool('daemonize', False, 'daemonize this process')
# clutter.
flags.DEFINE_bool('use_syslog', True, 'output to syslog when daemonizing')
flags.DEFINE_string('logfile', None, 'log file to output to')
flags.DEFINE_string('logdir', None, 'directory to keep log files in '
'(will be prepended to $logfile)')
flags.DEFINE_string('pidfile', None, 'pid file to output to')
flags.DEFINE_string('working_directory', './', 'working directory...')
flags.DEFINE_integer('uid', os.getuid(), 'uid under which to run')
@@ -119,6 +121,8 @@ def daemonize(args, name, main):
else:
if not FLAGS.logfile:
FLAGS.logfile = '%s.log' % name
if FLAGS.logdir:
FLAGS.logfile = os.path.join(FLAGS.logdir, FLAGS.logfile)
logfile = logging.FileHandler(FLAGS.logfile)
logfile.setFormatter(formatter)
logger.addHandler(logfile)

View File

@@ -91,6 +91,41 @@ class CloudTestCase(test.TrialTestCase):
# NOTE(vish): create depends on pool, so just call helper directly
return cloud._gen_key(self.context, self.context.user.id, name)
def test_describe_addresses(self):
"""Makes sure describe addresses runs without raising an exception"""
address = "10.10.10.10"
db.floating_ip_create(self.context,
{'address': address,
'host': FLAGS.host})
self.cloud.allocate_address(self.context)
self.cloud.describe_addresses(self.context)
self.cloud.release_address(self.context,
public_ip=address)
greenthread.sleep(0.3)
db.floating_ip_destroy(self.context, address)
def test_associate_disassociate_address(self):
"""Verifies associate runs cleanly without raising an exception"""
address = "10.10.10.10"
db.floating_ip_create(self.context,
{'address': address,
'host': FLAGS.host})
self.cloud.allocate_address(self.context)
inst = db.instance_create(self.context, {})
fixed = self.network.allocate_fixed_ip(self.context, inst['id'])
ec2_id = cloud.internal_id_to_ec2_id(inst['internal_id'])
self.cloud.associate_address(self.context,
instance_id=ec2_id,
public_ip=address)
self.cloud.disassociate_address(self.context,
public_ip=address)
self.cloud.release_address(self.context,
public_ip=address)
greenthread.sleep(0.3)
self.network.deallocate_fixed_ip(self.context, fixed)
db.instance_destroy(self.context, inst['id'])
db.floating_ip_destroy(self.context, address)
def test_console_output(self):
image_id = FLAGS.default_image
instance_type = FLAGS.default_instance_type

View File

@@ -24,6 +24,7 @@ flags.DECLARE('volume_driver', 'nova.volume.manager')
FLAGS.volume_driver = 'nova.volume.driver.FakeISCSIDriver'
FLAGS.connection_type = 'fake'
FLAGS.fake_rabbit = True
flags.DECLARE('auth_driver', 'nova.auth.manager')
FLAGS.auth_driver = 'nova.auth.dbdriver.DbDriver'
flags.DECLARE('network_size', 'nova.network.manager')
flags.DECLARE('num_networks', 'nova.network.manager')

View File

@@ -0,0 +1,48 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 OpenStack LLC
#
# 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.
import os
import subprocess
from nova import test
from nova.utils import parse_mailmap, str_dict_replace
class ProjectTestCase(test.TrialTestCase):
def test_authors_up_to_date(self):
if os.path.exists('../.bzr'):
log_cmd = subprocess.Popen(["bzr", "log", "-n0"],
stdout=subprocess.PIPE)
changelog = log_cmd.communicate()[0]
mailmap = parse_mailmap('../.mailmap')
contributors = set()
for l in changelog.split('\n'):
l = l.strip()
if (l.startswith('author:') or l.startswith('committer:')
and not l == 'committer: Tarmac'):
email = l.split(' ')[-1]
contributors.add(str_dict_replace(email, mailmap))
authors_file = open('../Authors', 'r').read()
missing = set()
for contributor in contributors:
if not contributor in authors_file:
missing.add(contributor)
self.assertTrue(len(missing) == 0,
'%r not listed in Authors' % missing)

View File

@@ -41,7 +41,6 @@ class NetworkTestCase(test.TrialTestCase):
# flags in the corresponding section in nova-dhcpbridge
self.flags(connection_type='fake',
fake_network=True,
auth_driver='nova.auth.ldapdriver.FakeLdapDriver',
network_size=16,
num_networks=5)
logging.getLogger().setLevel(logging.DEBUG)
@@ -127,6 +126,7 @@ class NetworkTestCase(test.TrialTestCase):
self.network.deallocate_floating_ip(self.context, float_addr)
self.network.deallocate_fixed_ip(self.context, fix_addr)
release_ip(fix_addr)
db.floating_ip_destroy(context.get_admin_context(), float_addr)
def test_allocate_deallocate_fixed_ip(self):
"""Makes sure that we can allocate and deallocate a fixed ip"""

View File

@@ -138,11 +138,8 @@ class QuotaTestCase(test.TrialTestCase):
def test_too_many_addresses(self):
address = '192.168.0.100'
try:
db.floating_ip_get_by_address(context.get_admin_context(), address)
except exception.NotFound:
db.floating_ip_create(context.get_admin_context(),
{'address': address, 'host': FLAGS.host})
db.floating_ip_create(context.get_admin_context(),
{'address': address, 'host': FLAGS.host})
float_addr = self.network.allocate_floating_ip(self.context,
self.project.id)
# NOTE(vish): This assert never fails. When cloud attempts to
@@ -151,3 +148,4 @@ class QuotaTestCase(test.TrialTestCase):
# that is breaking.
self.assertRaises(cloud.QuotaError, self.cloud.allocate_address,
self.context)
db.floating_ip_destroy(context.get_admin_context(), address)

View File

@@ -16,7 +16,8 @@
# License for the specific language governing permissions and limitations
# under the License.
"""
Tests for Volume Code
Tests for Volume Code.
"""
import logging
@@ -33,7 +34,8 @@ FLAGS = flags.FLAGS
class VolumeTestCase(test.TrialTestCase):
"""Test Case for volumes"""
"""Test Case for volumes."""
def setUp(self):
logging.getLogger().setLevel(logging.DEBUG)
super(VolumeTestCase, self).setUp()
@@ -44,7 +46,7 @@ class VolumeTestCase(test.TrialTestCase):
@staticmethod
def _create_volume(size='0'):
"""Create a volume object"""
"""Create a volume object."""
vol = {}
vol['size'] = size
vol['user_id'] = 'fake'
@@ -56,7 +58,7 @@ class VolumeTestCase(test.TrialTestCase):
@defer.inlineCallbacks
def test_create_delete_volume(self):
"""Test volume can be created and deleted"""
"""Test volume can be created and deleted."""
volume_id = self._create_volume()
yield self.volume.create_volume(self.context, volume_id)
self.assertEqual(volume_id, db.volume_get(context.get_admin_context(),
@@ -70,7 +72,7 @@ class VolumeTestCase(test.TrialTestCase):
@defer.inlineCallbacks
def test_too_big_volume(self):
"""Ensure failure if a too large of a volume is requested"""
"""Ensure failure if a too large of a volume is requested."""
# FIXME(vish): validation needs to move into the data layer in
# volume_create
defer.returnValue(True)
@@ -83,7 +85,7 @@ class VolumeTestCase(test.TrialTestCase):
@defer.inlineCallbacks
def test_too_many_volumes(self):
"""Ensure that NoMoreTargets is raised when we run out of volumes"""
"""Ensure that NoMoreTargets is raised when we run out of volumes."""
vols = []
total_slots = FLAGS.iscsi_num_targets
for _index in xrange(total_slots):
@@ -100,7 +102,7 @@ class VolumeTestCase(test.TrialTestCase):
@defer.inlineCallbacks
def test_run_attach_detach_volume(self):
"""Make sure volume can be attached and detached from instance"""
"""Make sure volume can be attached and detached from instance."""
inst = {}
inst['image_id'] = 'ami-test'
inst['reservation_id'] = 'r-fakeres'
@@ -149,12 +151,12 @@ class VolumeTestCase(test.TrialTestCase):
@defer.inlineCallbacks
def test_concurrent_volumes_get_different_targets(self):
"""Ensure multiple concurrent volumes get different targets"""
"""Ensure multiple concurrent volumes get different targets."""
volume_ids = []
targets = []
def _check(volume_id):
"""Make sure targets aren't duplicated"""
"""Make sure targets aren't duplicated."""
volume_ids.append(volume_id)
admin_context = context.get_admin_context()
iscsi_target = db.volume_get_iscsi_target_num(admin_context,

View File

@@ -43,6 +43,8 @@ else:
FLAGS = flags.FLAGS
flags.DEFINE_string('logdir', None, 'directory to keep log files in '
'(will be prepended to $logfile)')
class TwistdServerOptions(ServerOptions):
@@ -246,6 +248,8 @@ def serve(filename):
FLAGS.logfile = '%s.log' % name
elif FLAGS.logfile.endswith('twistd.log'):
FLAGS.logfile = FLAGS.logfile.replace('twistd.log', '%s.log' % name)
if FLAGS.logdir:
FLAGS.logfile = os.path.join(FLAGS.logdir, FLAGS.logfile)
if not FLAGS.prefix:
FLAGS.prefix = name
elif FLAGS.prefix.endswith('twisted'):

View File

@@ -49,11 +49,12 @@ from nova import flags
from nova import twistd
from nova.tests.access_unittest import *
from nova.tests.auth_unittest import *
from nova.tests.api_unittest import *
from nova.tests.auth_unittest import *
from nova.tests.cloud_unittest import *
from nova.tests.compute_unittest import *
from nova.tests.flags_unittest import *
from nova.tests.misc_unittest import *
from nova.tests.network_unittest import *
from nova.tests.objectstore_unittest import *
from nova.tests.process_unittest import *
@@ -64,8 +65,8 @@ from nova.tests.service_unittest import *
from nova.tests.twistd_unittest import *
from nova.tests.validator_unittest import *
from nova.tests.virt_unittest import *
from nova.tests.volume_unittest import *
from nova.tests.virt_unittest import *
from nova.tests.volume_unittest import *
FLAGS = flags.FLAGS