summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorVishvananda Ishaya <vishvananda@gmail.com>2010-07-26 11:02:28 -0700
committerVishvananda Ishaya <vishvananda@gmail.com>2010-07-26 11:02:28 -0700
commitb1bc1e2edc9fdafabfc27b5ea313dbb934c374eb (patch)
treec51a31f5c90eba7935458c0052539799dc67937d /nova
parent3233f7a964564fba9ec88c277d566eebed50d12a (diff)
parent340f9fc8d63ec931485aba1dcfeccdc1cb3849fa (diff)
downloadnova-b1bc1e2edc9fdafabfc27b5ea313dbb934c374eb.tar.gz
nova-b1bc1e2edc9fdafabfc27b5ea313dbb934c374eb.tar.xz
nova-b1bc1e2edc9fdafabfc27b5ea313dbb934c374eb.zip
merged trunk
Diffstat (limited to 'nova')
-rwxr-xr-xnova/cloudpipe/bootscript.sh2
-rw-r--r--nova/compute/disk.py7
-rw-r--r--nova/compute/node.py20
-rw-r--r--nova/endpoint/cloud.py26
-rw-r--r--nova/exception.py3
-rw-r--r--nova/objectstore/bucket.py4
-rw-r--r--nova/objectstore/handler.py10
-rw-r--r--nova/rpc.py3
-rw-r--r--nova/tests/network_unittest.py2
-rw-r--r--nova/tests/objectstore_unittest.py68
-rw-r--r--nova/volume/storage.py64
11 files changed, 104 insertions, 105 deletions
diff --git a/nova/cloudpipe/bootscript.sh b/nova/cloudpipe/bootscript.sh
index 43fc2ecab..82ec2012a 100755
--- a/nova/cloudpipe/bootscript.sh
+++ b/nova/cloudpipe/bootscript.sh
@@ -24,7 +24,7 @@ export VPN_IP=`ifconfig | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f2
export BROADCAST=`ifconfig | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f3 | awk '{print $1}'`
export DHCP_MASK=`ifconfig | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f4 | awk '{print $1}'`
export GATEWAY=`netstat -r | grep default | cut -d' ' -f10`
-export SUBJ=/C=US/ST=California/L=Mountain View/O=Anso Labs/OU=Nova Dev/CN=customer-vpn-$VPN_IP
+export SUBJ="/C=US/ST=California/L=MountainView/O=AnsoLabs/OU=NovaDev/CN=customer-vpn-$VPN_IP"
DHCP_LOWER=`echo $BROADCAST | awk -F. '{print $1"."$2"."$3"." $4 - 10 }'`
DHCP_UPPER=`echo $BROADCAST | awk -F. '{print $1"."$2"."$3"." $4 - 1 }'`
diff --git a/nova/compute/disk.py b/nova/compute/disk.py
index 08a22556e..1ffcca685 100644
--- a/nova/compute/disk.py
+++ b/nova/compute/disk.py
@@ -40,7 +40,8 @@ def partition(infile, outfile, local_bytes=0, local_type='ext2', execute=None):
formatted as ext2.
In the diagram below, dashes represent drive sectors.
- 0 a b c d e
+ +-----+------. . .-------+------. . .------+
+ | 0 a| b c|d e|
+-----+------. . .-------+------. . .------+
| mbr | primary partiton | local partition |
+-----+------. . .-------+------. . .------+
@@ -64,8 +65,8 @@ def partition(infile, outfile, local_bytes=0, local_type='ext2', execute=None):
last_sector = local_last # e
# create an empty file
- execute('dd if=/dev/zero of=%s count=1 seek=%d bs=%d'
- % (outfile, last_sector, sector_size))
+ yield execute('dd if=/dev/zero of=%s count=1 seek=%d bs=%d'
+ % (outfile, last_sector, sector_size))
# make mbr partition
yield execute('parted --script %s mklabel msdos' % outfile)
diff --git a/nova/compute/node.py b/nova/compute/node.py
index 4683f1c8d..7cae86d02 100644
--- a/nova/compute/node.py
+++ b/nova/compute/node.py
@@ -223,16 +223,20 @@ class Node(object, service.Service):
volume_id = None, mountpoint = None):
volume = storage.get_volume(volume_id)
yield self._init_aoe()
- yield utils.runthis("Attached Volume: %s",
- "sudo virsh attach-disk %s /dev/etherd/%s %s"
- % (instance_id, volume['aoe_device'], mountpoint.split("/")[-1]))
+ yield process.simple_execute(
+ "sudo virsh attach-disk %s /dev/etherd/%s %s" %
+ (instance_id,
+ volume['aoe_device'],
+ mountpoint.rpartition('/dev/')[2]))
volume.finish_attach()
defer.returnValue(True)
+ @defer.inlineCallbacks
def _init_aoe(self):
- utils.runthis("Doin an AoE discover, returns %s", "sudo aoe-discover")
- utils.runthis("Doin an AoE stat, returns %s", "sudo aoe-stat")
+ yield process.simple_execute("sudo aoe-discover")
+ yield process.simple_execute("sudo aoe-stat")
+ @defer.inlineCallbacks
@exception.wrap_exception
def detach_volume(self, instance_id, volume_id):
""" detach a volume from an instance """
@@ -240,10 +244,10 @@ class Node(object, service.Service):
# name without the leading /dev/
volume = storage.get_volume(volume_id)
target = volume['mountpoint'].rpartition('/dev/')[2]
- utils.runthis("Detached Volume: %s", "sudo virsh detach-disk %s %s "
- % (instance_id, target))
+ yield process.simple_execute(
+ "sudo virsh detach-disk %s %s " % (instance_id, target))
volume.finish_detach()
- return defer.succeed(True)
+ defer.returnValue(True)
class Group(object):
diff --git a/nova/endpoint/cloud.py b/nova/endpoint/cloud.py
index 8eac1ce4a..8c6c05566 100644
--- a/nova/endpoint/cloud.py
+++ b/nova/endpoint/cloud.py
@@ -453,21 +453,21 @@ class CloudController(object):
def format_addresses(self, context):
addresses = []
- # TODO(vish): move authorization checking into network.py
for address in self.network.host_objs:
- #logging.debug(address_record)
- address_rv = {
- 'public_ip': address['address'],
- 'instance_id' : address.get('instance_id', 'free')
- }
- if context.user.is_admin():
- address_rv['instance_id'] = "%s (%s, %s)" % (
- address['instance_id'],
- address['user_id'],
- address['project_id'],
- )
+ # TODO(vish): implement a by_project iterator for addresses
+ if (context.user.is_admin() or
+ address['project_id'] == self.project.id):
+ address_rv = {
+ 'public_ip': address['address'],
+ 'instance_id' : address.get('instance_id', 'free')
+ }
+ if context.user.is_admin():
+ address_rv['instance_id'] = "%s (%s, %s)" % (
+ address['instance_id'],
+ address['user_id'],
+ address['project_id'],
+ )
addresses.append(address_rv)
- # logging.debug(addresses)
return {'addressesSet': addresses}
@rbac.allow('netadmin')
diff --git a/nova/exception.py b/nova/exception.py
index bda002d1e..2108123de 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -44,6 +44,9 @@ class Duplicate(Error):
class NotAuthorized(Error):
pass
+class NotEmpty(Error):
+ pass
+
def wrap_exception(f):
def _wrap(*args, **kw):
try:
diff --git a/nova/objectstore/bucket.py b/nova/objectstore/bucket.py
index 090ef4e61..b42a96233 100644
--- a/nova/objectstore/bucket.py
+++ b/nova/objectstore/bucket.py
@@ -107,7 +107,7 @@ class Bucket(object):
try:
return context.user.is_admin() or self.owner_id == context.project.id
except Exception, e:
- pass
+ return False
def list_keys(self, prefix='', marker=None, max_keys=1000, terse=False):
object_names = []
@@ -161,7 +161,7 @@ class Bucket(object):
def delete(self):
if len(os.listdir(self.path)) > 0:
- raise exception.NotAuthorized()
+ raise exception.NotEmpty()
os.rmdir(self.path)
os.remove(self.path+'.json')
diff --git a/nova/objectstore/handler.py b/nova/objectstore/handler.py
index 9566d2c81..7d997390b 100644
--- a/nova/objectstore/handler.py
+++ b/nova/objectstore/handler.py
@@ -277,12 +277,12 @@ class ImageResource(Resource):
def render_POST(self, request):
""" update image attributes: public/private """
- image_id = self.get_argument('image_id', u'')
- operation = self.get_argument('operation', u'')
+ image_id = get_argument(request, 'image_id', u'')
+ operation = get_argument(request, 'operation', u'')
image_object = image.Image(image_id)
- if not image.is_authorized(request.context):
+ if not image_object.is_authorized(request.context):
raise exception.NotAuthorized
image_object.set_public(operation=='add')
@@ -291,10 +291,10 @@ class ImageResource(Resource):
def render_DELETE(self, request):
""" delete a registered image """
- image_id = self.get_argument("image_id", u"")
+ image_id = get_argument(request, "image_id", u"")
image_object = image.Image(image_id)
- if not image.is_authorized(request.context):
+ if not image_object.is_authorized(request.context):
raise exception.NotAuthorized
image_object.delete()
diff --git a/nova/rpc.py b/nova/rpc.py
index ef463e84b..ebf140d92 100644
--- a/nova/rpc.py
+++ b/nova/rpc.py
@@ -151,6 +151,7 @@ class TopicPublisher(Publisher):
def __init__(self, connection=None, topic="broadcast"):
self.routing_key = topic
self.exchange = FLAGS.control_exchange
+ self.durable = False
super(TopicPublisher, self).__init__(connection=connection)
@@ -242,7 +243,7 @@ def send_message(topic, message, wait=True):
consumer.register_callback(generic_response)
publisher = messaging.Publisher(connection=Connection.instance(),
- exchange="nova",
+ exchange=FLAGS.control_exchange,
exchange_type="topic",
routing_key=topic)
publisher.send(message)
diff --git a/nova/tests/network_unittest.py b/nova/tests/network_unittest.py
index 9e17bf155..a8dba835a 100644
--- a/nova/tests/network_unittest.py
+++ b/nova/tests/network_unittest.py
@@ -142,7 +142,7 @@ class NetworkTestCase(test.TrialTestCase):
self.dnsmasq.release_ip(mac3, address3, hostname, net.bridge_name)
net = network.get_project_network(self.projects[0].id, "default")
rv = network.deallocate_ip(secondaddress)
- self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name)
+ self.dnsmasq.release_ip(mac, secondaddress, hostname, net.bridge_name)
def test_release_before_deallocate(self):
pass
diff --git a/nova/tests/objectstore_unittest.py b/nova/tests/objectstore_unittest.py
index 1703adb62..8c6d866cd 100644
--- a/nova/tests/objectstore_unittest.py
+++ b/nova/tests/objectstore_unittest.py
@@ -27,6 +27,7 @@ from nova import flags
from nova import objectstore
from nova import test
from nova.auth import manager
+from nova.exception import NotEmpty, NotFound, NotAuthorized
FLAGS = flags.FLAGS
@@ -95,49 +96,37 @@ class ObjectStoreTestCase(test.BaseTestCase):
# another user is not authorized
self.context.user = self.um.get_user('user2')
self.context.project = self.um.get_project('proj2')
- self.assert_(bucket.is_authorized(self.context) == False)
+ self.assertFalse(bucket.is_authorized(self.context))
# admin is authorized to use bucket
self.context.user = self.um.get_user('admin_user')
self.context.project = None
- self.assert_(bucket.is_authorized(self.context))
+ self.assertTrue(bucket.is_authorized(self.context))
# new buckets are empty
- self.assert_(bucket.list_keys()['Contents'] == [])
+ self.assertTrue(bucket.list_keys()['Contents'] == [])
# storing keys works
bucket['foo'] = "bar"
- self.assert_(len(bucket.list_keys()['Contents']) == 1)
+ self.assertEquals(len(bucket.list_keys()['Contents']), 1)
- self.assert_(bucket['foo'].read() == 'bar')
+ self.assertEquals(bucket['foo'].read(), 'bar')
# md5 of key works
- self.assert_(bucket['foo'].md5 == hashlib.md5('bar').hexdigest())
-
- # deleting non-empty bucket throws exception
- exception = False
- try:
- bucket.delete()
- except:
- exception = True
+ self.assertEquals(bucket['foo'].md5, hashlib.md5('bar').hexdigest())
- self.assert_(exception)
+ # deleting non-empty bucket should throw a NotEmpty exception
+ self.assertRaises(NotEmpty, bucket.delete)
# deleting key
del bucket['foo']
- # deleting empty button
+ # deleting empty bucket
bucket.delete()
# accessing deleted bucket throws exception
- exception = False
- try:
- objectstore.bucket.Bucket('new_bucket')
- except:
- exception = True
-
- self.assert_(exception)
+ self.assertRaises(NotFound, objectstore.bucket.Bucket, 'new_bucket')
def test_images(self):
self.context.user = self.um.get_user('user1')
@@ -166,37 +155,4 @@ class ObjectStoreTestCase(test.BaseTestCase):
# verify image permissions
self.context.user = self.um.get_user('user2')
self.context.project = self.um.get_project('proj2')
- self.assert_(my_img.is_authorized(self.context) == False)
-
-# class ApiObjectStoreTestCase(test.BaseTestCase):
-# def setUp(self):
-# super(ApiObjectStoreTestCase, self).setUp()
-# FLAGS.fake_users = True
-# FLAGS.buckets_path = os.path.join(tempdir, 'buckets')
-# FLAGS.images_path = os.path.join(tempdir, 'images')
-# FLAGS.ca_path = os.path.join(os.path.dirname(__file__), 'CA')
-#
-# self.users = manager.AuthManager()
-# self.app = handler.Application(self.users)
-#
-# self.host = '127.0.0.1'
-#
-# self.conn = boto.s3.connection.S3Connection(
-# aws_access_key_id=user.access,
-# aws_secret_access_key=user.secret,
-# is_secure=False,
-# calling_format=boto.s3.connection.OrdinaryCallingFormat(),
-# port=FLAGS.s3_port,
-# host=FLAGS.s3_host)
-#
-# self.mox.StubOutWithMock(self.ec2, 'new_http_connection')
-#
-# def tearDown(self):
-# FLAGS.Reset()
-# super(ApiObjectStoreTestCase, self).tearDown()
-#
-# def test_describe_instances(self):
-# self.expect_http()
-# self.mox.ReplayAll()
-#
-# self.assertEqual(self.ec2.get_all_instances(), [])
+ self.assertFalse(my_img.is_authorized(self.context))
diff --git a/nova/volume/storage.py b/nova/volume/storage.py
index de20f30b5..121bc01e6 100644
--- a/nova/volume/storage.py
+++ b/nova/volume/storage.py
@@ -28,15 +28,17 @@ import os
import shutil
import socket
import tempfile
-import time
-from tornado import ioloop
+
+from twisted.application import service
from twisted.internet import defer
from nova import datastore
from nova import exception
from nova import flags
+from nova import process
from nova import utils
from nova import validate
+from nova.compute import model
FLAGS = flags.FLAGS
@@ -80,7 +82,7 @@ def get_volume(volume_id):
return volume_class(volume_id=volume_id)
raise exception.Error("Volume does not exist")
-class BlockStore(object):
+class BlockStore(object, service.Service):
"""
There is one BlockStore running on each volume node.
However, each BlockStore can report on the state of
@@ -102,9 +104,21 @@ class BlockStore(object):
except Exception, err:
pass
- def report_state(self):
- #TODO: aggregate the state of the system
- pass
+ @defer.inlineCallbacks
+ def report_state(self, nodename, daemon):
+ # TODO(termie): make this pattern be more elegant. -todd
+ try:
+ record = model.Daemon(nodename, daemon)
+ record.heartbeat()
+ if getattr(self, "model_disconnected", False):
+ self.model_disconnected = False
+ logging.error("Recovered model server connection!")
+
+ except model.ConnectionError, ex:
+ if not getattr(self, "model_disconnected", False):
+ self.model_disconnected = True
+ logging.exception("model server went away")
+ yield
@validate.rangetest(size=(0, 1000))
def create_volume(self, size, user_id, project_id):
@@ -143,17 +157,24 @@ class BlockStore(object):
datastore.Redis.instance().srem('volumes:%s' % (FLAGS.storage_name), vol['volume_id'])
return True
+ @defer.inlineCallbacks
def _restart_exports(self):
if FLAGS.fake_storage:
return
- utils.runthis("Setting exports to auto: %s", "sudo vblade-persist auto all")
- utils.runthis("Starting all exports: %s", "sudo vblade-persist start all")
+ yield process.simple_execute(
+ "sudo vblade-persist auto all")
+ yield process.simple_execute(
+ "sudo vblade-persist start all")
+ @defer.inlineCallbacks
def _init_volume_group(self):
if FLAGS.fake_storage:
return
- utils.runthis("PVCreate returned: %s", "sudo pvcreate %s" % (FLAGS.storage_dev))
- utils.runthis("VGCreate returned: %s", "sudo vgcreate %s %s" % (FLAGS.volume_group, FLAGS.storage_dev))
+ yield process.simple_execute(
+ "sudo pvcreate %s" % (FLAGS.storage_dev))
+ yield process.simple_execute(
+ "sudo vgcreate %s %s" % (FLAGS.volume_group,
+ FLAGS.storage_dev))
class Volume(datastore.BasicModel):
@@ -227,15 +248,22 @@ class Volume(datastore.BasicModel):
self._delete_lv()
super(Volume, self).destroy()
+ @defer.inlineCallbacks
def create_lv(self):
if str(self['size']) == '0':
sizestr = '100M'
else:
sizestr = '%sG' % self['size']
- utils.runthis("Creating LV: %s", "sudo lvcreate -L %s -n %s %s" % (sizestr, self['volume_id'], FLAGS.volume_group))
+ yield process.simple_execute(
+ "sudo lvcreate -L %s -n %s %s" % (sizestr,
+ self['volume_id'],
+ FLAGS.volume_group))
+ @defer.inlineCallbacks
def _delete_lv(self):
- utils.runthis("Removing LV: %s", "sudo lvremove -f %s/%s" % (FLAGS.volume_group, self['volume_id']))
+ yield process.simple_execute(
+ "sudo lvremove -f %s/%s" % (FLAGS.volume_group,
+ self['volume_id']))
def _setup_export(self):
(shelf_id, blade_id) = get_next_aoe_numbers()
@@ -245,8 +273,9 @@ class Volume(datastore.BasicModel):
self.save()
self._exec_export()
+ @defer.inlineCallbacks
def _exec_export(self):
- utils.runthis("Creating AOE export: %s",
+ yield process.simple_execute(
"sudo vblade-persist setup %s %s %s /dev/%s/%s" %
(self['shelf_id'],
self['blade_id'],
@@ -254,9 +283,14 @@ class Volume(datastore.BasicModel):
FLAGS.volume_group,
self['volume_id']))
+ @defer.inlineCallbacks
def _remove_export(self):
- utils.runthis("Stopped AOE export: %s", "sudo vblade-persist stop %s %s" % (self['shelf_id'], self['blade_id']))
- utils.runthis("Destroyed AOE export: %s", "sudo vblade-persist destroy %s %s" % (self['shelf_id'], self['blade_id']))
+ yield process.simple_execute(
+ "sudo vblade-persist stop %s %s" % (self['shelf_id'],
+ self['blade_id']))
+ yield process.simple_execute(
+ "sudo vblade-persist destroy %s %s" % (self['shelf_id'],
+ self['blade_id']))
class FakeVolume(Volume):