summaryrefslogtreecommitdiffstats
path: root/nova/api
diff options
context:
space:
mode:
authorMichael Gundlach <michael.gundlach@rackspace.com>2010-11-16 13:23:12 -0500
committerMichael Gundlach <michael.gundlach@rackspace.com>2010-11-16 13:23:12 -0500
commit1d2bb38ed4d79f7455a5b8b83c652706bdca0489 (patch)
treee6521d16e92a7cd25a3d8119c5db1c0845bfa497 /nova/api
parentdfe98891b46c4f02f13ea2686979ca7ff4547bd3 (diff)
parent06118df7b06a729e918242149119a485b9f25f7e (diff)
Merge from trunk
Diffstat (limited to 'nova/api')
-rw-r--r--nova/api/__init__.py43
-rw-r--r--nova/api/cloud.py20
-rw-r--r--nova/api/ec2/__init__.py5
-rw-r--r--nova/api/ec2/cloud.py69
-rw-r--r--nova/api/openstack/servers.py25
5 files changed, 105 insertions, 57 deletions
diff --git a/nova/api/__init__.py b/nova/api/__init__.py
index 8a1d9fe32..7e75445a8 100644
--- a/nova/api/__init__.py
+++ b/nova/api/__init__.py
@@ -15,15 +15,22 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-
"""
Root WSGI middleware for all API controllers.
+
+**Related Flags**
+
+:osapi_subdomain: subdomain running the OpenStack API (default: api)
+:ec2api_subdomain: subdomain running the EC2 API (default: ec2)
+:FAKE_subdomain: set to 'api' or 'ec2', requests default to that endpoint
+
"""
import routes
import webob.dec
from nova import flags
+from nova import utils
from nova import wsgi
from nova.api import cloudpipe
from nova.api import ec2
@@ -35,37 +42,31 @@ flags.DEFINE_string('osapi_subdomain', 'api',
'subdomain running the OpenStack API')
flags.DEFINE_string('ec2api_subdomain', 'ec2',
'subdomain running the EC2 API')
-flags.DEFINE_string('FAKE_subdomain', None,
- 'set to api or ec2 to fake the subdomain of the host '
- 'for testing')
FLAGS = flags.FLAGS
class API(wsgi.Router):
"""Routes top-level requests to the appropriate controller."""
- def __init__(self):
- osapidomain = {'sub_domain': [FLAGS.osapi_subdomain]}
- ec2domain = {'sub_domain': [FLAGS.ec2api_subdomain]}
- # If someone wants to pretend they're hitting the OSAPI subdomain
- # on their local box, they can set FAKE_subdomain to 'api', which
- # removes subdomain restrictions from the OpenStack API routes below.
- if FLAGS.FAKE_subdomain == 'api':
- osapidomain = {}
- elif FLAGS.FAKE_subdomain == 'ec2':
- ec2domain = {}
+ def __init__(self, default_api):
+ osapi_subdomain = {'sub_domain': [FLAGS.osapi_subdomain]}
+ ec2api_subdomain = {'sub_domain': [FLAGS.ec2api_subdomain]}
+ if default_api == 'os':
+ osapi_subdomain = {}
+ elif default_api == 'ec2':
+ ec2api_subdomain = {}
mapper = routes.Mapper()
mapper.sub_domains = True
+
mapper.connect("/", controller=self.osapi_versions,
- conditions=osapidomain)
+ conditions=osapi_subdomain)
mapper.connect("/v1.0/{path_info:.*}", controller=openstack.API(),
- conditions=osapidomain)
+ conditions=osapi_subdomain)
mapper.connect("/", controller=self.ec2api_versions,
- conditions=ec2domain)
+ conditions=ec2api_subdomain)
mapper.connect("/services/{path_info:.*}", controller=ec2.API(),
- conditions=ec2domain)
- mapper.connect("/cloudpipe/{path_info:.*}", controller=cloudpipe.API())
+ conditions=ec2api_subdomain)
mrh = metadatarequesthandler.MetadataRequestHandler()
for s in ['/latest',
'/2009-04-04',
@@ -78,7 +79,9 @@ class API(wsgi.Router):
'/2007-01-19',
'/1.0']:
mapper.connect('%s/{path_info:.*}' % s, controller=mrh,
- conditions=ec2domain)
+ conditions=ec2api_subdomain)
+
+ mapper.connect("/cloudpipe/{path_info:.*}", controller=cloudpipe.API())
super(API, self).__init__(mapper)
@webob.dec.wsgify
diff --git a/nova/api/cloud.py b/nova/api/cloud.py
index aa84075dc..b8f15019f 100644
--- a/nova/api/cloud.py
+++ b/nova/api/cloud.py
@@ -36,3 +36,23 @@ def reboot(instance_id, context=None):
db.queue_get_for(context, FLAGS.compute_topic, host),
{"method": "reboot_instance",
"args": {"instance_id": instance_ref['id']}})
+
+
+def rescue(instance_id, context):
+ """Rescue the given instance."""
+ instance_ref = db.instance_get_by_internal_id(context, instance_id)
+ host = instance_ref['host']
+ rpc.cast(context,
+ db.queue_get_for(context, FLAGS.compute_topic, host),
+ {"method": "rescue_instance",
+ "args": {"instance_id": instance_ref['id']}})
+
+
+def unrescue(instance_id, context):
+ """Unrescue the given instance."""
+ instance_ref = db.instance_get_by_internal_id(context, instance_id)
+ host = instance_ref['host']
+ rpc.cast(context,
+ db.queue_get_for(context, FLAGS.compute_topic, host),
+ {"method": "unrescue_instance",
+ "args": {"instance_id": instance_ref['id']}})
diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py
index 0df4d3710..b7664ec71 100644
--- a/nova/api/ec2/__init__.py
+++ b/nova/api/ec2/__init__.py
@@ -15,8 +15,10 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
+"""
+Starting point for routing EC2 requests.
-"""Starting point for routing EC2 requests"""
+"""
import logging
import routes
@@ -238,6 +240,7 @@ class Executor(wsgi.Application):
return self._error(req, type(ex).__name__, str(ex))
def _error(self, req, code, message):
+ logging.error("%s: %s", code, message)
resp = webob.Response()
resp.status = 400
resp.headers['Content-Type'] = 'text/xml'
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index 07229dd73..fbe4caa48 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -99,6 +99,7 @@ class CloudController(object):
"""
def __init__(self):
self.network_manager = utils.import_object(FLAGS.network_manager)
+ self.compute_manager = utils.import_object(FLAGS.compute_manager)
self.setup()
def __str__(self):
@@ -464,24 +465,31 @@ class CloudController(object):
return {'volumeSet': volumes}
def _format_volume(self, context, volume):
+ instance_ec2_id = None
+ instance_data = None
+ if volume.get('instance', None):
+ internal_id = volume['instance']['internal_id']
+ instance_ec2_id = internal_id_to_ec2_id(internal_id)
+ instance_data = '%s[%s]' % (instance_ec2_id,
+ volume['instance']['host'])
v = {}
v['volumeId'] = volume['ec2_id']
v['status'] = volume['status']
v['size'] = volume['size']
v['availabilityZone'] = volume['availability_zone']
v['createTime'] = volume['created_at']
- if context.user.is_admin():
+ if context.is_admin:
v['status'] = '%s (%s, %s, %s, %s)' % (
volume['status'],
volume['user_id'],
volume['host'],
- volume['instance_id'],
+ instance_data,
volume['mountpoint'])
if volume['attach_status'] == 'attached':
v['attachmentSet'] = [{'attachTime': volume['attach_time'],
'deleteOnTermination': False,
'device': volume['mountpoint'],
- 'instanceId': volume['instance_id'],
+ 'instanceId': instance_ec2_id,
'status': 'attached',
'volume_id': volume['ec2_id']}]
else:
@@ -516,7 +524,10 @@ class CloudController(object):
"args": {"topic": FLAGS.volume_topic,
"volume_id": volume_ref['id']}})
- return {'volumeSet': [self._format_volume(context, volume_ref)]}
+ # TODO(vish): Instance should be None at db layer instead of
+ # trying to lazy load, but for now we turn it into
+ # a dict to avoid an error.
+ return {'volumeSet': [self._format_volume(context, dict(volume_ref))]}
def attach_volume(self, context, volume_id, instance_id, device, **kwargs):
volume_ref = db.volume_get_by_ec2_id(context, volume_id)
@@ -835,21 +846,21 @@ class CloudController(object):
elevated = context.elevated()
for num in range(num_instances):
- instance_ref = db.instance_create(context, base_options)
- inst_id = instance_ref['id']
- for security_group_id in security_groups:
- db.instance_add_security_group(elevated,
- inst_id,
- security_group_id)
+ instance_ref = self.compute_manager.create_instance(context,
+ security_groups,
+ mac_address=utils.generate_mac(),
+ launch_index=num,
+ **base_options)
+ inst_id = instance_ref['id']
- inst = {}
- inst['mac_address'] = utils.generate_mac()
- inst['launch_index'] = num
internal_id = instance_ref['internal_id']
ec2_id = internal_id_to_ec2_id(internal_id)
- inst['hostname'] = ec2_id
- db.instance_update(context, inst_id, inst)
+
+ self.compute_manager.update_instance(context,
+ inst_id,
+ hostname=ec2_id)
+
# TODO(vish): This probably should be done in the scheduler
# or in compute as a call. The network should be
# allocated after the host is assigned and setup
@@ -895,11 +906,12 @@ class CloudController(object):
id_str)
continue
now = datetime.datetime.utcnow()
- db.instance_update(context,
- instance_ref['id'],
- {'state_description': 'terminating',
- 'state': 0,
- 'terminated_at': now})
+ self.compute_manager.update_instance(context,
+ instance_ref['id'],
+ state_description='terminating',
+ state=0,
+ terminated_at=now)
+
# FIXME(ja): where should network deallocate occur?
address = db.instance_get_floating_address(context,
instance_ref['id'])
@@ -936,8 +948,21 @@ class CloudController(object):
def reboot_instances(self, context, instance_id, **kwargs):
"""instance_id is a list of instance ids"""
- for id_str in instance_id:
- cloud.reboot(id_str, context=context)
+ for ec2_id in instance_id:
+ internal_id = ec2_id_to_internal_id(ec2_id)
+ cloud.reboot(internal_id, context=context)
+ return True
+
+ def rescue_instance(self, context, instance_id, **kwargs):
+ """This is an extension to the normal ec2_api"""
+ internal_id = ec2_id_to_internal_id(instance_id)
+ cloud.rescue(internal_id, context=context)
+ return True
+
+ def unrescue_instance(self, context, instance_id, **kwargs):
+ """This is an extension to the normal ec2_api"""
+ internal_id = ec2_id_to_internal_id(instance_id)
+ cloud.unrescue(internal_id, context=context)
return True
def update_instance(self, context, ec2_id, **kwargs):
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index ef773c3be..1d8aa2fa4 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -95,6 +95,7 @@ class Controller(wsgi.Controller):
db_driver = FLAGS.db_driver
self.db_driver = utils.import_object(db_driver)
self.network_manager = utils.import_object(FLAGS.network_manager)
+ self.compute_manager = utils.import_object(FLAGS.compute_manager)
super(Controller, self).__init__()
def index(self, req):
@@ -242,34 +243,30 @@ class Controller(wsgi.Controller):
inst['memory_mb'] = flavor['memory_mb']
inst['vcpus'] = flavor['vcpus']
inst['local_gb'] = flavor['local_gb']
-
- ref = self.db_driver.instance_create(ctxt, inst)
- inst['id'] = ref.internal_id
-
inst['mac_address'] = utils.generate_mac()
-
- #TODO(dietz) is this necessary?
inst['launch_index'] = 0
- inst['hostname'] = str(ref.internal_id)
- self.db_driver.instance_update(ctxt, inst['id'], inst)
+ ref = self.compute_manager.create_instance(ctxt, **inst)
+ inst['id'] = ref['internal_id']
+
+ inst['hostname'] = str(ref['internal_id'])
+ self.compute_manager.update_instance(ctxt, inst['id'], **inst)
- network_manager = utils.import_object(FLAGS.network_manager)
- address = network_manager.allocate_fixed_ip(ctxt,
- inst['id'])
+ address = self.network_manager.allocate_fixed_ip(ctxt,
+ inst['id'])
# TODO(vish): This probably should be done in the scheduler
# network is setup when host is assigned
- network_topic = self._get_network_topic(ctxt, network_manager)
+ network_topic = self._get_network_topic(ctxt)
rpc.call(ctxt,
network_topic,
{"method": "setup_fixed_ip",
"args": {"address": address}})
return inst
- def _get_network_topic(self, context, network_manager):
+ def _get_network_topic(self, context):
"""Retrieves the network host for a project"""
- network_ref = network_manager.get_network(context)
+ network_ref = self.network_manager.get_network(context)
host = network_ref['host']
if not host:
host = rpc.call(context,