From 198af0ef9e65bc4c2efe74b9d93cf40210eb77bc Mon Sep 17 00:00:00 2001 From: "jaypipes@gmail.com" <> Date: Thu, 21 Oct 2010 14:29:34 -0400 Subject: Moves db writes into compute manager class. Cleans up sqlalchemy model/api to remove redundant calls for updating what is really a dict. --- nova/api/ec2/cloud.py | 43 ++++++++++++++++++++++++------------------- nova/api/openstack/servers.py | 25 +++++++++++-------------- 2 files changed, 35 insertions(+), 33 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 6d4f58499..096ddf668 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -97,6 +97,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): @@ -846,27 +847,29 @@ 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'] + + instance_data = base_options + instance_data['mac_address'] = utils.generate_mac() + instance_data['launch_index'] = num - 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, + instance_data, + security_groups) - 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) + instance_ref['hostname'] = ec2_id + + self.compute_manager.update_instance(context, + instance_ref['id'], + instance_ref) + # 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 # can happen at the same time. address = self.network_manager.allocate_fixed_ip(context, - inst_id, + instance_ref['id'], vpn) network_topic = self._get_network_topic(context) rpc.cast(elevated, @@ -878,9 +881,9 @@ class CloudController(object): FLAGS.scheduler_topic, {"method": "run_instance", "args": {"topic": FLAGS.compute_topic, - "instance_id": inst_id}}) + "instance_id": instance_ref['id']}}) logging.debug("Casting to scheduler for %s/%s's instance %s" % - (context.project.name, context.user.name, inst_id)) + (context.project.name, context.user.name, instance_ref['id'])) return self._format_run_instances(context, reservation_id) @@ -907,11 +910,13 @@ 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}) + updated_data = {'state_description': 'terminating', + 'state': 0, + 'terminated_at': now} + self.compute_manager.update_instance(context, + instance_ref['id'], + updated_data) + # FIXME(ja): where should network deallocate occur? address = db.instance_get_floating_address(context, instance_ref['id']) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index a73591ccc..6ce364eb7 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -94,6 +94,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): @@ -241,34 +242,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, -- cgit From eecef70fcdd173cc54ad8ac7edba9e9b31855134 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Sun, 24 Oct 2010 15:37:55 -0700 Subject: add methods to cloud for rescue and unrescue --- nova/api/cloud.py | 18 ++++++++++++++++++ nova/api/ec2/cloud.py | 17 +++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/cloud.py b/nova/api/cloud.py index aa84075dc..46b342d32 100644 --- a/nova/api/cloud.py +++ b/nova/api/cloud.py @@ -36,3 +36,21 @@ 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/cloud.py b/nova/api/ec2/cloud.py index 784697b01..73f0dcc16 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -932,8 +932,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): -- cgit From 4948fed24d5e16d95f237ec95c1cd305fcc4df95 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Sun, 24 Oct 2010 16:04:35 -0700 Subject: pep 8 cleanup and typo in resize --- nova/api/cloud.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'nova/api') diff --git a/nova/api/cloud.py b/nova/api/cloud.py index 46b342d32..b8f15019f 100644 --- a/nova/api/cloud.py +++ b/nova/api/cloud.py @@ -37,6 +37,7 @@ def reboot(instance_id, context=None): {"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) @@ -46,6 +47,7 @@ def rescue(instance_id, context): {"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) -- cgit From bde0d8d0f0e864d5b5d0f87e55ab23839846f71e Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 25 Oct 2010 01:37:01 -0700 Subject: fix bugs, describe volumes, detach on terminate --- nova/api/ec2/cloud.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 784697b01..a1899c47f 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -463,24 +463,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'] + 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: -- cgit From 43a545a8bd8f763eba7741a240c29da447aef61e Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 25 Oct 2010 03:11:00 -0700 Subject: more bugfixes, flag for local volumes --- nova/api/ec2/__init__.py | 1 + nova/api/ec2/cloud.py | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index 0df4d3710..c53ce6f5e 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -238,6 +238,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 a1899c47f..7a057396c 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -467,7 +467,7 @@ class CloudController(object): instance_data = None if volume.get('instance', None): internal_id = volume['instance']['internal_id'] - ec2_id = internal_id_to_ec2_id(internal_id) + instance_ec2_id = internal_id_to_ec2_id(internal_id) instance_data = '%s[%s]' % (instance_ec2_id, volume['instance']['host']) v = {} @@ -522,7 +522,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) -- cgit From 79acdcca7d37e81d626be7a3369394ef9dface1b Mon Sep 17 00:00:00 2001 From: "jaypipes@gmail.com" <> Date: Wed, 27 Oct 2010 11:10:50 -0400 Subject: Style cleanups and review from Eric. --- nova/api/ec2/cloud.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 51e972aa7..9084958a1 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -836,29 +836,30 @@ class CloudController(object): elevated = context.elevated() for num in range(num_instances): - + instance_data = base_options - instance_data['mac_address'] = utils.generate_mac() - instance_data['launch_index'] = num instance_ref = self.compute_manager.create_instance(context, - instance_data, - security_groups) + instance_data, + security_groups, + mac_address=utils.generate_mac(), + launch_index=num) + inst_id = instance_ref['id'] internal_id = instance_ref['internal_id'] ec2_id = internal_id_to_ec2_id(internal_id) - instance_ref['hostname'] = ec2_id self.compute_manager.update_instance(context, - instance_ref['id'], - instance_ref) + inst_id, + instance_ref, + 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 # can happen at the same time. address = self.network_manager.allocate_fixed_ip(context, - instance_ref['id'], + inst_id, vpn) network_topic = self._get_network_topic(context) rpc.cast(elevated, @@ -870,9 +871,9 @@ class CloudController(object): FLAGS.scheduler_topic, {"method": "run_instance", "args": {"topic": FLAGS.compute_topic, - "instance_id": instance_ref['id']}}) + "instance_id": inst_id}}) logging.debug("Casting to scheduler for %s/%s's instance %s" % - (context.project.name, context.user.name, instance_ref['id'])) + (context.project.name, context.user.name, inst_id)) return self._format_run_instances(context, reservation_id) def terminate_instances(self, context, instance_id, **kwargs): -- cgit From 213b9987365c4b336b63e08e1ca187a43d00fa3d Mon Sep 17 00:00:00 2001 From: "jaypipes@gmail.com" <> Date: Wed, 27 Oct 2010 14:55:01 -0400 Subject: OK, let's try this one more time. --- nova/api/ec2/cloud.py | 13 ++++++------- nova/api/openstack/servers.py | 4 ++-- 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 9084958a1..7b6144ba5 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -837,13 +837,11 @@ class CloudController(object): for num in range(num_instances): - instance_data = base_options - instance_ref = self.compute_manager.create_instance(context, - instance_data, security_groups, mac_address=utils.generate_mac(), - launch_index=num) + launch_index=num, + **base_options) inst_id = instance_ref['id'] internal_id = instance_ref['internal_id'] @@ -851,7 +849,6 @@ class CloudController(object): self.compute_manager.update_instance(context, inst_id, - instance_ref, hostname=ec2_id) # TODO(vish): This probably should be done in the scheduler @@ -903,8 +900,10 @@ class CloudController(object): 'state': 0, 'terminated_at': now} self.compute_manager.update_instance(context, - instance_ref['id'], - updated_data) + 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, diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index e1a254d4e..1d8aa2fa4 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -246,11 +246,11 @@ class Controller(wsgi.Controller): inst['mac_address'] = utils.generate_mac() inst['launch_index'] = 0 - ref = self.compute_manager.create_instance(ctxt, 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) + self.compute_manager.update_instance(ctxt, inst['id'], **inst) address = self.network_manager.allocate_fixed_ip(ctxt, inst['id']) -- cgit From 4012860b57593632d1f0061099e0d211dba58a59 Mon Sep 17 00:00:00 2001 From: "jaypipes@gmail.com" <> Date: Thu, 28 Oct 2010 11:43:08 -0400 Subject: Remove unused updated_data variable --- nova/api/ec2/cloud.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 7b6144ba5..f2a6dc3b0 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -896,9 +896,6 @@ class CloudController(object): id_str) continue now = datetime.datetime.utcnow() - updated_data = {'state_description': 'terminating', - 'state': 0, - 'terminated_at': now} self.compute_manager.update_instance(context, instance_ref['id'], state_description='terminating', -- cgit From c8e2341c98ffacfafffbadb7d204f10ff87cf89c Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Mon, 1 Nov 2010 20:33:03 -0400 Subject: API endpoint documentation. --- nova/api/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/__init__.py b/nova/api/__init__.py index 8a1d9fe32..27b8199db 100644 --- a/nova/api/__init__.py +++ b/nova/api/__init__.py @@ -15,9 +15,15 @@ # 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 -- cgit From e0f889443f5c0732db28871f350c45e7c8e8d031 Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Mon, 1 Nov 2010 21:47:16 -0400 Subject: Add ec2 api docs. --- nova/api/ec2/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index 0df4d3710..816314901 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 -- cgit From 2e2dce7ebf478258f67a9122c6b158ba5e89c1ed Mon Sep 17 00:00:00 2001 From: Eric Day Date: Tue, 2 Nov 2010 11:28:14 -0700 Subject: Added support for OpenStack and EC2 APIs to run on different ports. --- nova/api/__init__.py | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) (limited to 'nova/api') diff --git a/nova/api/__init__.py b/nova/api/__init__.py index 8a1d9fe32..707c1623e 100644 --- a/nova/api/__init__.py +++ b/nova/api/__init__.py @@ -35,37 +35,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 +72,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 -- cgit From a8a61d61db0b00e0b397c807ac8ca89e39a26c5b Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Fri, 5 Nov 2010 19:52:12 -0400 Subject: Fix docstrings for wsigfied methods. --- nova/api/__init__.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'nova/api') diff --git a/nova/api/__init__.py b/nova/api/__init__.py index f693225d9..1dabd3d21 100644 --- a/nova/api/__init__.py +++ b/nova/api/__init__.py @@ -30,6 +30,7 @@ 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 @@ -83,6 +84,7 @@ class API(wsgi.Router): mapper.connect("/cloudpipe/{path_info:.*}", controller=cloudpipe.API()) super(API, self).__init__(mapper) + @utils.fix_wsgify_docstr @webob.dec.wsgify def osapi_versions(self, req): """Respond to a request for all OpenStack API versions.""" @@ -94,6 +96,7 @@ class API(wsgi.Router): "attributes": dict(version=["status", "id"])}} return wsgi.Serializer(req.environ, metadata).to_content_type(response) + @utils.fix_wsgify_docstr @webob.dec.wsgify def ec2api_versions(self, req): """Respond to a request for all EC2 versions.""" -- cgit From ff3ec33010ce8ece87523f7cf3ef2e4a0a23006e Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Mon, 15 Nov 2010 21:08:08 -0500 Subject: The docs are just going to be wrong for now. I'll file a bug upstream. --- nova/api/__init__.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/__init__.py b/nova/api/__init__.py index 1dabd3d21..7e75445a8 100644 --- a/nova/api/__init__.py +++ b/nova/api/__init__.py @@ -84,7 +84,6 @@ class API(wsgi.Router): mapper.connect("/cloudpipe/{path_info:.*}", controller=cloudpipe.API()) super(API, self).__init__(mapper) - @utils.fix_wsgify_docstr @webob.dec.wsgify def osapi_versions(self, req): """Respond to a request for all OpenStack API versions.""" @@ -96,7 +95,6 @@ class API(wsgi.Router): "attributes": dict(version=["status", "id"])}} return wsgi.Serializer(req.environ, metadata).to_content_type(response) - @utils.fix_wsgify_docstr @webob.dec.wsgify def ec2api_versions(self, req): """Respond to a request for all EC2 versions.""" -- cgit From 7b4733b36d5351a2ba42c82b4d2b821a3b1d12cd Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 16 Nov 2010 23:38:37 +0000 Subject: fixes errors in describe address and associate address. Adds test cases --- nova/api/ec2/cloud.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index fbe4caa48..e2eaa7c5c 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -679,7 +679,7 @@ class CloudController(object): context.project_id) for floating_ip_ref in iterator: address = floating_ip_ref['address'] - instance_id = None + ec2_id = None if (floating_ip_ref['fixed_ip'] and floating_ip_ref['fixed_ip']['instance']): internal_id = floating_ip_ref['fixed_ip']['instance']['ec2_id'] @@ -717,8 +717,8 @@ class CloudController(object): "args": {"floating_address": floating_ip_ref['address']}}) return {'releaseResponse': ["Address released."]} - def associate_address(self, context, ec2_id, public_ip, **kwargs): - internal_id = ec2_id_to_internal_id(ec2_id) + def associate_address(self, context, instance_id, public_ip, **kwargs): + internal_id = ec2_id_to_internal_id(instance_id) instance_ref = db.instance_get_by_internal_id(context, internal_id) fixed_address = db.instance_get_fixed_address(context, instance_ref['id']) -- cgit From 70e10503472d37f08f9f0880c87e10afc3abc851 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 18 Nov 2010 10:52:54 -0800 Subject: Make sure that the response body is a string and not unicode --- nova/api/ec2/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index b7664ec71..a6ee16c33 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -244,8 +244,8 @@ class Executor(wsgi.Application): resp = webob.Response() resp.status = 400 resp.headers['Content-Type'] = 'text/xml' - resp.body = ('\n' + resp.body = str('\n' '%s' '%s' - '?') % (code, message) + '?' % (code, message)) return resp -- cgit From 8e1b88cc228f9ed55c3b6e4fdd790a572d63e6fe Mon Sep 17 00:00:00 2001 From: Eric Day Date: Thu, 18 Nov 2010 13:27:52 -0800 Subject: First step to getting the image APIs consolidated. The EC2 API was using a one-off S3 image service wrapper, but this should be moved into the nova.image space and use the same interface as the others. There are still some mismatches between the various image service implementations, but this patch was getting large and wanted to keep it within a resonable size. --- nova/api/ec2/cloud.py | 24 ++++----- nova/api/ec2/images.py | 123 ------------------------------------------- nova/api/openstack/images.py | 13 +++-- 3 files changed, 20 insertions(+), 140 deletions(-) delete mode 100644 nova/api/ec2/images.py (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index e2eaa7c5c..9327bf0d4 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -41,7 +41,7 @@ from nova import rpc from nova import utils from nova.compute.instance_types import INSTANCE_TYPES from nova.api import cloud -from nova.api.ec2 import images +from nova.image.s3 import S3ImageService FLAGS = flags.FLAGS @@ -100,6 +100,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.image_service = S3ImageService() self.setup() def __str__(self): @@ -785,7 +786,7 @@ class CloudController(object): vpn = kwargs['image_id'] == FLAGS.vpn_image_id if not vpn: - image = images.get(context, kwargs['image_id']) + image = self.image_service.show(context, kwargs['image_id']) # FIXME(ja): if image is vpn, this breaks # get defaults from imagestore @@ -798,8 +799,8 @@ class CloudController(object): ramdisk_id = kwargs.get('ramdisk_id', ramdisk_id) # make sure we have access to kernel and ramdisk - images.get(context, kernel_id) - images.get(context, ramdisk_id) + self.image_service.show(context, kernel_id) + self.image_service.show(context, ramdisk_id) logging.debug("Going to run %s instances...", num_instances) launch_time = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()) @@ -993,20 +994,17 @@ class CloudController(object): return True def describe_images(self, context, image_id=None, **kwargs): - # The objectstore does its own authorization for describe - imageSet = images.list(context, image_id) + imageSet = self.image_service.index(context, image_id) return {'imagesSet': imageSet} def deregister_image(self, context, image_id, **kwargs): - # FIXME: should the objectstore be doing these authorization checks? - images.deregister(context, image_id) + self.image_service.deregister(context, image_id) return {'imageId': image_id} def register_image(self, context, image_location=None, **kwargs): - # FIXME: should the objectstore be doing these authorization checks? if image_location is None and 'name' in kwargs: image_location = kwargs['name'] - image_id = images.register(context, image_location) + image_id = self.image_service.register(context, image_location) logging.debug("Registered %s as %s" % (image_location, image_id)) return {'imageId': image_id} @@ -1014,7 +1012,7 @@ class CloudController(object): if attribute != 'launchPermission': raise exception.ApiError('attribute not supported: %s' % attribute) try: - image = images.list(context, image_id)[0] + image = self.image_service.show(context, image_id) except IndexError: raise exception.ApiError('invalid id: %s' % image_id) result = {'image_id': image_id, 'launchPermission': []} @@ -1033,8 +1031,8 @@ class CloudController(object): raise exception.ApiError('only group "all" is supported') if not operation_type in ['add', 'remove']: raise exception.ApiError('operation_type must be add or remove') - return images.modify(context, image_id, operation_type) + return self.image_service.modify(context, image_id, operation_type) def update_image(self, context, image_id, **kwargs): - result = images.update(context, image_id, dict(kwargs)) + result = self.image_service.update(context, image_id, dict(kwargs)) return result diff --git a/nova/api/ec2/images.py b/nova/api/ec2/images.py deleted file mode 100644 index 60f9008e9..000000000 --- a/nova/api/ec2/images.py +++ /dev/null @@ -1,123 +0,0 @@ -# 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. -# -# 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 -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Proxy AMI-related calls from the cloud controller, to the running -objectstore service. -""" - -import json -import urllib - -import boto.s3.connection - -from nova import exception -from nova import flags -from nova import utils -from nova.auth import manager - - -FLAGS = flags.FLAGS - - -def modify(context, image_id, operation): - conn(context).make_request( - method='POST', - bucket='_images', - query_args=qs({'image_id': image_id, 'operation': operation})) - - return True - - -def update(context, image_id, attributes): - """update an image's attributes / info.json""" - attributes.update({"image_id": image_id}) - conn(context).make_request( - method='POST', - bucket='_images', - query_args=qs(attributes)) - return True - - -def register(context, image_location): - """ rpc call to register a new image based from a manifest """ - - image_id = utils.generate_uid('ami') - conn(context).make_request( - method='PUT', - bucket='_images', - query_args=qs({'image_location': image_location, - 'image_id': image_id})) - - return image_id - - -def list(context, filter_list=[]): - """ return a list of all images that a user can see - - optionally filtered by a list of image_id """ - - if FLAGS.connection_type == 'fake': - return [{'imageId': 'bar'}] - - # FIXME: send along the list of only_images to check for - response = conn(context).make_request( - method='GET', - bucket='_images') - - result = json.loads(response.read()) - if not filter_list is None: - return [i for i in result if i['imageId'] in filter_list] - return result - - -def get(context, image_id): - """return a image object if the context has permissions""" - result = list(context, [image_id]) - if not result: - raise exception.NotFound('Image %s could not be found' % image_id) - image = result[0] - return image - - -def deregister(context, image_id): - """ unregister an image """ - conn(context).make_request( - method='DELETE', - bucket='_images', - query_args=qs({'image_id': image_id})) - - -def conn(context): - access = manager.AuthManager().get_access_key(context.user, - context.project) - secret = str(context.user.secret) - calling = boto.s3.connection.OrdinaryCallingFormat() - return boto.s3.connection.S3Connection(aws_access_key_id=access, - aws_secret_access_key=secret, - is_secure=False, - calling_format=calling, - port=FLAGS.s3_port, - host=FLAGS.s3_host) - - -def qs(params): - pairs = [] - for key in params.keys(): - pairs.append(key + '=' + urllib.quote(params[key])) - return '&'.join(pairs) diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index 5bc915e63..cdbdc9bdd 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -17,6 +17,7 @@ from webob import exc +from nova import context from nova import flags from nova import utils from nova import wsgi @@ -46,19 +47,23 @@ class Controller(wsgi.Controller): def detail(self, req): """Return all public images in detail.""" + user_id = req.environ['nova.context']['user']['id'] + ctxt = context.RequestContext(user_id, user_id) try: - images = self._service.detail() + images = self._service.detail(ctxt) images = nova.api.openstack.limited(images, req) except NotImplementedError: # Emulate detail() using repeated calls to show() - images = self._service.index() + images = self._service.index(ctxt) images = nova.api.openstack.limited(images, req) - images = [self._service.show(i['id']) for i in images] + images = [self._service.show(ctxt, i['id']) for i in images] return dict(images=images) def show(self, req, id): """Return data about the given image id.""" - return dict(image=self._service.show(id)) + user_id = req.environ['nova.context']['user']['id'] + ctxt = context.RequestContext(user_id, user_id) + return dict(image=self._service.show(ctxt, id)) def delete(self, req, id): # Only public images are supported for now. -- cgit From 9c57e5ce37c1f2405fcf7a1ba322946e6d84efeb Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Tue, 23 Nov 2010 12:46:07 -0600 Subject: Remove FAKE_subdomain from docs --- nova/api/__init__.py | 1 - 1 file changed, 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/__init__.py b/nova/api/__init__.py index 7e75445a8..80f9f2109 100644 --- a/nova/api/__init__.py +++ b/nova/api/__init__.py @@ -22,7 +22,6 @@ Root WSGI middleware for all API controllers. :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 """ -- cgit