diff options
Diffstat (limited to 'nova/api')
| -rw-r--r-- | nova/api/__init__.py | 43 | ||||
| -rw-r--r-- | nova/api/cloud.py | 20 | ||||
| -rw-r--r-- | nova/api/ec2/__init__.py | 5 | ||||
| -rw-r--r-- | nova/api/ec2/cloud.py | 69 | ||||
| -rw-r--r-- | nova/api/openstack/servers.py | 25 |
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, |
