Merged trunk. Fixed new references to UserManager

This commit is contained in:
Vishvananda Ishaya 2010-07-19 20:27:44 -05:00
commit 8ef16679e0
20 changed files with 266 additions and 265 deletions

1
.bzrignore Normal file
View File

@ -0,0 +1 @@
run_tests.err.log

View File

@ -18,23 +18,27 @@
# under the License.
"""
dhcpleasor.py
nova-dhcpbridge
Handle lease database updates from DHCP servers.
"""
import sys
import os
import logging
import os
import sys
#TODO(joshua): there is concern that the user dnsmasq runs under will not
# have nova in the path. This should be verified and if it is
# not true the ugly line below can be removed
sys.path.append(os.path.abspath(os.path.join(__file__, "../../")))
logging.debug(sys.path)
import getopt
from os import environ
from nova import rpc
from nova import flags
from nova import rpc
from nova import utils
from nova.compute import linux_net
from nova.compute import network
FLAGS = flags.FLAGS
@ -63,11 +67,12 @@ def init_leases(interface):
return res
def main(argv=None):
if argv is None:
argv = sys.argv
interface = environ.get('DNSMASQ_INTERFACE', 'br0')
if int(environ.get('TESTING', '0')):
def main():
flagfile = os.environ.get('FLAGFILE', FLAGS.dhcpbridge_flagfile)
utils.default_flagfile(flagfile)
argv = FLAGS(sys.argv)
interface = os.environ.get('DNSMASQ_INTERFACE', 'br0')
if int(os.environ.get('TESTING', '0')):
FLAGS.fake_rabbit = True
FLAGS.redis_db = 8
FLAGS.network_size = 32

View File

@ -18,33 +18,32 @@
# under the License.
"""
Tornado daemon for nova objectstore. Supports S3 API.
Twisted daemon for nova objectstore. Supports S3 API.
"""
import logging
from tornado import httpserver
from tornado import ioloop
from nova import flags
from nova import server
from nova import utils
from nova.auth import manager
from nova import twistd
from nova.objectstore import handler
FLAGS = flags.FLAGS
def main(argv):
def main():
# FIXME: if this log statement isn't here, no logging
# appears from other files and app won't start daemonized
logging.debug('Started HTTP server on %s' % (FLAGS.s3_internal_port))
app = handler.Application(manager.AuthManager())
server = httpserver.HTTPServer(app)
server.listen(FLAGS.s3_internal_port)
ioloop.IOLoop.instance().start()
logging.debug('Started HTTP server on %s' % (FLAGS.s3_port))
app = handler.get_application()
print app
return app
# NOTE(soren): Stolen from nova-compute
if __name__ == '__main__':
twistd.serve(__file__)
if __name__ == '__builtin__':
utils.default_flagfile()
server.serve('nova-objectstore', main)
application = main()

2
debian/control vendored
View File

@ -91,7 +91,7 @@ Description: Nova Cloud Computing - API frontend
Package: nova-objectstore
Architecture: all
Depends: nova-common (= ${binary:Version}), nginx, ${python:Depends}, ${misc:Depends}
Depends: nova-common (= ${binary:Version}), ${python:Depends}, ${misc:Depends}
Description: Nova Cloud Computing - object store
Nova is a cloud computing fabric controller (the main part of an IaaS
system) built to match the popular AWS EC2 and S3 APIs. It is written in

View File

@ -1,5 +1,6 @@
--daemonize=1
--ca_path=/var/lib/nova/CA
--keys_path=/var/lib/nova/keys
--networks_path=/var/lib/nova/networks
--dhcpbridge_flagfile=/etc/nova/nova-dhcpbridge.conf
--fake_users=1
--datastore_path=/var/lib/nova/keeper

View File

@ -1,2 +1,3 @@
bin/nova-api usr/bin
debian/nova-api.conf etc/nova
debian/nova-dhcpbridge.conf etc/nova

View File

@ -1,8 +1,6 @@
--ca_path=/var/lib/nova/CA
--keys_path=/var/lib/nova/keys
--datastore_path=/var/lib/nova/keeper
--instances_path=/var/lib/nova/instances
--networks_path=/var/lib/nova/networks
--simple_network_template=/usr/share/nova/interfaces.template
--libvirt_xml_template=/usr/share/nova/libvirt.xml.template
--vpn_client_template=/usr/share/nova/client.ovpn.template

2
debian/nova-dhcp.conf vendored Normal file
View File

@ -0,0 +1,2 @@
--networks_path=/var/lib/nova/networks
--fake_users=1

View File

@ -1,7 +1,6 @@
--daemonize=1
--ca_path=/var/lib/nova/CA
--keys_path=/var/lib/nova/keys
--datastore_path=/var/lib/nova/keeper
--fake_users=1
--images_path=/var/lib/nova/images
--buckets_path=/var/lib/nova/buckets

View File

@ -1,3 +1,2 @@
bin/nova-objectstore usr/bin
debian/nova-objectstore.conf etc/nova
debian/nova-objectstore.nginx.conf etc/nginx/sites-available

View File

@ -1 +0,0 @@
/etc/nginx/sites-available/nova-objectstore.nginx.conf /etc/nginx/sites-enabled/nova-objectstore.nginx.conf

View File

@ -1,17 +0,0 @@
server {
listen 3333 default;
server_name localhost;
client_max_body_size 10m;
access_log /var/log/nginx/localhost.access.log;
location ~ /_images/.+ {
root /var/lib/nova/images;
rewrite ^/_images/(.*)$ /$1 break;
}
location / {
proxy_pass http://localhost:3334/;
}
}

View File

@ -1,7 +1,6 @@
--daemonize=1
--ca_path=/var/lib/nova/CA
--keys_path=/var/lib/nova/keys
--datastore_path=/var/lib/nova/keeper
--fake_users=1
--images_path=/var/lib/nova/images
--buckets_path=/var/lib/nova/buckets

View File

@ -28,18 +28,22 @@ from nova import utils
from nova import flags
FLAGS=flags.FLAGS
def execute(cmd):
flags.DEFINE_string('dhcpbridge_flagfile',
'/etc/nova-dhcpbridge.conf',
'location of flagfile for dhcpbridge')
def execute(cmd, addl_env=None):
if FLAGS.fake_network:
logging.debug("FAKE NET: %s" % cmd)
return "fake", 0
else:
return nova.utils.execute(cmd)
return utils.execute(cmd, addl_env=addl_env)
def runthis(desc, cmd):
if FLAGS.fake_network:
return execute(cmd)
else:
return nova.utils.runthis(desc,cmd)
return utils.runthis(desc,cmd)
def Popen(cmd):
if FLAGS.fake_network:
@ -61,7 +65,7 @@ def remove_rule(cmd):
def bind_public_ip(ip, interface):
runthis("Binding IP to interface: %s", "sudo ip addr add %s dev %s" % (ip, interface))
def unbind_public_ip(ip, interface):
runthis("Binding IP to interface: %s", "sudo ip addr del %s dev %s" % (ip, interface))
@ -99,7 +103,7 @@ def dnsmasq_cmd(net):
' --except-interface=lo',
' --dhcp-range=%s,static,600s' % (net.dhcp_range_start),
' --dhcp-hostsfile=%s' % dhcp_file(net['vlan'], 'conf'),
' --dhcp-script=%s' % bin_file('dhcpleasor.py'),
' --dhcp-script=%s' % bin_file('nova-dhcpbridge'),
' --leasefile-ro']
return ''.join(cmd)
@ -139,7 +143,9 @@ def start_dnsmasq(network):
if os.path.exists(lease_file):
os.unlink(lease_file)
Popen(dnsmasq_cmd(network).split(" "))
# FLAGFILE in env
env = {'FLAGFILE' : FLAGS.dhcpbridge_flagfile}
execute(dnsmasq_cmd(network), addl_env=env)
def stop_dnsmasq(network):
""" stops the dnsmasq instance for a given network """

View File

@ -251,7 +251,7 @@ class BaseNetwork(datastore.BasicModel):
raise compute_exception.NoMoreAddresses("Project %s with network %s" %
(project_id, str(self.network)))
def lease_ip(self, ip_str):
def lease_ip(self, ip_str):
logging.debug("Leasing allocated IP %s" % (ip_str))
def release_ip(self, ip_str):
@ -566,10 +566,10 @@ def allocate_ip(user_id, project_id, mac):
def deallocate_ip(address):
return get_network_by_address(address).deallocate_ip(address)
def release_ip(address):
return get_network_by_address(address).release_ip(address)
def lease_ip(address):
return get_network_by_address(address).lease_ip(address)

View File

@ -37,7 +37,6 @@ DEFINE_bool = DEFINE_bool
# http://code.google.com/p/python-gflags/source/browse/trunk/gflags.py#39
DEFINE_integer('s3_port', 3333, 's3 port')
DEFINE_integer('s3_internal_port', 3334, 's3 port')
DEFINE_string('s3_host', '127.0.0.1', 's3 host')
#DEFINE_string('cloud_topic', 'cloud', 'the topic clouds listen on')
DEFINE_string('compute_topic', 'compute', 'the topic compute nodes listen on')

View File

@ -1,10 +1,11 @@
# 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.
#
# Copyright 2009 Facebook
# Copyright 2010 OpenStack LLC.
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Copyright 2009 Facebook
#
# 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
@ -37,15 +38,21 @@ S3 client with this module::
"""
import datetime
import os
import json
import logging
import json
import multiprocessing
from tornado import escape, web
import os
from tornado import escape
import urllib
from twisted.application import internet, service
from twisted.web.resource import Resource
from twisted.web import server, static
from nova import exception
from nova import flags
from nova.auth import manager
from nova.endpoint import api
from nova.objectstore import bucket
from nova.objectstore import image
@ -53,241 +60,217 @@ from nova.objectstore import image
FLAGS = flags.FLAGS
def render_xml(request, value):
assert isinstance(value, dict) and len(value) == 1
request.setHeader("Content-Type", "application/xml; charset=UTF-8")
def catch_nova_exceptions(target):
# FIXME: find a way to wrap all handlers in the web.Application.__init__ ?
def wrapper(*args, **kwargs):
try:
return target(*args, **kwargs)
except exception.NotFound:
raise web.HTTPError(404)
except exception.NotAuthorized:
raise web.HTTPError(403)
name = value.keys()[0]
request.write('<?xml version="1.0" encoding="UTF-8"?>\n')
request.write('<' + escape.utf8(name) +
' xmlns="http://doc.s3.amazonaws.com/2006-03-01">')
_render_parts(value.values()[0], request.write)
request.write('</' + escape.utf8(name) + '>')
request.finish()
return wrapper
def finish(request, content=None):
if content:
request.write(content)
request.finish()
def _render_parts(value, write_cb):
if isinstance(value, basestring):
write_cb(escape.xhtml_escape(value))
elif isinstance(value, int) or isinstance(value, long):
write_cb(str(value))
elif isinstance(value, datetime.datetime):
write_cb(value.strftime("%Y-%m-%dT%H:%M:%S.000Z"))
elif isinstance(value, dict):
for name, subvalue in value.iteritems():
if not isinstance(subvalue, list):
subvalue = [subvalue]
for subsubvalue in subvalue:
write_cb('<' + escape.utf8(name) + '>')
_render_parts(subsubvalue, write_cb)
write_cb('</' + escape.utf8(name) + '>')
else:
raise Exception("Unknown S3 value type %r", value)
class Application(web.Application):
def get_argument(request, key, default_value):
if key in request.args:
return request.args[key][0]
return default_value
def get_context(request):
try:
# Authorization Header format: 'AWS <access>:<secret>'
access, sep, secret = request.getHeader('Authorization').split(' ')[1].rpartition(':')
(user, project) = manager.AuthManager().authenticate(access,
secret,
{},
request.method,
request.host,
request.uri,
False)
# FIXME: check signature here!
return api.APIRequestContext(None, user, project)
except exception.Error, ex:
logging.debug("Authentication Failure: %s" % ex)
raise exception.NotAuthorized
class S3(Resource):
"""Implementation of an S3-like storage server based on local files."""
def __init__(self, user_manager):
web.Application.__init__(self, [
(r"/", RootHandler),
(r"/_images/(.+)", ImageDownloadHandler),
(r"/_images/", ImageHandler),
(r"/([^/]+)/(.+)", ObjectHandler),
(r"/([^/]+)/", BucketHandler),
])
self.buckets_path = os.path.abspath(FLAGS.buckets_path)
self.images_path = os.path.abspath(FLAGS.images_path)
def getChild(self, name, request):
request.context = get_context(request)
if not os.path.exists(self.buckets_path):
raise Exception("buckets_path does not exist")
if not os.path.exists(self.images_path):
raise Exception("images_path does not exist")
self.user_manager = user_manager
class BaseRequestHandler(web.RequestHandler):
SUPPORTED_METHODS = ("PUT", "GET", "DELETE", "HEAD")
@property
def context(self):
if not hasattr(self, '_context'):
try:
# Authorization Header format: 'AWS <access>:<secret>'
access, sep, secret = self.request.headers['Authorization'].split(' ')[1].rpartition(':')
(user, project) = self.application.user_manager.authenticate(access, secret, {}, self.request.method, self.request.host, self.request.path, False)
# FIXME: check signature here!
self._context = api.APIRequestContext(self, user, project)
except exception.Error, ex:
logging.debug("Authentication Failure: %s" % ex)
raise web.HTTPError(403)
return self._context
def render_xml(self, value):
assert isinstance(value, dict) and len(value) == 1
self.set_header("Content-Type", "application/xml; charset=UTF-8")
name = value.keys()[0]
parts = []
parts.append('<' + escape.utf8(name) +
' xmlns="http://doc.s3.amazonaws.com/2006-03-01">')
self._render_parts(value.values()[0], parts)
parts.append('</' + escape.utf8(name) + '>')
self.finish('<?xml version="1.0" encoding="UTF-8"?>\n' +
''.join(parts))
def _render_parts(self, value, parts=[]):
if isinstance(value, basestring):
parts.append(escape.xhtml_escape(value))
elif isinstance(value, int) or isinstance(value, long):
parts.append(str(value))
elif isinstance(value, datetime.datetime):
parts.append(value.strftime("%Y-%m-%dT%H:%M:%S.000Z"))
elif isinstance(value, dict):
for name, subvalue in value.iteritems():
if not isinstance(subvalue, list):
subvalue = [subvalue]
for subsubvalue in subvalue:
parts.append('<' + escape.utf8(name) + '>')
self._render_parts(subsubvalue, parts)
parts.append('</' + escape.utf8(name) + '>')
if name == '':
return self
elif name == '_images':
return ImageResource()
else:
raise Exception("Unknown S3 value type %r", value)
return BucketResource(name)
def head(self, *args, **kwargs):
return self.get(*args, **kwargs)
def render_GET(self, request):
buckets = [b for b in bucket.Bucket.all() if b.is_authorized(request.context)]
class RootHandler(BaseRequestHandler):
def get(self):
buckets = [b for b in bucket.Bucket.all() if b.is_authorized(self.context)]
self.render_xml({"ListAllMyBucketsResult": {
render_xml(request, {"ListAllMyBucketsResult": {
"Buckets": {"Bucket": [b.metadata for b in buckets]},
}})
return server.NOT_DONE_YET
class BucketResource(Resource):
def __init__(self, name):
Resource.__init__(self)
self.name = name
class BucketHandler(BaseRequestHandler):
@catch_nova_exceptions
def get(self, bucket_name):
logging.debug("List keys for bucket %s" % (bucket_name))
def getChild(self, name, request):
if name == '':
return self
else:
return ObjectResource(bucket.Bucket(self.name), name)
bucket_object = bucket.Bucket(bucket_name)
def render_GET(self, request):
logging.debug("List keys for bucket %s" % (self.name))
if not bucket_object.is_authorized(self.context):
raise web.HTTPError(403)
bucket_object = bucket.Bucket(self.name)
prefix = self.get_argument("prefix", u"")
marker = self.get_argument("marker", u"")
max_keys = int(self.get_argument("max-keys", 1000))
terse = int(self.get_argument("terse", 0))
if not bucket_object.is_authorized(request.context):
raise exception.NotAuthorized
prefix = get_argument(request, "prefix", u"")
marker = get_argument(request, "marker", u"")
max_keys = int(get_argument(request, "max-keys", 1000))
terse = int(get_argument(request, "terse", 0))
results = bucket_object.list_keys(prefix=prefix, marker=marker, max_keys=max_keys, terse=terse)
self.render_xml({"ListBucketResult": results})
render_xml(request, {"ListBucketResult": results})
return server.NOT_DONE_YET
@catch_nova_exceptions
def put(self, bucket_name):
logging.debug("Creating bucket %s" % (bucket_name))
bucket.Bucket.create(bucket_name, self.context)
self.finish()
def render_PUT(self, request):
logging.debug("Creating bucket %s" % (self.name))
try:
print 'user is %s' % request.context
except Exception, e:
logging.exception(e)
logging.debug("calling bucket.Bucket.create(%r, %r)" % (self.name, request.context))
bucket.Bucket.create(self.name, request.context)
return ''
@catch_nova_exceptions
def delete(self, bucket_name):
logging.debug("Deleting bucket %s" % (bucket_name))
bucket_object = bucket.Bucket(bucket_name)
def render_DELETE(self, request):
logging.debug("Deleting bucket %s" % (self.name))
bucket_object = bucket.Bucket(self.name)
if not bucket_object.is_authorized(self.context):
raise web.HTTPError(403)
if not bucket_object.is_authorized(request.context):
raise exception.NotAuthorized
bucket_object.delete()
self.set_status(204)
self.finish()
request.setResponseCode(204)
return ''
class ObjectHandler(BaseRequestHandler):
@catch_nova_exceptions
def get(self, bucket_name, object_name):
logging.debug("Getting object: %s / %s" % (bucket_name, object_name))
class ObjectResource(Resource):
def __init__(self, bucket, name):
Resource.__init__(self)
self.bucket = bucket
self.name = name
bucket_object = bucket.Bucket(bucket_name)
def render_GET(self, request):
logging.debug("Getting object: %s / %s" % (self.bucket.name, self.name))
if not bucket_object.is_authorized(self.context):
raise web.HTTPError(403)
if not self.bucket.is_authorized(request.context):
raise exception.NotAuthorized
obj = bucket_object[urllib.unquote(object_name)]
self.set_header("Content-Type", "application/unknown")
self.set_header("Last-Modified", datetime.datetime.utcfromtimestamp(obj.mtime))
self.set_header("Etag", '"' + obj.md5 + '"')
self.finish(obj.read())
obj = self.bucket[urllib.unquote(self.name)]
request.setHeader("Content-Type", "application/unknown")
request.setHeader("Last-Modified", datetime.datetime.utcfromtimestamp(obj.mtime))
request.setHeader("Etag", '"' + obj.md5 + '"')
return static.File(obj.path).render_GET(request)
@catch_nova_exceptions
def put(self, bucket_name, object_name):
logging.debug("Putting object: %s / %s" % (bucket_name, object_name))
bucket_object = bucket.Bucket(bucket_name)
def render_PUT(self, request):
logging.debug("Putting object: %s / %s" % (self.bucket.name, self.name))
if not bucket_object.is_authorized(self.context):
raise web.HTTPError(403)
if not self.bucket.is_authorized(request.context):
raise exception.NotAuthorized
key = urllib.unquote(object_name)
bucket_object[key] = self.request.body
self.set_header("Etag", '"' + bucket_object[key].md5 + '"')
self.finish()
key = urllib.unquote(self.name)
request.content.seek(0, 0)
self.bucket[key] = request.content.read()
request.setHeader("Etag", '"' + self.bucket[key].md5 + '"')
finish(request)
return server.NOT_DONE_YET
@catch_nova_exceptions
def delete(self, bucket_name, object_name):
logging.debug("Deleting object: %s / %s" % (bucket_name, object_name))
bucket_object = bucket.Bucket(bucket_name)
def render_DELETE(self, request):
logging.debug("Deleting object: %s / %s" % (self.bucket.name, self.name))
if not bucket_object.is_authorized(self.context):
raise web.HTTPError(403)
if not self.bucket.is_authorized(request.context):
raise exception.NotAuthorized
del bucket_object[urllib.unquote(object_name)]
self.set_status(204)
self.finish()
del self.bucket[urllib.unquote(self.name)]
request.setResponseCode(204)
return ''
class ImageResource(Resource):
isLeaf = True
class ImageDownloadHandler(BaseRequestHandler):
SUPPORTED_METHODS = ("GET", )
def getChild(self, name, request):
if name == '':
return self
else:
request.setHeader("Content-Type", "application/octet-stream")
img = image.Image(name)
return static.File(img.image_path)
@catch_nova_exceptions
def get(self, image_id):
""" send the decrypted image file
streaming content through python is slow and should only be used
in development mode. You should serve files via a web server
in production.
"""
self.set_header("Content-Type", "application/octet-stream")
READ_SIZE = 64*1024
img = image.Image(image_id)
with open(img.image_path, 'rb') as fp:
s = fp.read(READ_SIZE)
while s:
self.write(s)
s = fp.read(READ_SIZE)
self.finish()
class ImageHandler(BaseRequestHandler):
SUPPORTED_METHODS = ("POST", "PUT", "GET", "DELETE")
@catch_nova_exceptions
def get(self):
def render_GET(self, request):
""" returns a json listing of all images
that a user has permissions to see """
images = [i for i in image.Image.all() if i.is_authorized(self.context)]
self.finish(json.dumps([i.metadata for i in images]))
request.write(json.dumps([i.metadata for i in images]))
return server.NOT_DONE_YET
@catch_nova_exceptions
def put(self):
def render_PUT(self, request):
""" create a new registered image """
image_id = self.get_argument('image_id', u'')
image_location = self.get_argument('image_location', u'')
image_id = get_argument(request, 'image_id', u'')
image_location = get_argument(request, 'image_location', u'')
image_path = os.path.join(FLAGS.images_path, image_id)
if not image_path.startswith(FLAGS.images_path) or \
os.path.exists(image_path):
raise web.HTTPError(403)
raise exception.NotAuthorized
bucket_object = bucket.Bucket(image_location.split("/")[0])
manifest = image_location[len(image_location.split('/')[0])+1:]
if not bucket_object.is_authorized(self.context):
raise web.HTTPError(403)
if not bucket_object.is_authorized(request.context):
raise exception.NotAuthorized
p = multiprocessing.Process(target=image.Image.register_aws_image,
args=(image_id, image_location, self.context))
args=(image_id, image_location, request.context))
p.start()
self.finish()
return ''
@catch_nova_exceptions
def post(self):
def render_POST(self, request):
""" update image attributes: public/private """
image_id = self.get_argument('image_id', u'')
@ -295,22 +278,30 @@ class ImageHandler(BaseRequestHandler):
image_object = image.Image(image_id)
if not image_object.is_authorized(self.context):
raise web.HTTPError(403)
if not image.is_authorized(request.context):
raise exception.NotAuthorized
image_object.set_public(operation=='add')
self.finish()
return ''
@catch_nova_exceptions
def delete(self):
def render_DELETE(self, request):
""" delete a registered image """
image_id = self.get_argument("image_id", u"")
image_object = image.Image(image_id)
if not image_object.is_authorized(self.context):
raise web.HTTPError(403)
if not image.is_authorized(request.context):
raise exception.NotAuthorized
image_object.delete()
self.set_status(204)
request.setResponseCode(204)
return ''
def get_application():
root = S3()
factory = server.Site(root)
application = service.Application("objectstore")
objectStoreService = internet.TCPServer(FLAGS.s3_port, factory)
objectStoreService.setServiceParent(application)
return application

View File

@ -110,6 +110,7 @@ class TopicConsumer(Consumer):
self.queue = topic
self.routing_key = topic
self.exchange = FLAGS.control_exchange
self.durable = False
super(TopicConsumer, self).__init__(connection=connection)
@ -195,7 +196,10 @@ def call(topic, msg):
conn = Connection.instance()
d = defer.Deferred()
consumer = DirectConsumer(connection=conn, msg_id=msg_id)
consumer.register_callback(lambda data, message: d.callback(data))
def deferred_receive(data, message):
message.ack()
d.callback(data)
consumer.register_callback(deferred_receive)
injected = consumer.attach_to_tornado()
# clean up after the injected listened and return x
@ -233,7 +237,8 @@ def send_message(topic, message, wait=True):
exchange=msg_id,
auto_delete=True,
exchange_type="direct",
routing_key=msg_id)
routing_key=msg_id,
durable=False)
consumer.register_callback(generic_response)
publisher = messaging.Publisher(connection=Connection.instance(),

View File

@ -19,16 +19,15 @@
import IPy
import os
import logging
import unittest
from nova import flags
from nova import test
from nova import exception
from nova.compute.exception import NoMoreAddresses
from nova.compute import network
from nova.auth import manager
from nova import utils
from nova.auth import manager
from nova.compute import network
from nova.compute.exception import NoMoreAddresses
FLAGS = flags.FLAGS
class NetworkTestCase(test.TrialTestCase):
def setUp(self):
@ -180,14 +179,20 @@ def binpath(script):
class FakeDNSMasq(object):
def issue_ip(self, mac, ip, hostname, interface):
cmd = "%s add %s %s %s" % (binpath('dhcpleasor.py'), mac, ip, hostname)
env = {'DNSMASQ_INTERFACE': interface, 'TESTING' : '1'}
cmd = "%s add %s %s %s" % (binpath('nova-dhcpbridge'),
mac, ip, hostname)
env = {'DNSMASQ_INTERFACE': interface,
'TESTING' : '1',
'FLAGFILE' : FLAGS.dhcpbridge_flagfile}
(out, err) = utils.execute(cmd, addl_env=env)
logging.debug("ISSUE_IP: %s, %s " % (out, err))
def release_ip(self, mac, ip, hostname, interface):
cmd = "%s del %s %s %s" % (binpath('dhcpleasor.py'), mac, ip, hostname)
env = {'DNSMASQ_INTERFACE': interface, 'TESTING' : '1'}
cmd = "%s del %s %s %s" % (binpath('nova-dhcpbridge'),
mac, ip, hostname)
env = {'DNSMASQ_INTERFACE': interface,
'TESTING' : '1',
'FLAGFILE' : FLAGS.dhcpbridge_flagfile}
(out, err) = utils.execute(cmd, addl_env=env)
logging.debug("RELEASE_IP: %s, %s " % (out, err))

View File

@ -39,6 +39,7 @@ Due to our use of multiprocessing it we frequently get some ignorable
"""
import __main__
import os
import sys
@ -66,6 +67,9 @@ FLAGS = flags.FLAGS
flags.DEFINE_bool('flush_db', True,
'Flush the database before running fake tests')
flags.DEFINE_string('tests_stderr', 'run_tests.err.log',
'Path to where to pipe STDERR during test runs. Default = "run_tests.err.log"')
if __name__ == '__main__':
OptionsClass = twistd.WrapTwistedOptions(trial_script.Options)
config = OptionsClass()
@ -85,6 +89,11 @@ if __name__ == '__main__':
else:
from nova.tests.real_flags import *
# Establish redirect for STDERR
sys.stderr.flush()
err = open(FLAGS.tests_stderr, 'w+', 0)
os.dup2(err.fileno(), sys.stderr.fileno())
if len(argv) == 1 and len(config['tests']) == 0:
# If no tests were specified run the ones imported in this file
# NOTE(termie): "tests" is not a flag, just some Trial related stuff