merged trunk

This commit is contained in:
Vishvananda Ishaya
2011-02-23 15:27:54 -08:00
30 changed files with 24553 additions and 305 deletions

View File

@@ -1,2 +0,0 @@
[python: **.py]

View File

@@ -42,6 +42,12 @@ from nova import wsgi
LOG = logging.getLogger('nova.api') LOG = logging.getLogger('nova.api')
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
flags.DEFINE_string('ec2_listen', "0.0.0.0",
'IP address for EC2 API to listen')
flags.DEFINE_integer('ec2_listen_port', 8773, 'port for ec2 api to listen')
flags.DEFINE_string('osapi_listen', "0.0.0.0",
'IP address for OpenStack API to listen')
flags.DEFINE_integer('osapi_listen_port', 8774, 'port for os api to listen')
API_ENDPOINTS = ['ec2', 'osapi'] API_ENDPOINTS = ['ec2', 'osapi']
@@ -55,22 +61,15 @@ def run_app(paste_config_file):
LOG.debug(_("No paste configuration for app: %s"), api) LOG.debug(_("No paste configuration for app: %s"), api)
continue continue
LOG.debug(_("App Config: %(api)s\n%(config)r") % locals()) LOG.debug(_("App Config: %(api)s\n%(config)r") % locals())
wsgi.paste_config_to_flags(config, {
"verbose": FLAGS.verbose,
"%s_host" % api: config.get('host', '0.0.0.0'),
"%s_port" % api: getattr(FLAGS, "%s_port" % api)})
LOG.info(_("Running %s API"), api) LOG.info(_("Running %s API"), api)
app = wsgi.load_paste_app(paste_config_file, api) app = wsgi.load_paste_app(paste_config_file, api)
apps.append((app, getattr(FLAGS, "%s_port" % api), apps.append((app, getattr(FLAGS, "%s_listen_port" % api),
getattr(FLAGS, "%s_host" % api))) getattr(FLAGS, "%s_listen" % api)))
if len(apps) == 0: if len(apps) == 0:
LOG.error(_("No known API applications configured in %s."), LOG.error(_("No known API applications configured in %s."),
paste_config_file) paste_config_file)
return return
# NOTE(todd): redo logging config, verbose could be set in paste config
logging.reset()
server = wsgi.Server() server = wsgi.Server()
for app in apps: for app in apps:
server.start(*app) server.start(*app)
@@ -82,6 +81,10 @@ if __name__ == '__main__':
logging.setup() logging.setup()
LOG.audit(_("Starting nova-api node (version %s)"), LOG.audit(_("Starting nova-api node (version %s)"),
version.version_string_with_vcs()) version.version_string_with_vcs())
LOG.debug(_("Full set of FLAGS:"))
for flag in FLAGS:
flag_get = FLAGS.get(flag, None)
LOG.debug("%(flag)s : %(flag_get)s" % locals())
conf = wsgi.paste_config_file('nova-api.conf') conf = wsgi.paste_config_file('nova-api.conf')
if conf: if conf:
run_app(conf) run_app(conf)

View File

@@ -1,79 +0,0 @@
#!/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.
"""Combined starter script for Nova services."""
import eventlet
eventlet.monkey_patch()
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 log as logging
from nova import service
from nova import utils
from nova import wsgi
FLAGS = flags.FLAGS
if __name__ == '__main__':
utils.default_flagfile()
FLAGS(sys.argv)
logging.setup()
compute = service.Service.create(binary='nova-compute')
network = service.Service.create(binary='nova-network')
volume = service.Service.create(binary='nova-volume')
scheduler = service.Service.create(binary='nova-scheduler')
#objectstore = service.Service.create(binary='nova-objectstore')
service.serve(compute, network, volume, scheduler)
apps = []
paste_config_file = wsgi.paste_config_file('nova-api.conf')
for api in ['osapi', 'ec2']:
config = wsgi.load_paste_configuration(paste_config_file, api)
if config is None:
continue
wsgi.paste_config_to_flags(config, {
"verbose": FLAGS.verbose,
"%s_host" % api: config.get('host', '0.0.0.0'),
"%s_port" % api: getattr(FLAGS, "%s_port" % api)})
app = wsgi.load_paste_app(paste_config_file, api)
apps.append((app, getattr(FLAGS, "%s_port" % api),
getattr(FLAGS, "%s_host" % api)))
if len(apps) > 0:
server = wsgi.Server()
for app in apps:
server.start(*app)
server.wait()

View File

@@ -30,5 +30,3 @@
.. moduleauthor:: Manish Singh <yosh@gimp.org> .. moduleauthor:: Manish Singh <yosh@gimp.org>
.. moduleauthor:: Andy Smith <andy@anarkystic.com> .. moduleauthor:: Andy Smith <andy@anarkystic.com>
""" """
from exception import *

View File

@@ -35,6 +35,8 @@ flags.DEFINE_integer('quota_gigabytes', 1000,
'number of volume gigabytes allowed per project') 'number of volume gigabytes allowed per project')
flags.DEFINE_integer('quota_floating_ips', 10, flags.DEFINE_integer('quota_floating_ips', 10,
'number of floating ips allowed per project') 'number of floating ips allowed per project')
flags.DEFINE_integer('quota_metadata_items', 128,
'number of metadata items allowed per instance')
def get_quota(context, project_id): def get_quota(context, project_id):
@@ -42,7 +44,8 @@ def get_quota(context, project_id):
'cores': FLAGS.quota_cores, 'cores': FLAGS.quota_cores,
'volumes': FLAGS.quota_volumes, 'volumes': FLAGS.quota_volumes,
'gigabytes': FLAGS.quota_gigabytes, 'gigabytes': FLAGS.quota_gigabytes,
'floating_ips': FLAGS.quota_floating_ips} 'floating_ips': FLAGS.quota_floating_ips,
'metadata_items': FLAGS.quota_metadata_items}
try: try:
quota = db.quota_get(context, project_id) quota = db.quota_get(context, project_id)
for key in rval.keys(): for key in rval.keys():
@@ -94,6 +97,15 @@ def allowed_floating_ips(context, num_floating_ips):
return min(num_floating_ips, allowed_floating_ips) return min(num_floating_ips, allowed_floating_ips)
def allowed_metadata_items(context, num_metadata_items):
"""Check quota; return min(num_metadata_items,allowed_metadata_items)"""
project_id = context.project_id
context = context.elevated()
quota = get_quota(context, project_id)
num_allowed_metadata_items = quota['metadata_items']
return min(num_metadata_items, num_allowed_metadata_items)
class QuotaError(exception.ApiError): class QuotaError(exception.ApiError):
"""Quota Exceeeded""" """Quota Exceeeded"""
pass pass

View File

@@ -50,10 +50,6 @@ flags.DEFINE_integer('periodic_interval', 60,
'seconds between running periodic tasks', 'seconds between running periodic tasks',
lower_bound=1) lower_bound=1)
flags.DEFINE_string('pidfile', None,
'pidfile to use for this service')
flags.DEFINE_flag(flags.HelpFlag()) flags.DEFINE_flag(flags.HelpFlag())
flags.DEFINE_flag(flags.HelpshortFlag()) flags.DEFINE_flag(flags.HelpshortFlag())
flags.DEFINE_flag(flags.HelpXMLFlag()) flags.DEFINE_flag(flags.HelpXMLFlag())
@@ -181,6 +177,13 @@ class Service(object):
pass pass
self.timers = [] self.timers = []
def wait(self):
for x in self.timers:
try:
x.wait()
except Exception:
pass
def periodic_tasks(self): def periodic_tasks(self):
"""Tasks to be run at a periodic interval""" """Tasks to be run at a periodic interval"""
self.manager.periodic_tasks(context.get_admin_context()) self.manager.periodic_tasks(context.get_admin_context())

View File

@@ -23,6 +23,7 @@ and some black magic for inline callbacks.
""" """
import datetime import datetime
import uuid
import unittest import unittest
import mox import mox
@@ -34,6 +35,7 @@ from nova import fakerabbit
from nova import flags from nova import flags
from nova import log as logging from nova import log as logging
from nova import rpc from nova import rpc
from nova import service
from nova.network import manager as network_manager from nova.network import manager as network_manager
@@ -80,6 +82,7 @@ class TestCase(unittest.TestCase):
self.stubs = stubout.StubOutForTesting() self.stubs = stubout.StubOutForTesting()
self.flag_overrides = {} self.flag_overrides = {}
self.injected = [] self.injected = []
self._services = []
self._monkey_patch_attach() self._monkey_patch_attach()
self._original_flags = FLAGS.FlagValuesDict() self._original_flags = FLAGS.FlagValuesDict()
@@ -91,25 +94,42 @@ class TestCase(unittest.TestCase):
self.stubs.UnsetAll() self.stubs.UnsetAll()
self.stubs.SmartUnsetAll() self.stubs.SmartUnsetAll()
self.mox.VerifyAll() self.mox.VerifyAll()
# NOTE(vish): Clean up any ips associated during the test. super(TestCase, self).tearDown()
ctxt = context.get_admin_context() finally:
db.fixed_ip_disassociate_all_by_timeout(ctxt, FLAGS.host, try:
self.start) # Clean up any ips associated during the test.
db.network_disassociate_all(ctxt) ctxt = context.get_admin_context()
db.fixed_ip_disassociate_all_by_timeout(ctxt, FLAGS.host,
self.start)
db.network_disassociate_all(ctxt)
db.security_group_destroy_all(ctxt)
except Exception:
pass
# Clean out fake_rabbit's queue if we used it
if FLAGS.fake_rabbit:
fakerabbit.reset_all()
# Reset any overriden flags
self.reset_flags()
# Reset our monkey-patches
rpc.Consumer.attach_to_eventlet = self.originalAttach rpc.Consumer.attach_to_eventlet = self.originalAttach
# Stop any timers
for x in self.injected: for x in self.injected:
try: try:
x.stop() x.stop()
except AssertionError: except AssertionError:
pass pass
if FLAGS.fake_rabbit: # Kill any services
fakerabbit.reset_all() for x in self._services:
try:
db.security_group_destroy_all(ctxt) x.kill()
super(TestCase, self).tearDown() except Exception:
finally: pass
self.reset_flags()
def flags(self, **kw): def flags(self, **kw):
"""Override flag variables for a test""" """Override flag variables for a test"""
@@ -127,6 +147,15 @@ class TestCase(unittest.TestCase):
for k, v in self._original_flags.iteritems(): for k, v in self._original_flags.iteritems():
setattr(FLAGS, k, v) setattr(FLAGS, k, v)
def start_service(self, name, host=None, **kwargs):
host = host and host or uuid.uuid4().hex
kwargs.setdefault('host', host)
kwargs.setdefault('binary', 'nova-%s' % name)
svc = service.Service.create(**kwargs)
svc.start()
self._services.append(svc)
return svc
def _monkey_patch_attach(self): def _monkey_patch_attach(self):
self.originalAttach = rpc.Consumer.attach_to_eventlet self.originalAttach = rpc.Consumer.attach_to_eventlet

View File

@@ -20,6 +20,7 @@
import boto import boto
from boto.ec2 import regioninfo from boto.ec2 import regioninfo
import datetime
import httplib import httplib
import random import random
import StringIO import StringIO
@@ -127,6 +128,28 @@ class ApiEc2TestCase(test.TestCase):
self.ec2.new_http_connection(host, is_secure).AndReturn(self.http) self.ec2.new_http_connection(host, is_secure).AndReturn(self.http)
return self.http return self.http
def test_return_valid_isoformat(self):
"""
Ensure that the ec2 api returns datetime in xs:dateTime
(which apparently isn't datetime.isoformat())
NOTE(ken-pepple): https://bugs.launchpad.net/nova/+bug/721297
"""
conv = apirequest._database_to_isoformat
# sqlite database representation with microseconds
time_to_convert = datetime.datetime.strptime(
"2011-02-21 20:14:10.634276",
"%Y-%m-%d %H:%M:%S.%f")
self.assertEqual(
conv(time_to_convert),
'2011-02-21T20:14:10Z')
# mysqlite database representation
time_to_convert = datetime.datetime.strptime(
"2011-02-21 19:56:18",
"%Y-%m-%d %H:%M:%S")
self.assertEqual(
conv(time_to_convert),
'2011-02-21T19:56:18Z')
def test_xmlns_version_matches_request_version(self): def test_xmlns_version_matches_request_version(self):
self.expect_http(api_version='2010-10-30') self.expect_http(api_version='2010-10-30')
self.mox.ReplayAll() self.mox.ReplayAll()

View File

@@ -65,18 +65,21 @@ class CloudTestCase(test.TestCase):
self.cloud = cloud.CloudController() self.cloud = cloud.CloudController()
# set up services # set up services
self.compute = service.Service.create(binary='nova-compute') self.compute = self.start_service('compute')
self.compute.start() self.scheduter = self.start_service('scheduler')
self.network = service.Service.create(binary='nova-network') self.network = self.start_service('network')
self.network.start()
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)
self.project = self.manager.create_project('proj', 'admin', 'proj') self.project = self.manager.create_project('proj', 'admin', 'proj')
self.context = context.RequestContext(user=self.user, self.context = context.RequestContext(user=self.user,
project=self.project) project=self.project)
host = self.network.get_network_host(self.context.elevated())
def tearDown(self): def tearDown(self):
network_ref = db.project_get_network(self.context,
self.project.id)
db.network_disassociate(self.context, network_ref['id'])
self.manager.delete_project(self.project) self.manager.delete_project(self.project)
self.manager.delete_user(self.user) self.manager.delete_user(self.user)
self.compute.kill() self.compute.kill()
@@ -102,7 +105,7 @@ class CloudTestCase(test.TestCase):
address = "10.10.10.10" address = "10.10.10.10"
db.floating_ip_create(self.context, db.floating_ip_create(self.context,
{'address': address, {'address': address,
'host': FLAGS.host}) 'host': self.network.host})
self.cloud.allocate_address(self.context) self.cloud.allocate_address(self.context)
self.cloud.describe_addresses(self.context) self.cloud.describe_addresses(self.context)
self.cloud.release_address(self.context, self.cloud.release_address(self.context,
@@ -115,9 +118,9 @@ class CloudTestCase(test.TestCase):
address = "10.10.10.10" address = "10.10.10.10"
db.floating_ip_create(self.context, db.floating_ip_create(self.context,
{'address': address, {'address': address,
'host': FLAGS.host}) 'host': self.network.host})
self.cloud.allocate_address(self.context) self.cloud.allocate_address(self.context)
inst = db.instance_create(self.context, {'host': FLAGS.host}) inst = db.instance_create(self.context, {'host': self.compute.host})
fixed = self.network.allocate_fixed_ip(self.context, inst['id']) fixed = self.network.allocate_fixed_ip(self.context, inst['id'])
ec2_id = cloud.id_to_ec2_id(inst['id']) ec2_id = cloud.id_to_ec2_id(inst['id'])
self.cloud.associate_address(self.context, self.cloud.associate_address(self.context,
@@ -133,6 +136,22 @@ class CloudTestCase(test.TestCase):
db.instance_destroy(self.context, inst['id']) db.instance_destroy(self.context, inst['id'])
db.floating_ip_destroy(self.context, address) db.floating_ip_destroy(self.context, address)
def test_describe_security_groups(self):
"""Makes sure describe_security_groups works and filters results."""
sec = db.security_group_create(self.context,
{'project_id': self.context.project_id,
'name': 'test'})
result = self.cloud.describe_security_groups(self.context)
# NOTE(vish): should have the default group as well
self.assertEqual(len(result['securityGroupInfo']), 2)
result = self.cloud.describe_security_groups(self.context,
group_name=[sec['name']])
self.assertEqual(len(result['securityGroupInfo']), 1)
self.assertEqual(
result['securityGroupInfo'][0]['groupName'],
sec['name'])
db.security_group_destroy(self.context, sec['id'])
def test_describe_volumes(self): def test_describe_volumes(self):
"""Makes sure describe_volumes works and filters results.""" """Makes sure describe_volumes works and filters results."""
vol1 = db.volume_create(self.context, {}) vol1 = db.volume_create(self.context, {})
@@ -203,27 +222,32 @@ class CloudTestCase(test.TestCase):
'instance_type': instance_type, 'instance_type': instance_type,
'max_count': max_count} 'max_count': max_count}
rv = self.cloud.run_instances(self.context, **kwargs) rv = self.cloud.run_instances(self.context, **kwargs)
greenthread.sleep(0.3)
instance_id = rv['instancesSet'][0]['instanceId'] instance_id = rv['instancesSet'][0]['instanceId']
output = self.cloud.get_console_output(context=self.context, output = self.cloud.get_console_output(context=self.context,
instance_id=[instance_id]) instance_id=[instance_id])
self.assertEquals(b64decode(output['output']), 'FAKE CONSOLE OUTPUT') self.assertEquals(b64decode(output['output']), 'FAKE CONSOLE OUTPUT')
# TODO(soren): We need this until we can stop polling in the rpc code # TODO(soren): We need this until we can stop polling in the rpc code
# for unit tests. # for unit tests.
greenthread.sleep(0.3) greenthread.sleep(0.3)
rv = self.cloud.terminate_instances(self.context, [instance_id]) rv = self.cloud.terminate_instances(self.context, [instance_id])
greenthread.sleep(0.3)
def test_ajax_console(self): def test_ajax_console(self):
image_id = FLAGS.default_image
kwargs = {'image_id': image_id} kwargs = {'image_id': image_id}
rv = yield self.cloud.run_instances(self.context, **kwargs) rv = self.cloud.run_instances(self.context, **kwargs)
instance_id = rv['instancesSet'][0]['instanceId'] instance_id = rv['instancesSet'][0]['instanceId']
output = yield self.cloud.get_console_output(context=self.context, greenthread.sleep(0.3)
instance_id=[instance_id]) output = self.cloud.get_ajax_console(context=self.context,
self.assertEquals(b64decode(output['output']), instance_id=[instance_id])
'http://fakeajaxconsole.com/?token=FAKETOKEN') self.assertEquals(output['url'],
'%s/?token=FAKETOKEN' % FLAGS.ajax_console_proxy_url)
# TODO(soren): We need this until we can stop polling in the rpc code # TODO(soren): We need this until we can stop polling in the rpc code
# for unit tests. # for unit tests.
greenthread.sleep(0.3) greenthread.sleep(0.3)
rv = yield self.cloud.terminate_instances(self.context, [instance_id]) rv = self.cloud.terminate_instances(self.context, [instance_id])
greenthread.sleep(0.3)
def test_key_generation(self): def test_key_generation(self):
result = self._create_key('test') result = self._create_key('test')
@@ -286,70 +310,6 @@ class CloudTestCase(test.TestCase):
LOG.debug(_("Terminating instance %s"), instance_id) LOG.debug(_("Terminating instance %s"), instance_id)
rv = self.compute.terminate_instance(instance_id) rv = self.compute.terminate_instance(instance_id)
def test_describe_instances(self):
"""Makes sure describe_instances works."""
instance1 = db.instance_create(self.context, {'host': 'host2'})
comp1 = db.service_create(self.context, {'host': 'host2',
'availability_zone': 'zone1',
'topic': "compute"})
result = self.cloud.describe_instances(self.context)
self.assertEqual(result['reservationSet'][0]
['instancesSet'][0]
['placement']['availabilityZone'], 'zone1')
db.instance_destroy(self.context, instance1['id'])
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',
'instance_id': 'i-%s' % num,
'image_id': 'ami-%s' % num,
'private_dns_name': '10.0.0.%s' % num,
'dns_name': '10.0.0%s' % num,
'ami_launch_index': str(num),
'instance_type': 'fake',
'availability_zone': 'fake',
'key_name': None,
'kernel_id': 'fake',
'ramdisk_id': 'fake',
'groups': ['default'],
'product_codes': None,
'state': 0x01,
'user_data': ''}
rv = self.cloud._format_describe_instances(self.context)
logging.error(str(rv))
self.assertEqual(len(rv['reservationSet']), 0)
# simulate launch of 5 instances
# self.cloud.instances['pending'] = {}
#for i in xrange(5):
# inst = instance(i)
# self.cloud.instances['pending'][inst['instance_id']] = inst
#rv = self.cloud._format_instances(self.admin)
#self.assert_(len(rv['reservationSet']) == 1)
#self.assert_(len(rv['reservationSet'][0]['instances_set']) == 5)
# report 4 nodes each having 1 of the instances
#for i in xrange(4):
# self.cloud.update_state('instances',
# {('node-%s' % i): {('i-%s' % i):
# instance(i)}})
# one instance should be pending still
#self.assert_(len(self.cloud.instances['pending'].keys()) == 1)
# check that the reservations collapse
#rv = self.cloud._format_instances(self.admin)
#self.assert_(len(rv['reservationSet']) == 1)
#self.assert_(len(rv['reservationSet'][0]['instances_set']) == 5)
# check that we can get metadata for each instance
#for i in xrange(4):
# data = self.cloud.get_metadata(instance(i)['private_dns_name'])
# self.assert_(data['meta-data']['ami-id'] == 'ami-%s' % i)
@staticmethod @staticmethod
def _fake_set_image_description(ctxt, image_id, description): def _fake_set_image_description(ctxt, image_id, description):
from nova.objectstore import handler from nova.objectstore import handler

View File

@@ -46,6 +46,8 @@ class ProjectTestCase(test.TestCase):
missing = set() missing = set()
for contributor in contributors: for contributor in contributors:
if contributor == 'nova-core':
continue
if not contributor in authors_file: if not contributor in authors_file:
missing.add(contributor) missing.add(contributor)

View File

@@ -117,6 +117,9 @@ class NetworkTestCase(test.TestCase):
utils.to_global_ipv6( utils.to_global_ipv6(
network_ref['cidr_v6'], network_ref['cidr_v6'],
instance_ref['mac_address'])) instance_ref['mac_address']))
self._deallocate_address(0, address)
db.instance_destroy(context.get_admin_context(),
instance_ref['id'])
def test_public_network_association(self): def test_public_network_association(self):
"""Makes sure that we can allocaate a public ip""" """Makes sure that we can allocaate a public ip"""

View File

@@ -150,6 +150,7 @@ class SimpleDriverTestCase(test.TestCase):
def tearDown(self): def tearDown(self):
self.manager.delete_user(self.user) self.manager.delete_user(self.user)
self.manager.delete_project(self.project) self.manager.delete_project(self.project)
super(SimpleDriverTestCase, self).tearDown()
def _create_instance(self, **kwargs): def _create_instance(self, **kwargs):
"""Create a test instance""" """Create a test instance"""
@@ -176,18 +177,8 @@ class SimpleDriverTestCase(test.TestCase):
def test_doesnt_report_disabled_hosts_as_up(self): def test_doesnt_report_disabled_hosts_as_up(self):
"""Ensures driver doesn't find hosts before they are enabled""" """Ensures driver doesn't find hosts before they are enabled"""
# NOTE(vish): constructing service without create method compute1 = self.start_service('compute', host='host1')
# because we are going to use it without queue compute2 = self.start_service('compute', host='host2')
compute1 = service.Service('host1',
'nova-compute',
'compute',
FLAGS.compute_manager)
compute1.start()
compute2 = service.Service('host2',
'nova-compute',
'compute',
FLAGS.compute_manager)
compute2.start()
s1 = db.service_get_by_args(self.context, 'host1', 'nova-compute') s1 = db.service_get_by_args(self.context, 'host1', 'nova-compute')
s2 = db.service_get_by_args(self.context, 'host2', 'nova-compute') s2 = db.service_get_by_args(self.context, 'host2', 'nova-compute')
db.service_update(self.context, s1['id'], {'disabled': True}) db.service_update(self.context, s1['id'], {'disabled': True})
@@ -199,18 +190,8 @@ class SimpleDriverTestCase(test.TestCase):
def test_reports_enabled_hosts_as_up(self): def test_reports_enabled_hosts_as_up(self):
"""Ensures driver can find the hosts that are up""" """Ensures driver can find the hosts that are up"""
# NOTE(vish): constructing service without create method compute1 = self.start_service('compute', host='host1')
# because we are going to use it without queue compute2 = self.start_service('compute', host='host2')
compute1 = service.Service('host1',
'nova-compute',
'compute',
FLAGS.compute_manager)
compute1.start()
compute2 = service.Service('host2',
'nova-compute',
'compute',
FLAGS.compute_manager)
compute2.start()
hosts = self.scheduler.driver.hosts_up(self.context, 'compute') hosts = self.scheduler.driver.hosts_up(self.context, 'compute')
self.assertEqual(2, len(hosts)) self.assertEqual(2, len(hosts))
compute1.kill() compute1.kill()
@@ -218,16 +199,8 @@ class SimpleDriverTestCase(test.TestCase):
def test_least_busy_host_gets_instance(self): def test_least_busy_host_gets_instance(self):
"""Ensures the host with less cores gets the next one""" """Ensures the host with less cores gets the next one"""
compute1 = service.Service('host1', compute1 = self.start_service('compute', host='host1')
'nova-compute', compute2 = self.start_service('compute', host='host2')
'compute',
FLAGS.compute_manager)
compute1.start()
compute2 = service.Service('host2',
'nova-compute',
'compute',
FLAGS.compute_manager)
compute2.start()
instance_id1 = self._create_instance() instance_id1 = self._create_instance()
compute1.run_instance(self.context, instance_id1) compute1.run_instance(self.context, instance_id1)
instance_id2 = self._create_instance() instance_id2 = self._create_instance()
@@ -241,16 +214,8 @@ class SimpleDriverTestCase(test.TestCase):
def test_specific_host_gets_instance(self): def test_specific_host_gets_instance(self):
"""Ensures if you set availability_zone it launches on that zone""" """Ensures if you set availability_zone it launches on that zone"""
compute1 = service.Service('host1', compute1 = self.start_service('compute', host='host1')
'nova-compute', compute2 = self.start_service('compute', host='host2')
'compute',
FLAGS.compute_manager)
compute1.start()
compute2 = service.Service('host2',
'nova-compute',
'compute',
FLAGS.compute_manager)
compute2.start()
instance_id1 = self._create_instance() instance_id1 = self._create_instance()
compute1.run_instance(self.context, instance_id1) compute1.run_instance(self.context, instance_id1)
instance_id2 = self._create_instance(availability_zone='nova:host1') instance_id2 = self._create_instance(availability_zone='nova:host1')
@@ -263,11 +228,7 @@ class SimpleDriverTestCase(test.TestCase):
compute2.kill() compute2.kill()
def test_wont_sechedule_if_specified_host_is_down(self): def test_wont_sechedule_if_specified_host_is_down(self):
compute1 = service.Service('host1', compute1 = self.start_service('compute', host='host1')
'nova-compute',
'compute',
FLAGS.compute_manager)
compute1.start()
s1 = db.service_get_by_args(self.context, 'host1', 'nova-compute') s1 = db.service_get_by_args(self.context, 'host1', 'nova-compute')
now = datetime.datetime.utcnow() now = datetime.datetime.utcnow()
delta = datetime.timedelta(seconds=FLAGS.service_down_time * 2) delta = datetime.timedelta(seconds=FLAGS.service_down_time * 2)
@@ -282,11 +243,7 @@ class SimpleDriverTestCase(test.TestCase):
compute1.kill() compute1.kill()
def test_will_schedule_on_disabled_host_if_specified(self): def test_will_schedule_on_disabled_host_if_specified(self):
compute1 = service.Service('host1', compute1 = self.start_service('compute', host='host1')
'nova-compute',
'compute',
FLAGS.compute_manager)
compute1.start()
s1 = db.service_get_by_args(self.context, 'host1', 'nova-compute') s1 = db.service_get_by_args(self.context, 'host1', 'nova-compute')
db.service_update(self.context, s1['id'], {'disabled': True}) db.service_update(self.context, s1['id'], {'disabled': True})
instance_id2 = self._create_instance(availability_zone='nova:host1') instance_id2 = self._create_instance(availability_zone='nova:host1')
@@ -298,16 +255,8 @@ class SimpleDriverTestCase(test.TestCase):
def test_too_many_cores(self): def test_too_many_cores(self):
"""Ensures we don't go over max cores""" """Ensures we don't go over max cores"""
compute1 = service.Service('host1', compute1 = self.start_service('compute', host='host1')
'nova-compute', compute2 = self.start_service('compute', host='host2')
'compute',
FLAGS.compute_manager)
compute1.start()
compute2 = service.Service('host2',
'nova-compute',
'compute',
FLAGS.compute_manager)
compute2.start()
instance_ids1 = [] instance_ids1 = []
instance_ids2 = [] instance_ids2 = []
for index in xrange(FLAGS.max_cores): for index in xrange(FLAGS.max_cores):
@@ -322,6 +271,7 @@ class SimpleDriverTestCase(test.TestCase):
self.scheduler.driver.schedule_run_instance, self.scheduler.driver.schedule_run_instance,
self.context, self.context,
instance_id) instance_id)
db.instance_destroy(self.context, instance_id)
for instance_id in instance_ids1: for instance_id in instance_ids1:
compute1.terminate_instance(self.context, instance_id) compute1.terminate_instance(self.context, instance_id)
for instance_id in instance_ids2: for instance_id in instance_ids2:
@@ -331,16 +281,8 @@ class SimpleDriverTestCase(test.TestCase):
def test_least_busy_host_gets_volume(self): def test_least_busy_host_gets_volume(self):
"""Ensures the host with less gigabytes gets the next one""" """Ensures the host with less gigabytes gets the next one"""
volume1 = service.Service('host1', volume1 = self.start_service('volume', host='host1')
'nova-volume', volume2 = self.start_service('volume', host='host2')
'volume',
FLAGS.volume_manager)
volume1.start()
volume2 = service.Service('host2',
'nova-volume',
'volume',
FLAGS.volume_manager)
volume2.start()
volume_id1 = self._create_volume() volume_id1 = self._create_volume()
volume1.create_volume(self.context, volume_id1) volume1.create_volume(self.context, volume_id1)
volume_id2 = self._create_volume() volume_id2 = self._create_volume()
@@ -354,16 +296,8 @@ class SimpleDriverTestCase(test.TestCase):
def test_too_many_gigabytes(self): def test_too_many_gigabytes(self):
"""Ensures we don't go over max gigabytes""" """Ensures we don't go over max gigabytes"""
volume1 = service.Service('host1', volume1 = self.start_service('volume', host='host1')
'nova-volume', volume2 = self.start_service('volume', host='host2')
'volume',
FLAGS.volume_manager)
volume1.start()
volume2 = service.Service('host2',
'nova-volume',
'volume',
FLAGS.volume_manager)
volume2.start()
volume_ids1 = [] volume_ids1 = []
volume_ids2 = [] volume_ids2 = []
for index in xrange(FLAGS.max_gigabytes): for index in xrange(FLAGS.max_gigabytes):

View File

@@ -204,6 +204,7 @@ class LibvirtConnTestCase(test.TestCase):
conn = libvirt_conn.LibvirtConnection(True) conn = libvirt_conn.LibvirtConnection(True)
uri = conn.get_uri() uri = conn.get_uri()
self.assertEquals(uri, testuri) self.assertEquals(uri, testuri)
db.instance_destroy(user_context, instance_ref['id'])
def tearDown(self): def tearDown(self):
super(LibvirtConnTestCase, self).tearDown() super(LibvirtConnTestCase, self).tearDown()
@@ -365,6 +366,7 @@ class IptablesFirewallTestCase(test.TestCase):
'--dports 80:81 -j ACCEPT' % security_group_chain \ '--dports 80:81 -j ACCEPT' % security_group_chain \
in self.out_rules, in self.out_rules,
"TCP port 80/81 acceptance rule wasn't added") "TCP port 80/81 acceptance rule wasn't added")
db.instance_destroy(admin_ctxt, instance_ref['id'])
class NWFilterTestCase(test.TestCase): class NWFilterTestCase(test.TestCase):
@@ -514,3 +516,4 @@ class NWFilterTestCase(test.TestCase):
self.fw.apply_instance_filter(instance) self.fw.apply_instance_filter(instance)
_ensure_all_called() _ensure_all_called()
self.teardown_security_group() self.teardown_security_group()
db.instance_destroy(admin_ctxt, instance_ref['id'])

View File

@@ -2,6 +2,7 @@
# Copyright 2010 United States Government as represented by the # Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration. # Administrator of the National Aeronautics and Space Administration.
# Copyright 2011 Justin Santa Barbara
# All Rights Reserved. # All Rights Reserved.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -31,6 +32,7 @@ import string
import struct import struct
import sys import sys
import time import time
import types
from xml.sax import saxutils from xml.sax import saxutils
import re import re
import netaddr import netaddr
@@ -499,3 +501,52 @@ def ensure_b64_encoding(val):
return val return val
except TypeError: except TypeError:
return base64.b64encode(val) return base64.b64encode(val)
def get_from_path(items, path):
""" Returns a list of items matching the specified path. Takes an
XPath-like expression e.g. prop1/prop2/prop3, and for each item in items,
looks up items[prop1][prop2][prop3]. Like XPath, if any of the
intermediate results are lists it will treat each list item individually.
A 'None' in items or any child expressions will be ignored, this function
will not throw because of None (anywhere) in items. The returned list
will contain no None values."""
if path is None:
raise exception.Error("Invalid mini_xpath")
(first_token, sep, remainder) = path.partition("/")
if first_token == "":
raise exception.Error("Invalid mini_xpath")
results = []
if items is None:
return results
if not isinstance(items, types.ListType):
# Wrap single objects in a list
items = [items]
for item in items:
if item is None:
continue
get_method = getattr(item, "get", None)
if get_method is None:
continue
child = get_method(first_token)
if child is None:
continue
if isinstance(child, types.ListType):
# Flatten intermediate lists
for x in child:
results.append(x)
else:
results.append(child)
if not sep:
# No more tokens
return results
else:
return get_from_path(results, remainder)

View File

@@ -514,10 +514,3 @@ def load_paste_app(filename, appname):
except LookupError: except LookupError:
pass pass
return app return app
def paste_config_to_flags(config, mixins):
for k, v in mixins.iteritems():
value = config.get(k, v)
converted_value = FLAGS[k].parser.Parse(value)
setattr(FLAGS, k, converted_value)

2130
po/ast.po Normal file

File diff suppressed because it is too large Load Diff

2137
po/cs.po Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,21 +1,21 @@
# Translations template for nova. # Danish translation for nova
# Copyright (C) 2011 ORGANIZATION # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
# This file is distributed under the same license as the nova project. # This file is distributed under the same license as the nova package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011. # FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
# #
#, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: nova 2011.1\n" "Project-Id-Version: nova\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2011-01-10 11:25-0800\n" "POT-Creation-Date: 2011-01-10 11:25-0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: 2011-01-15 21:46+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: Soren Hansen <soren@linux2go.dk>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: Danish <da@li.org>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.4\n" "X-Launchpad-Export-Date: 2011-02-05 05:36+0000\n"
"X-Generator: Launchpad (build 12177)\n"
#: nova/crypto.py:46 #: nova/crypto.py:46
msgid "Filename of root CA" msgid "Filename of root CA"
@@ -23,7 +23,7 @@ msgstr ""
#: nova/crypto.py:49 #: nova/crypto.py:49
msgid "Filename of private key" msgid "Filename of private key"
msgstr "" msgstr "Filnavn for privatnøgle"
#: nova/crypto.py:51 #: nova/crypto.py:51
msgid "Filename of root Certificate Revokation List" msgid "Filename of root Certificate Revokation List"
@@ -283,8 +283,8 @@ msgstr ""
#: nova/api/ec2/__init__.py:142 #: nova/api/ec2/__init__.py:142
#, python-format #, python-format
msgid "" msgid ""
"Access key %s has had %d failed authentications and will be locked out " "Access key %s has had %d failed authentications and will be locked out for "
"for %d minutes." "%d minutes."
msgstr "" msgstr ""
#: nova/api/ec2/__init__.py:179 nova/objectstore/handler.py:140 #: nova/api/ec2/__init__.py:179 nova/objectstore/handler.py:140
@@ -805,7 +805,8 @@ msgstr ""
#: nova/compute/api.py:94 #: nova/compute/api.py:94
#, python-format #, python-format
msgid "Instance quota exceeded. You can only run %s more instances of this type." msgid ""
"Instance quota exceeded. You can only run %s more instances of this type."
msgstr "" msgstr ""
#: nova/compute/api.py:109 #: nova/compute/api.py:109
@@ -957,7 +958,8 @@ msgstr ""
#: nova/compute/manager.py:289 #: nova/compute/manager.py:289
#, python-format #, python-format
msgid "trying to snapshot a non-running instance: %s (state: %s excepted: %s)" msgid ""
"trying to snapshot a non-running instance: %s (state: %s excepted: %s)"
msgstr "" msgstr ""
#: nova/compute/manager.py:301 #: nova/compute/manager.py:301
@@ -1697,9 +1699,8 @@ msgstr ""
#: nova/virt/xenapi_conn.py:113 #: nova/virt/xenapi_conn.py:113
msgid "" msgid ""
"Must specify xenapi_connection_url, xenapi_connection_username " "Must specify xenapi_connection_url, xenapi_connection_username (optionally), "
"(optionally), and xenapi_connection_password to use " "and xenapi_connection_password to use connection_type=xenapi"
"connection_type=xenapi"
msgstr "" msgstr ""
#: nova/virt/xenapi_conn.py:263 #: nova/virt/xenapi_conn.py:263
@@ -1826,7 +1827,7 @@ msgstr ""
#: nova/virt/xenapi/vm_utils.py:290 #: nova/virt/xenapi/vm_utils.py:290
#, python-format #, python-format
msgid "PV Kernel in VDI:%s" msgid "PV Kernel in VDI:%d"
msgstr "" msgstr ""
#: nova/virt/xenapi/vm_utils.py:318 #: nova/virt/xenapi/vm_utils.py:318
@@ -2126,5 +2127,4 @@ msgstr ""
#: nova/volume/manager.py:129 #: nova/volume/manager.py:129
#, python-format #, python-format
msgid "volume %s: deleted successfully" msgid "volume %s: deleted successfully"
msgstr "" msgstr "bind %s: slettet"

2137
po/de.po Normal file

File diff suppressed because it is too large Load Diff

2177
po/es.po Normal file

File diff suppressed because it is too large Load Diff

2141
po/it.po Normal file

File diff suppressed because it is too large Load Diff

2143
po/ja.po Normal file

File diff suppressed because it is too large Load Diff

2847
po/nova.pot Normal file

File diff suppressed because it is too large Load Diff

2148
po/pt_BR.po Normal file

File diff suppressed because it is too large Load Diff

2138
po/ru.po Normal file

File diff suppressed because it is too large Load Diff

2135
po/uk.po Normal file

File diff suppressed because it is too large Load Diff

2135
po/zh_CN.po Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -38,7 +38,22 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""Unittest runner for Nova.
To run all tests
python run_tests.py
To run a single test:
python run_tests.py test_compute:ComputeTestCase.test_run_terminate
To run a single test module:
python run_tests.py test_compute
or
python run_tests.py api.test_wsgi
"""
import gettext import gettext
import os import os
@@ -263,6 +278,15 @@ if __name__ == '__main__':
testdb = os.path.join(testdir, "tests.sqlite") testdb = os.path.join(testdir, "tests.sqlite")
if os.path.exists(testdb): if os.path.exists(testdb):
os.unlink(testdb) os.unlink(testdb)
# If any argument looks like a test name but doesn't have "nova.tests" in
# front of it, automatically add that so we don't have to type as much
argv = []
for x in sys.argv:
if x.startswith('test_'):
argv.append('nova.tests.%s' % x)
else:
argv.append(x)
c = config.Config(stream=sys.stdout, c = config.Config(stream=sys.stdout,
env=os.environ, env=os.environ,
verbosity=3, verbosity=3,
@@ -272,4 +296,4 @@ if __name__ == '__main__':
runner = NovaTestRunner(stream=c.stream, runner = NovaTestRunner(stream=c.stream,
verbosity=c.verbosity, verbosity=c.verbosity,
config=c) config=c)
sys.exit(not core.run(config=c, testRunner=runner)) sys.exit(not core.run(config=c, testRunner=runner, argv=argv))

View File

@@ -40,6 +40,17 @@ done
function run_tests { function run_tests {
# Just run the test suites in current environment # Just run the test suites in current environment
${wrapper} $NOSETESTS ${wrapper} $NOSETESTS
# If we get some short import error right away, print the error log directly
RESULT=$?
if [ "$RESULT" -ne "0" ];
then
ERRSIZE=`wc -l run_tests.err.log | awk '{print \$1}'`
if [ "$ERRSIZE" -lt "40" ];
then
cat run_tests.err.log
fi
fi
return $RESULT
} }
NOSETESTS="python run_tests.py $noseargs" NOSETESTS="python run_tests.py $noseargs"
@@ -72,7 +83,9 @@ fi
if [ -z "$noseargs" ]; if [ -z "$noseargs" ];
then then
run_tests && pep8 --repeat --show-pep8 --show-source --exclude=vcsversion.py bin/* nova setup.py || exit 1 srcfiles=`find bin -type f ! -name "nova.conf*"`
srcfiles+=" nova setup.py"
run_tests && pep8 --repeat --show-pep8 --show-source --exclude=vcsversion.py ${srcfiles} || exit 1
else else
run_tests run_tests
fi fi

View File

@@ -18,10 +18,21 @@
import os import os
import subprocess import subprocess
import sys
from setuptools import setup, find_packages from setuptools import find_packages
from setuptools.command.sdist import sdist from setuptools.command.sdist import sdist
try:
import DistUtilsExtra.auto
except ImportError:
print >> sys.stderr, 'To build nova you need '\
'https://launchpad.net/python-distutils-extra'
sys.exit(1)
assert DistUtilsExtra.auto.__version__ >= '2.18',\
'needs DistUtilsExtra.auto >= 2.18'
from nova.utils import parse_mailmap, str_dict_replace from nova.utils import parse_mailmap, str_dict_replace
from nova import version from nova import version
@@ -75,7 +86,7 @@ try:
except: except:
pass pass
setup(name='nova', DistUtilsExtra.auto.setup(name='nova',
version=version.canonical_version_string(), version=version.canonical_version_string(),
description='cloud computing fabric controller', description='cloud computing fabric controller',
author='OpenStack', author='OpenStack',
@@ -87,7 +98,6 @@ setup(name='nova',
test_suite='nose.collector', test_suite='nose.collector',
scripts=['bin/nova-ajax-console-proxy', scripts=['bin/nova-ajax-console-proxy',
'bin/nova-api', 'bin/nova-api',
'bin/nova-combined',
'bin/nova-compute', 'bin/nova-compute',
'bin/nova-console', 'bin/nova-console',
'bin/nova-dhcpbridge', 'bin/nova-dhcpbridge',