summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTodd Willey <todd@ansolabs.com>2011-01-12 17:35:09 -0500
committerTodd Willey <todd@ansolabs.com>2011-01-12 17:35:09 -0500
commit038c9c7663ee1a884726521afe181d30ebe00cc6 (patch)
treeda84fd2b309e195854532ead861b45d871d4ee07
parent6ebf9bb2db0aaad607e35e516bb6d7ffc971c5de (diff)
parent67307428d6d6f47f3215f485a1af720013a5c2ae (diff)
downloadnova-038c9c7663ee1a884726521afe181d30ebe00cc6.tar.gz
nova-038c9c7663ee1a884726521afe181d30ebe00cc6.tar.xz
nova-038c9c7663ee1a884726521afe181d30ebe00cc6.zip
Merge trunk and handle flagfiles with kid-gloves in nova-api. Rename some flags for clarity.
-rw-r--r--Authors1
-rwxr-xr-xbin/nova-api65
-rwxr-xr-xbin/nova-combined1
-rw-r--r--etc/nova-api.conf10
-rw-r--r--nova/api/ec2/__init__.py3
-rw-r--r--nova/api/ec2/cloud.py6
-rw-r--r--nova/auth/manager.py24
-rw-r--r--nova/cloudpipe/pipelib.py4
-rw-r--r--nova/flags.py16
-rw-r--r--nova/network/linux_net.py2
-rw-r--r--nova/virt/libvirt_conn.py23
-rw-r--r--nova/volume/driver.py57
12 files changed, 134 insertions, 78 deletions
diff --git a/Authors b/Authors
index 56344957e..0c49f76a2 100644
--- a/Authors
+++ b/Authors
@@ -21,6 +21,7 @@ Jesse Andrews <anotherjesse@gmail.com>
Joe Heck <heckj@mac.com>
Joel Moore <joelbm24@gmail.com>
Jonathan Bryce <jbryce@jbryce.com>
+Josh Durgin <joshd@hq.newdream.net>
Josh Kearney <josh.kearney@rackspace.com>
Joshua McKenty <jmckenty@gmail.com>
Justin Santa Barbara <justin@fathomdb.com>
diff --git a/bin/nova-api b/bin/nova-api
index 419f0bbdc..b30c5ee71 100755
--- a/bin/nova-api
+++ b/bin/nova-api
@@ -40,59 +40,48 @@ from nova import flags
from nova import log as logging
from nova import wsgi
+logging.basicConfig()
LOG = logging.getLogger('nova.api')
-LOG.setLevel(logging.DEBUG)
-LOG.addHandler(logging.StreamHandler())
FLAGS = flags.FLAGS
-API_ENDPOINTS = ['ec2', 'openstack']
+API_ENDPOINTS = ['ec2', 'osapi']
-def load_configuration(paste_config):
+def load_configuration(paste_config, name):
"""Load the paste configuration from the config file and return it."""
config = None
- # Try each known name to get the global DEFAULTS, which will give ports
- for name in API_ENDPOINTS:
- try:
- config = deploy.appconfig("config:%s" % paste_config, name=name)
- except LookupError:
- pass
- if config:
- verbose = config.get('verbose', None)
- if verbose:
- FLAGS.verbose = int(verbose) == 1
- if FLAGS.verbose:
- logging.getLogger().setLevel(logging.DEBUG)
- return config
- LOG.debug(_("Paste config at %s has no secion for known apis"),
- paste_config)
- print _("Paste config at %s has no secion for any known apis") % \
- paste_config
- os.exit(1)
-
-
-def launch_api(paste_config_file, section, server, port, host):
- """Launch an api server from the specified port and IP."""
- LOG.debug(_("Launching %s api on %s:%s"), section, host, port)
- app = deploy.loadapp('config:%s' % paste_config_file, name=section)
- server.start(app, int(port), host)
+ try:
+ config = deploy.appconfig("config:%s" % paste_config, name=name)
+ return config
+ except LookupError:
+ return None
def run_app(paste_config_file):
LOG.debug(_("Using paste.deploy config at: %s"), configfile)
- config = load_configuration(paste_config_file)
- LOG.debug(_("Configuration: %r"), config)
server = wsgi.Server()
- ip = config.get('host', '0.0.0.0')
+ apps = []
for api in API_ENDPOINTS:
- port = config.get("%s_port" % api, None)
- if not port:
+ config = load_configuration(paste_config_file, api)
+ if config is None:
continue
- host = config.get("%s_host" % api, ip)
- launch_api(configfile, api, server, port, host)
- LOG.debug(_("All api servers launched, now waiting"))
- server.wait()
+ if int(config.get('verbose', 0)) == 1:
+ FLAGS.verbose = True
+ host = config.get("%s_host" % api, config.get('host', '0.0.0.0'))
+ port = config.get("%s_port" % api, getattr(FLAGS, "%s_port" % api))
+ setattr(FLAGS, "%s_host" % api, host)
+ setattr(FLAGS, "%s_port" % api, port)
+ LOG.info(_("Running %s API"), api)
+ app = deploy.loadapp('config:%s' % paste_config_file, name=api)
+ apps.append((app, int(port), host))
+ if len(apps) == 0:
+ LOG.error(_("No known API applications configured in %s."),
+ paste_config_file)
+ else:
+ for app in apps:
+ server.start(*app)
+ server.wait()
if __name__ == '__main__':
diff --git a/bin/nova-combined b/bin/nova-combined
index 53322f1a0..f932fdfd5 100755
--- a/bin/nova-combined
+++ b/bin/nova-combined
@@ -44,7 +44,6 @@ from nova import wsgi
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')
diff --git a/etc/nova-api.conf b/etc/nova-api.conf
index 7c6a5b4f3..b68471ece 100644
--- a/etc/nova-api.conf
+++ b/etc/nova-api.conf
@@ -1,9 +1,5 @@
[DEFAULT]
verbose = 1
-ec2_port = 8773
-ec2_address = 0.0.0.0
-openstack_port = 8774
-openstack_address = 0.0.0.0
#######
# EC2 #
@@ -64,13 +60,13 @@ paste.app_factory = nova.api.ec2.metadatarequesthandler:metadata_factory
# Openstack #
#############
-[composite:openstack]
+[composite:osapi]
use = egg:Paste#urlmap
/: osversions
/v1.0: openstackapi
[pipeline:openstackapi]
-pipeline = faultwrap auth ratelimit osapi
+pipeline = faultwrap auth ratelimit osapiapp
[filter:faultwrap]
paste.filter_factory = nova.api.openstack:fault_wrapper_factory
@@ -81,7 +77,7 @@ paste.filter_factory = nova.api.openstack.auth:auth_factory
[filter:ratelimit]
paste.filter_factory = nova.api.openstack.ratelimiting:ratelimit_factory
-[app:osapi]
+[app:osapiapp]
paste.app_factory = nova.api.openstack:router_factory
[pipeline:osversions]
diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py
index 1286be5ea..d0adf5e21 100644
--- a/nova/api/ec2/__init__.py
+++ b/nova/api/ec2/__init__.py
@@ -278,8 +278,7 @@ class Authorizer(wsgi.Middleware):
return self.application
else:
LOG.audit(_("Unauthorized request for controller=%s "
- "and action=%s"), controller_name, action,
- context=context)
+ "and action=%s"), controller, action, context=context)
raise webob.exc.HTTPUnauthorized()
def _matches_any_role(self, context, roles):
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index 832426b94..e5308ca87 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -263,15 +263,15 @@ class CloudController(object):
name, _sep, host = region.partition('=')
endpoint = '%s://%s:%s%s' % (FLAGS.ec2_prefix,
host,
- FLAGS.cc_port,
+ FLAGS.ec2_port,
FLAGS.ec2_suffix)
regions.append({'regionName': name,
'regionEndpoint': endpoint})
else:
regions = [{'regionName': 'nova',
'regionEndpoint': '%s://%s:%s%s' % (FLAGS.ec2_prefix,
- FLAGS.cc_host,
- FLAGS.cc_port,
+ FLAGS.ec2_host,
+ FLAGS.ec2_port,
FLAGS.ec2_suffix)}]
return {'regionInfo': regions}
diff --git a/nova/auth/manager.py b/nova/auth/manager.py
index 89f02998d..ea7d07b1e 100644
--- a/nova/auth/manager.py
+++ b/nova/auth/manager.py
@@ -682,7 +682,7 @@ class AuthManager(object):
region, _sep, region_host = item.partition("=")
regions[region] = region_host
else:
- regions = {'nova': FLAGS.cc_host}
+ regions = {'nova': FLAGS.ec2_host}
for region, host in regions.iteritems():
rc = self.__generate_rc(user,
pid,
@@ -727,28 +727,28 @@ class AuthManager(object):
def __generate_rc(user, pid, use_dmz=True, host=None):
"""Generate rc file for user"""
if use_dmz:
- cc_host = FLAGS.cc_dmz
+ ec2_host = FLAGS.ec2_dmz_host
else:
- cc_host = FLAGS.cc_host
+ ec2_host = FLAGS.ec2_host
# NOTE(vish): Always use the dmz since it is used from inside the
# instance
s3_host = FLAGS.s3_dmz
if host:
s3_host = host
- cc_host = host
+ ec2_host = host
rc = open(FLAGS.credentials_template).read()
rc = rc % {'access': user.access,
'project': pid,
'secret': user.secret,
- 'ec2': '%s://%s:%s%s' % (FLAGS.ec2_prefix,
- cc_host,
- FLAGS.cc_port,
- FLAGS.ec2_suffix),
+ 'ec2': '%s://%s:%s%s' % (FLAGS.ec2_scheme,
+ ec2_host,
+ FLAGS.ec2_port,
+ FLAGS.ec2_path),
's3': 'http://%s:%s' % (s3_host, FLAGS.s3_port),
- 'os': '%s://%s:%s%s' % (FLAGS.os_prefix,
- cc_host,
- FLAGS.cc_port,
- FLAGS.os_suffix),
+ 'os': '%s://%s:%s%s' % (FLAGS.osapi_scheme,
+ ec2_host,
+ FLAGS.osapi_port,
+ FLAGS.osapi_path),
'user': user.name,
'nova': FLAGS.ca_file,
'cert': FLAGS.credential_cert_file,
diff --git a/nova/cloudpipe/pipelib.py b/nova/cloudpipe/pipelib.py
index 8aefd341f..dc6f55af2 100644
--- a/nova/cloudpipe/pipelib.py
+++ b/nova/cloudpipe/pipelib.py
@@ -68,8 +68,8 @@ class CloudPipe(object):
shellfile = open(FLAGS.boot_script_template, "r")
s = string.Template(shellfile.read())
shellfile.close()
- boot_script = s.substitute(cc_dmz=FLAGS.cc_dmz,
- cc_port=FLAGS.cc_port,
+ boot_script = s.substitute(cc_dmz=FLAGS.ec2_dmz_host,
+ cc_port=FLAGS.ec2_port,
dmz_net=FLAGS.dmz_net,
dmz_mask=FLAGS.dmz_mask,
num_vpn=FLAGS.cnt_vpn_clients)
diff --git a/nova/flags.py b/nova/flags.py
index fdcba6c72..81e2e36f9 100644
--- a/nova/flags.py
+++ b/nova/flags.py
@@ -254,13 +254,15 @@ 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('ec2_prefix', 'http', 'prefix for ec2')
-DEFINE_string('os_prefix', 'http', 'prefix for openstack')
-DEFINE_string('cc_host', '$my_ip', 'ip of api server')
-DEFINE_string('cc_dmz', '$my_ip', 'internal ip of api server')
-DEFINE_integer('cc_port', 8773, 'cloud controller port')
-DEFINE_string('ec2_suffix', '/services/Cloud', 'suffix for ec2')
-DEFINE_string('os_suffix', '/v1.0/', 'suffix for openstack')
+DEFINE_string('ec2_host', '$my_ip', 'ip of api server')
+DEFINE_string('ec2_dmz_host', '$my_ip', 'internal ip of api server')
+DEFINE_integer('ec2_port', 8773, 'cloud controller port')
+DEFINE_string('ec2_scheme', 'http', 'prefix for ec2')
+DEFINE_string('ec2_path', '/services/Cloud', 'suffix for ec2')
+DEFINE_string('osapi_host', '$my_ip', 'ip of api server')
+DEFINE_string('osapi_scheme', 'http', 'prefix for openstack')
+DEFINE_integer('osapi_port', 8774, 'OpenStack API port')
+DEFINE_string('osapi_path', '/v1.0/', 'suffix for openstack')
DEFINE_string('default_project', 'openstack', 'default project for openstack')
DEFINE_string('default_image', 'ami-11111',
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
index 3743fc7e8..69bb37b49 100644
--- a/nova/network/linux_net.py
+++ b/nova/network/linux_net.py
@@ -60,7 +60,7 @@ def metadata_forward():
"""Create forwarding rule for metadata"""
_confirm_rule("PREROUTING", "-t nat -s 0.0.0.0/0 "
"-d 169.254.169.254/32 -p tcp -m tcp --dport 80 -j DNAT "
- "--to-destination %s:%s" % (FLAGS.cc_dmz, FLAGS.cc_port))
+ "--to-destination %s:%s" % (FLAGS.ec2_dmz_host, FLAGS.ec2_port))
def init_host():
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index 655c55fa1..bd863b3a2 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -243,11 +243,24 @@ class LibvirtConnection(object):
def attach_volume(self, instance_name, device_path, mountpoint):
virt_dom = self._conn.lookupByName(instance_name)
mount_device = mountpoint.rpartition("/")[2]
- xml = """<disk type='block'>
- <driver name='qemu' type='raw'/>
- <source dev='%s'/>
- <target dev='%s' bus='virtio'/>
- </disk>""" % (device_path, mount_device)
+ if device_path.startswith('/dev/'):
+ xml = """<disk type='block'>
+ <driver name='qemu' type='raw'/>
+ <source dev='%s'/>
+ <target dev='%s' bus='virtio'/>
+ </disk>""" % (device_path, mount_device)
+ elif ':' in device_path:
+ (protocol, name) = device_path.split(':')
+ xml = """<disk type='network'>
+ <driver name='qemu' type='raw'/>
+ <source protocol='%s' name='%s'/>
+ <target dev='%s' bus='virtio'/>
+ </disk>""" % (protocol,
+ name,
+ mount_device)
+ else:
+ raise exception.Invalid(_("Invalid device path %s") % device_path)
+
virt_dom.attachDevice(xml)
def _get_disk_xml(self, xml, device):
diff --git a/nova/volume/driver.py b/nova/volume/driver.py
index 6bc925f3e..44bfeaf0c 100644
--- a/nova/volume/driver.py
+++ b/nova/volume/driver.py
@@ -49,6 +49,8 @@ flags.DEFINE_string('iscsi_target_prefix', 'iqn.2010-10.org.openstack:',
'prefix for iscsi volumes')
flags.DEFINE_string('iscsi_ip_prefix', '127.0',
'discover volumes on the ip that starts with this prefix')
+flags.DEFINE_string('rbd_pool', 'rbd',
+ 'the rbd pool in which volumes are stored')
class VolumeDriver(object):
@@ -314,3 +316,58 @@ class FakeISCSIDriver(ISCSIDriver):
"""Execute that simply logs the command."""
LOG.debug(_("FAKE ISCSI: %s"), cmd)
return (None, None)
+
+
+class RBDDriver(VolumeDriver):
+ """Implements RADOS block device (RBD) volume commands"""
+
+ def check_for_setup_error(self):
+ """Returns an error if prerequisites aren't met"""
+ (stdout, stderr) = self._execute("rados lspools")
+ pools = stdout.split("\n")
+ if not FLAGS.rbd_pool in pools:
+ raise exception.Error(_("rbd has no pool %s") %
+ FLAGS.rbd_pool)
+
+ def create_volume(self, volume):
+ """Creates a logical volume."""
+ if int(volume['size']) == 0:
+ size = 100
+ else:
+ size = int(volume['size']) * 1024
+ self._try_execute("rbd --pool %s --size %d create %s" %
+ (FLAGS.rbd_pool,
+ size,
+ volume['name']))
+
+ def delete_volume(self, volume):
+ """Deletes a logical volume."""
+ self._try_execute("rbd --pool %s rm %s" %
+ (FLAGS.rbd_pool,
+ volume['name']))
+
+ def local_path(self, volume):
+ """Returns the path of the rbd volume."""
+ # This is the same as the remote path
+ # since qemu accesses it directly.
+ return self.discover_volume(volume)
+
+ def ensure_export(self, context, volume):
+ """Synchronously recreates an export for a logical volume."""
+ pass
+
+ def create_export(self, context, volume):
+ """Exports the volume"""
+ pass
+
+ def remove_export(self, context, volume):
+ """Removes an export for a logical volume"""
+ pass
+
+ def discover_volume(self, volume):
+ """Discover volume on a remote host"""
+ return "rbd:%s/%s" % (FLAGS.rbd_pool, volume['name'])
+
+ def undiscover_volume(self, volume):
+ """Undiscover volume on a remote host"""
+ pass