From ca7bf95e610bdc47f01b8fb7b459269bb8e5df66 Mon Sep 17 00:00:00 2001 From: Tushar Patil Date: Thu, 11 Aug 2011 18:11:59 -0700 Subject: Initial version --- nova/api/__init__.py | 6 ++ nova/api/ec2/__init__.py | 3 - nova/api/openstack/create_instance_helper.py | 4 +- nova/api/openstack/userdatarequesthandler.py | 110 +++++++++++++++++++++ nova/network/linux_net.py | 5 + nova/tests/api/openstack/fakes.py | 2 + .../api/openstack/test_userdatarequesthandler.py | 80 +++++++++++++++ 7 files changed, 206 insertions(+), 4 deletions(-) create mode 100644 nova/api/openstack/userdatarequesthandler.py create mode 100644 nova/tests/api/openstack/test_userdatarequesthandler.py diff --git a/nova/api/__init__.py b/nova/api/__init__.py index 747015af5..6e6b092b3 100644 --- a/nova/api/__init__.py +++ b/nova/api/__init__.py @@ -15,3 +15,9 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. +from nova import flags + + +flags.DEFINE_boolean('use_forwarded_for', False, + 'Treat X-Forwarded-For as the canonical remote address. ' + 'Only enable this if you have a sanitizing proxy.') diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index 8b6e47cfb..e497b499a 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -37,9 +37,6 @@ from nova.auth import manager FLAGS = flags.FLAGS LOG = logging.getLogger("nova.api") -flags.DEFINE_boolean('use_forwarded_for', False, - 'Treat X-Forwarded-For as the canonical remote address. ' - 'Only enable this if you have a sanitizing proxy.') flags.DEFINE_integer('lockout_attempts', 5, 'Number of failed auths before lockout.') flags.DEFINE_integer('lockout_minutes', 15, diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py index 1425521a9..144697790 100644 --- a/nova/api/openstack/create_instance_helper.py +++ b/nova/api/openstack/create_instance_helper.py @@ -122,6 +122,7 @@ class CreateInstanceHelper(object): raise exc.HTTPBadRequest(explanation=msg) zone_blob = server_dict.get('blob') + user_data = server_dict.get('user_data') name = server_dict['name'] self._validate_server_name(name) name = name.strip() @@ -161,7 +162,8 @@ class CreateInstanceHelper(object): zone_blob=zone_blob, reservation_id=reservation_id, min_count=min_count, - max_count=max_count)) + max_count=max_count, + user_data=user_data)) except quota.QuotaError as error: self._handle_quota_error(error) except exception.ImageNotFound as error: diff --git a/nova/api/openstack/userdatarequesthandler.py b/nova/api/openstack/userdatarequesthandler.py new file mode 100644 index 000000000..5daa37e95 --- /dev/null +++ b/nova/api/openstack/userdatarequesthandler.py @@ -0,0 +1,110 @@ +# 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. + +"""User data request handler.""" + +import base64 +import webob.dec +import webob.exc + +from nova import log as logging +from nova import context +from nova import exception +from nova import db +from nova import flags +from nova import wsgi + + +LOG = logging.getLogger('nova.api.openstack.userdata') +FLAGS = flags.FLAGS + + +class Controller(object): + """ The server user-data API controller for the Openstack API """ + + def __init__(self): + super(Controller, self).__init__() + + @staticmethod + def _format_user_data(instance_ref): + return base64.b64decode(instance_ref['user_data']) + + def get_user_data(self, address): + ctxt = context.get_admin_context() + try: + instance_ref = db.instance_get_by_fixed_ip(ctxt, address) + except exception.NotFound: + instance_ref = None + if not instance_ref: + return None + + data = {'user-data': self._format_user_data(instance_ref)} + return data + + +class UserdataRequestHandler(wsgi.Application): + """Serve user-data from the OS API.""" + + def __init__(self): + self.cc = Controller() + + def print_data(self, data): + if isinstance(data, dict): + output = '' + for key in data: + if key == '_name': + continue + output += key + if isinstance(data[key], dict): + if '_name' in data[key]: + output += '=' + str(data[key]['_name']) + else: + output += '/' + output += '\n' + # Cut off last \n + return output[:-1] + elif isinstance(data, list): + return '\n'.join(data) + else: + return str(data) + + def lookup(self, path, data): + items = path.split('/') + for item in items: + if item: + if not isinstance(data, dict): + return data + if not item in data: + return None + data = data[item] + return data + + @webob.dec.wsgify(RequestClass=wsgi.Request) + def __call__(self, req): + remote_address = "10.0.1.6"#req.remote_addr + if FLAGS.use_forwarded_for: + remote_address = req.headers.get('X-Forwarded-For', remote_address) + + data = self.cc.get_user_data(remote_address) + if data is None: + LOG.error(_('Failed to get user data for ip: %s'), remote_address) + raise webob.exc.HTTPNotFound() + data = self.lookup(req.path_info, data) + if data is None: + raise webob.exc.HTTPNotFound() + return self.print_data(data) diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index 4e1e1f85a..d8fff8a32 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -371,6 +371,11 @@ def metadata_forward(): '-p tcp -m tcp --dport 80 -j DNAT ' '--to-destination %s:%s' % \ (FLAGS.ec2_dmz_host, FLAGS.ec2_port)) + iptables_manager.ipv4['nat'].add_rule('PREROUTING', + '-s 0.0.0.0/0 -d 169.254.169.253/32 ' + '-p tcp -m tcp --dport 80 -j DNAT ' + '--to-destination %s:%s' % \ + (FLAGS.osapi_host, FLAGS.osapi_port)) iptables_manager.apply() diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py index d11fbf788..aa5aeef16 100644 --- a/nova/tests/api/openstack/fakes.py +++ b/nova/tests/api/openstack/fakes.py @@ -36,6 +36,7 @@ from nova.api.openstack import auth from nova.api.openstack import extensions from nova.api.openstack import versions from nova.api.openstack import limits +from nova.api.openstack import userdatarequesthandler from nova.auth.manager import User, Project import nova.image.fake from nova.image import glance @@ -99,6 +100,7 @@ def wsgi_app(inner_app10=None, inner_app11=None, fake_auth=True, mapper['/v1.0'] = api10 mapper['/v1.1'] = api11 mapper['/'] = openstack.FaultWrapper(versions.Versions()) + mapper['/latest'] = userdatarequesthandler.UserdataRequestHandler() return mapper diff --git a/nova/tests/api/openstack/test_userdatarequesthandler.py b/nova/tests/api/openstack/test_userdatarequesthandler.py new file mode 100644 index 000000000..0c63076b4 --- /dev/null +++ b/nova/tests/api/openstack/test_userdatarequesthandler.py @@ -0,0 +1,80 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010-2011 OpenStack LLC. +# 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. + +import base64 +import json +import unittest +import webob + +from nova import context +from nova import db +from nova import exception +from nova import flags +from nova import test +from nova import log as logging + +from nova.tests.api.openstack import fakes + +LOG = logging.getLogger('nova.api.openstack.userdata') + +USER_DATA_STRING = ("This is an encoded string") +ENCODE_STRING = base64.b64encode(USER_DATA_STRING) + + +def return_server_by_address(context, address): + instance = {"user_data": ENCODE_STRING} + instance["fixed_ips"] = {"address": address, + "floating_ips": []} + return instance + + +def return_non_existing_server_by_address(context, address): + raise exception.NotFound() + + +class TestUserdatarequesthandler(test.TestCase): + + def setUp(self): + super(TestUserdatarequesthandler, self).setUp() + self.stubs.Set(db, 'instance_get_by_fixed_ip', + return_server_by_address) + + def test_user_data(self): + req = webob.Request.blank('/latest/user-data') + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 200) + self.assertEqual(res.body, USER_DATA_STRING) + + def test_user_data_non_existing_fixed_address(self): + self.stubs.Set(db, 'instance_get_by_fixed_ip', + return_non_existing_server_by_address) + self.flags(use_forwarded_for=False) + req = webob.Request.blank('/latest/user-data') + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 404) + + def test_user_data_invalid_url(self): + req = webob.Request.blank('/latest/user-data-invalid') + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 404) + + def test_user_data_with_use_forwarded_header(self): + self.flags(use_forwarded_for=True) + req = webob.Request.blank('/latest/user-data') + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 200) + self.assertEqual(res.body, USER_DATA_STRING) -- cgit From 7507ba23004c989c75962c47efbd2ce5e5178a90 Mon Sep 17 00:00:00 2001 From: Tushar Patil Date: Thu, 11 Aug 2011 18:22:35 -0700 Subject: added userdata entry in the api paste ini --- etc/nova/api-paste.ini | 7 +++++++ nova/api/openstack/userdatarequesthandler.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/etc/nova/api-paste.ini b/etc/nova/api-paste.ini index abe8c20c4..46a3b0af9 100644 --- a/etc/nova/api-paste.ini +++ b/etc/nova/api-paste.ini @@ -69,6 +69,7 @@ use = egg:Paste#urlmap /: osversions /v1.0: openstackapi10 /v1.1: openstackapi11 +/latest: osuserdata [pipeline:openstackapi10] pipeline = faultwrap auth ratelimit osapiapp10 @@ -76,6 +77,9 @@ pipeline = faultwrap auth ratelimit osapiapp10 [pipeline:openstackapi11] pipeline = faultwrap auth ratelimit extensions osapiapp11 +[pipeline:osuserdata] +pipeline = logrequest osappud + [filter:faultwrap] paste.filter_factory = nova.api.openstack:FaultWrapper.factory @@ -99,3 +103,6 @@ pipeline = faultwrap osversionapp [app:osversionapp] paste.app_factory = nova.api.openstack.versions:Versions.factory + +[app:osappud] +paste.app_factory = nova.api.openstack.userdatarequesthandler:UserdataRequestHandler.factory diff --git a/nova/api/openstack/userdatarequesthandler.py b/nova/api/openstack/userdatarequesthandler.py index 5daa37e95..f0205419b 100644 --- a/nova/api/openstack/userdatarequesthandler.py +++ b/nova/api/openstack/userdatarequesthandler.py @@ -96,7 +96,7 @@ class UserdataRequestHandler(wsgi.Application): @webob.dec.wsgify(RequestClass=wsgi.Request) def __call__(self, req): - remote_address = "10.0.1.6"#req.remote_addr + remote_address = req.remote_addr if FLAGS.use_forwarded_for: remote_address = req.headers.get('X-Forwarded-For', remote_address) -- cgit From 8666aca320ce95840a378231bfe81bc4e759df6e Mon Sep 17 00:00:00 2001 From: Tushar Patil Date: Mon, 15 Aug 2011 11:50:54 -0700 Subject: Fixed merging issue --- nova/api/openstack/create_instance_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py index 7e9d48c02..c8798536e 100644 --- a/nova/api/openstack/create_instance_helper.py +++ b/nova/api/openstack/create_instance_helper.py @@ -164,7 +164,7 @@ class CreateInstanceHelper(object): reservation_id=reservation_id, min_count=min_count, max_count=max_count, - user_data=user_data)) + user_data=user_data, availability_zone=availability_zone)) except quota.QuotaError as error: self._handle_quota_error(error) -- cgit From 066b675e3ce5c2bd67dde124cbe01b68bd1eded8 Mon Sep 17 00:00:00 2001 From: John Tran Date: Mon, 15 Aug 2011 13:22:14 -0700 Subject: fix bug which DescribeInstances in EC2 api was returning deleted instances --- nova/db/sqlalchemy/api.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index e5d35a20b..e7b71d494 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1209,7 +1209,8 @@ def instance_get_all_by_filters(context, filters): options(joinedload('security_groups')).\ options(joinedload_all('fixed_ips.network')).\ options(joinedload('metadata')).\ - options(joinedload('instance_type')) + options(joinedload('instance_type')).\ + filter_by(deleted=can_read_deleted(context)) # Make a copy of the filters dictionary to use going forward, as we'll # be modifying it and we shouldn't affect the caller's use of it. -- cgit From f06f80591a41f5d1b373677937bbbcddcfb0bb7c Mon Sep 17 00:00:00 2001 From: John Tran Date: Mon, 15 Aug 2011 13:48:09 -0700 Subject: added cloud unit test for describe_instances to ensure doesn't return deleted instances --- nova/tests/test_cloud.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index b2afc53c9..07a35c447 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -487,6 +487,16 @@ class CloudTestCase(test.TestCase): db.service_destroy(self.context, comp1['id']) db.service_destroy(self.context, comp2['id']) + def test_describe_instances_deleted(self): + args = {'reservation_id': 'a', 'image_ref': 1, 'host': 'host1'} + inst1 = db.instance_create(self.context, args) + inst2 = db.instance_create(self.context, args) + db.instance_destroy(self.context, inst1.id) + result = self.cloud.describe_instances(self.context) + result = result['reservationSet'][0]['instancesSet'] + print result + self.assertEqual(1, len(result)) + def _block_device_mapping_create(self, instance_id, mappings): volumes = [] for bdm in mappings: -- cgit From 3e561f148fcba627f8fbd4ab1089f426fbc2e61b Mon Sep 17 00:00:00 2001 From: John Tran Date: Mon, 15 Aug 2011 13:58:44 -0700 Subject: adding sqlalchemi api tests for test_instance_get_all_by_filter to ensure doesn't return deleted instances --- nova/tests/test_cloud.py | 1 - nova/tests/test_db_api.py | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index 07a35c447..39358eeff 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -494,7 +494,6 @@ class CloudTestCase(test.TestCase): db.instance_destroy(self.context, inst1.id) result = self.cloud.describe_instances(self.context) result = result['reservationSet'][0]['instancesSet'] - print result self.assertEqual(1, len(result)) def _block_device_mapping_create(self, instance_id, mappings): diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py index 0c07cbb7c..ed363d1be 100644 --- a/nova/tests/test_db_api.py +++ b/nova/tests/test_db_api.py @@ -76,3 +76,18 @@ class DbApiTestCase(test.TestCase): self.assertEqual(instance['id'], result['id']) self.assertEqual(result['fixed_ips'][0]['floating_ips'][0].address, '1.2.1.2') + + def test_instance_get_all_by_filters(self): + args = {'reservation_id': 'a', 'image_ref': 1, 'host': 'host1'} + inst1 = db.instance_create(self.context, args) + inst2 = db.instance_create(self.context, args) + result = db.instance_get_all_by_filters(self.context, {}) + self.assertTrue(2, len(result)) + + def test_instance_get_all_by_filters_deleted(self): + args = {'reservation_id': 'a', 'image_ref': 1, 'host': 'host1'} + inst1 = db.instance_create(self.context, args) + inst2 = db.instance_create(self.context, args) + db.instance_destroy(self.context, inst1.id) + result = db.instance_get_all_by_filters(self.context, {}) + self.assertTrue(1, len(result)) -- cgit From 9a4b1deb5f9abdc88809ff80bccdfb503e66dccd Mon Sep 17 00:00:00 2001 From: Tushar Patil Date: Mon, 15 Aug 2011 15:09:42 -0700 Subject: Removed newly added userdatarequesthandler for OS API, there is no need to add this handler since the existing Ec2 API metadatarequesthandler does the same job --- etc/nova/api-paste.ini | 7 -- nova/api/__init__.py | 6 -- nova/api/ec2/__init__.py | 3 + nova/api/openstack/userdatarequesthandler.py | 110 --------------------- nova/network/linux_net.py | 5 - nova/tests/api/openstack/fakes.py | 2 - .../api/openstack/test_userdatarequesthandler.py | 80 --------------- 7 files changed, 3 insertions(+), 210 deletions(-) delete mode 100644 nova/api/openstack/userdatarequesthandler.py delete mode 100644 nova/tests/api/openstack/test_userdatarequesthandler.py diff --git a/etc/nova/api-paste.ini b/etc/nova/api-paste.ini index 46a3b0af9..abe8c20c4 100644 --- a/etc/nova/api-paste.ini +++ b/etc/nova/api-paste.ini @@ -69,7 +69,6 @@ use = egg:Paste#urlmap /: osversions /v1.0: openstackapi10 /v1.1: openstackapi11 -/latest: osuserdata [pipeline:openstackapi10] pipeline = faultwrap auth ratelimit osapiapp10 @@ -77,9 +76,6 @@ pipeline = faultwrap auth ratelimit osapiapp10 [pipeline:openstackapi11] pipeline = faultwrap auth ratelimit extensions osapiapp11 -[pipeline:osuserdata] -pipeline = logrequest osappud - [filter:faultwrap] paste.filter_factory = nova.api.openstack:FaultWrapper.factory @@ -103,6 +99,3 @@ pipeline = faultwrap osversionapp [app:osversionapp] paste.app_factory = nova.api.openstack.versions:Versions.factory - -[app:osappud] -paste.app_factory = nova.api.openstack.userdatarequesthandler:UserdataRequestHandler.factory diff --git a/nova/api/__init__.py b/nova/api/__init__.py index 6e6b092b3..747015af5 100644 --- a/nova/api/__init__.py +++ b/nova/api/__init__.py @@ -15,9 +15,3 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. -from nova import flags - - -flags.DEFINE_boolean('use_forwarded_for', False, - 'Treat X-Forwarded-For as the canonical remote address. ' - 'Only enable this if you have a sanitizing proxy.') diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index 2e9278b52..96df97393 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -37,6 +37,9 @@ from nova.auth import manager FLAGS = flags.FLAGS LOG = logging.getLogger("nova.api") +flags.DEFINE_boolean('use_forwarded_for', False, + 'Treat X-Forwarded-For as the canonical remote address. ' + 'Only enable this if you have a sanitizing proxy.') flags.DEFINE_integer('lockout_attempts', 5, 'Number of failed auths before lockout.') flags.DEFINE_integer('lockout_minutes', 15, diff --git a/nova/api/openstack/userdatarequesthandler.py b/nova/api/openstack/userdatarequesthandler.py deleted file mode 100644 index f0205419b..000000000 --- a/nova/api/openstack/userdatarequesthandler.py +++ /dev/null @@ -1,110 +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. - -"""User data request handler.""" - -import base64 -import webob.dec -import webob.exc - -from nova import log as logging -from nova import context -from nova import exception -from nova import db -from nova import flags -from nova import wsgi - - -LOG = logging.getLogger('nova.api.openstack.userdata') -FLAGS = flags.FLAGS - - -class Controller(object): - """ The server user-data API controller for the Openstack API """ - - def __init__(self): - super(Controller, self).__init__() - - @staticmethod - def _format_user_data(instance_ref): - return base64.b64decode(instance_ref['user_data']) - - def get_user_data(self, address): - ctxt = context.get_admin_context() - try: - instance_ref = db.instance_get_by_fixed_ip(ctxt, address) - except exception.NotFound: - instance_ref = None - if not instance_ref: - return None - - data = {'user-data': self._format_user_data(instance_ref)} - return data - - -class UserdataRequestHandler(wsgi.Application): - """Serve user-data from the OS API.""" - - def __init__(self): - self.cc = Controller() - - def print_data(self, data): - if isinstance(data, dict): - output = '' - for key in data: - if key == '_name': - continue - output += key - if isinstance(data[key], dict): - if '_name' in data[key]: - output += '=' + str(data[key]['_name']) - else: - output += '/' - output += '\n' - # Cut off last \n - return output[:-1] - elif isinstance(data, list): - return '\n'.join(data) - else: - return str(data) - - def lookup(self, path, data): - items = path.split('/') - for item in items: - if item: - if not isinstance(data, dict): - return data - if not item in data: - return None - data = data[item] - return data - - @webob.dec.wsgify(RequestClass=wsgi.Request) - def __call__(self, req): - remote_address = req.remote_addr - if FLAGS.use_forwarded_for: - remote_address = req.headers.get('X-Forwarded-For', remote_address) - - data = self.cc.get_user_data(remote_address) - if data is None: - LOG.error(_('Failed to get user data for ip: %s'), remote_address) - raise webob.exc.HTTPNotFound() - data = self.lookup(req.path_info, data) - if data is None: - raise webob.exc.HTTPNotFound() - return self.print_data(data) diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index d8fff8a32..4e1e1f85a 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -371,11 +371,6 @@ def metadata_forward(): '-p tcp -m tcp --dport 80 -j DNAT ' '--to-destination %s:%s' % \ (FLAGS.ec2_dmz_host, FLAGS.ec2_port)) - iptables_manager.ipv4['nat'].add_rule('PREROUTING', - '-s 0.0.0.0/0 -d 169.254.169.253/32 ' - '-p tcp -m tcp --dport 80 -j DNAT ' - '--to-destination %s:%s' % \ - (FLAGS.osapi_host, FLAGS.osapi_port)) iptables_manager.apply() diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py index aa5aeef16..d11fbf788 100644 --- a/nova/tests/api/openstack/fakes.py +++ b/nova/tests/api/openstack/fakes.py @@ -36,7 +36,6 @@ from nova.api.openstack import auth from nova.api.openstack import extensions from nova.api.openstack import versions from nova.api.openstack import limits -from nova.api.openstack import userdatarequesthandler from nova.auth.manager import User, Project import nova.image.fake from nova.image import glance @@ -100,7 +99,6 @@ def wsgi_app(inner_app10=None, inner_app11=None, fake_auth=True, mapper['/v1.0'] = api10 mapper['/v1.1'] = api11 mapper['/'] = openstack.FaultWrapper(versions.Versions()) - mapper['/latest'] = userdatarequesthandler.UserdataRequestHandler() return mapper diff --git a/nova/tests/api/openstack/test_userdatarequesthandler.py b/nova/tests/api/openstack/test_userdatarequesthandler.py deleted file mode 100644 index 0c63076b4..000000000 --- a/nova/tests/api/openstack/test_userdatarequesthandler.py +++ /dev/null @@ -1,80 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010-2011 OpenStack LLC. -# 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. - -import base64 -import json -import unittest -import webob - -from nova import context -from nova import db -from nova import exception -from nova import flags -from nova import test -from nova import log as logging - -from nova.tests.api.openstack import fakes - -LOG = logging.getLogger('nova.api.openstack.userdata') - -USER_DATA_STRING = ("This is an encoded string") -ENCODE_STRING = base64.b64encode(USER_DATA_STRING) - - -def return_server_by_address(context, address): - instance = {"user_data": ENCODE_STRING} - instance["fixed_ips"] = {"address": address, - "floating_ips": []} - return instance - - -def return_non_existing_server_by_address(context, address): - raise exception.NotFound() - - -class TestUserdatarequesthandler(test.TestCase): - - def setUp(self): - super(TestUserdatarequesthandler, self).setUp() - self.stubs.Set(db, 'instance_get_by_fixed_ip', - return_server_by_address) - - def test_user_data(self): - req = webob.Request.blank('/latest/user-data') - res = req.get_response(fakes.wsgi_app()) - self.assertEqual(res.status_int, 200) - self.assertEqual(res.body, USER_DATA_STRING) - - def test_user_data_non_existing_fixed_address(self): - self.stubs.Set(db, 'instance_get_by_fixed_ip', - return_non_existing_server_by_address) - self.flags(use_forwarded_for=False) - req = webob.Request.blank('/latest/user-data') - res = req.get_response(fakes.wsgi_app()) - self.assertEqual(res.status_int, 404) - - def test_user_data_invalid_url(self): - req = webob.Request.blank('/latest/user-data-invalid') - res = req.get_response(fakes.wsgi_app()) - self.assertEqual(res.status_int, 404) - - def test_user_data_with_use_forwarded_header(self): - self.flags(use_forwarded_for=True) - req = webob.Request.blank('/latest/user-data') - res = req.get_response(fakes.wsgi_app()) - self.assertEqual(res.status_int, 200) - self.assertEqual(res.body, USER_DATA_STRING) -- cgit From ca13037d2cd130f5b970d3af219566f3a70a9cb5 Mon Sep 17 00:00:00 2001 From: John Tran Date: Tue, 16 Aug 2011 09:18:13 -0700 Subject: test improvements per peer review --- nova/tests/test_cloud.py | 10 ++++++---- nova/tests/test_db_api.py | 12 +++++++----- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index 39358eeff..0793784f8 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -488,13 +488,15 @@ class CloudTestCase(test.TestCase): db.service_destroy(self.context, comp2['id']) def test_describe_instances_deleted(self): - args = {'reservation_id': 'a', 'image_ref': 1, 'host': 'host1'} - inst1 = db.instance_create(self.context, args) - inst2 = db.instance_create(self.context, args) + args1 = {'reservation_id': 'a', 'image_ref': 1, 'host': 'host1'} + inst1 = db.instance_create(self.context, args1) + args2 = {'reservation_id': 'b', 'image_ref': 1, 'host': 'host1'} + inst2 = db.instance_create(self.context, args2) db.instance_destroy(self.context, inst1.id) result = self.cloud.describe_instances(self.context) result = result['reservationSet'][0]['instancesSet'] - self.assertEqual(1, len(result)) + self.assertEqual(result[0]['instanceId'], + ec2utils.id_to_ec2_id(inst2.id)) def _block_device_mapping_create(self, instance_id, mappings): volumes = [] diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py index ed363d1be..038c07f40 100644 --- a/nova/tests/test_db_api.py +++ b/nova/tests/test_db_api.py @@ -85,9 +85,11 @@ class DbApiTestCase(test.TestCase): self.assertTrue(2, len(result)) def test_instance_get_all_by_filters_deleted(self): - args = {'reservation_id': 'a', 'image_ref': 1, 'host': 'host1'} - inst1 = db.instance_create(self.context, args) - inst2 = db.instance_create(self.context, args) + args1 = {'reservation_id': 'a', 'image_ref': 1, 'host': 'host1'} + inst1 = db.instance_create(self.context, args1) + args2 = {'reservation_id': 'b', 'image_ref': 1, 'host': 'host1'} + inst2 = db.instance_create(self.context, args2) db.instance_destroy(self.context, inst1.id) - result = db.instance_get_all_by_filters(self.context, {}) - self.assertTrue(1, len(result)) + result = db.instance_get_all_by_filters(self.context.elevated(), {}) + self.assertEqual(1, len(result)) + self.assertEqual(result[0].id, inst2.id) -- cgit From af9681bc82d7509cb2f65d213bd4d8ae24286663 Mon Sep 17 00:00:00 2001 From: "matt.dietz@rackspace.com" <> Date: Thu, 18 Aug 2011 13:47:09 -0500 Subject: Moved compute calls to their own handler --- nova/compute/api.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index e909e9959..0c5d4349d 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1068,14 +1068,20 @@ class API(base.Base): """Unpause the given instance.""" self._cast_compute_message('unpause_instance', context, instance_id) + def _make_compute_call_for_host(self context, host, params): + """Call method deliberately designed to make host/service only calls""" + queue = self.db.queue_get_for(context, FLAGS.compute_topic, host) + kwargs = {'method': method, 'args': params} + return rpc.call(context, queue, kwargs) + def set_host_enabled(self, context, host, enabled): """Sets the specified host's ability to accept new instances.""" - return self._call_compute_message("set_host_enabled", context, + return self._make_compute_call_for_host("set_host_enabled", context, host=host, params={"enabled": enabled}) def host_power_action(self, context, host, action): """Reboots, shuts down or powers up the host.""" - return self._call_compute_message("host_power_action", context, + return self._make_compute_call_for_host("host_power_action", context, host=host, params={"action": action}) @scheduler_api.reroute_compute("diagnostics") -- cgit From 69996e83f10387b83bdc7e5e76b62fe67ea6c2ab Mon Sep 17 00:00:00 2001 From: "matt.dietz@rackspace.com" <> Date: Thu, 18 Aug 2011 13:55:38 -0500 Subject: Syntax error --- nova/compute/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index 0c5d4349d..3110cd92d 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1068,7 +1068,7 @@ class API(base.Base): """Unpause the given instance.""" self._cast_compute_message('unpause_instance', context, instance_id) - def _make_compute_call_for_host(self context, host, params): + def _make_compute_call_for_host(self, context, host, params): """Call method deliberately designed to make host/service only calls""" queue = self.db.queue_get_for(context, FLAGS.compute_topic, host) kwargs = {'method': method, 'args': params} -- cgit From 19495e51bc86bf1bc333759e3825ab4b5592ff66 Mon Sep 17 00:00:00 2001 From: Matt Dietz Date: Thu, 18 Aug 2011 19:40:59 +0000 Subject: Need to pass the action --- nova/compute/api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index 3110cd92d..598270ba1 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1068,10 +1068,10 @@ class API(base.Base): """Unpause the given instance.""" self._cast_compute_message('unpause_instance', context, instance_id) - def _make_compute_call_for_host(self, context, host, params): + def _make_compute_call_for_host(self, action, context, host, params): """Call method deliberately designed to make host/service only calls""" queue = self.db.queue_get_for(context, FLAGS.compute_topic, host) - kwargs = {'method': method, 'args': params} + kwargs = {'method': action, 'args': params} return rpc.call(context, queue, kwargs) def set_host_enabled(self, context, host, enabled): -- cgit From 56129e4a0b0c5cb2f8766e023bcaff77fc990008 Mon Sep 17 00:00:00 2001 From: Tushar Patil Date: Thu, 18 Aug 2011 13:45:45 -0700 Subject: Added more unit testcases for userdata functionality --- nova/tests/test_metadata.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/nova/tests/test_metadata.py b/nova/tests/test_metadata.py index bfc7a6d44..b06e5c136 100644 --- a/nova/tests/test_metadata.py +++ b/nova/tests/test_metadata.py @@ -23,12 +23,21 @@ import httplib import webob +from nova import exception from nova import test from nova import wsgi from nova.api.ec2 import metadatarequesthandler from nova.db.sqlalchemy import api +USER_DATA_STRING = ("This is an encoded string") +ENCODE_USER_DATA_STRING = base64.b64encode(USER_DATA_STRING) + + +def return_non_existing_server_by_address(context, address): + raise exception.NotFound() + + class MetadataTestCase(test.TestCase): """Test that metadata is returning proper values.""" @@ -79,3 +88,34 @@ class MetadataTestCase(test.TestCase): self.stubs.Set(api, 'security_group_get_by_instance', sg_get) self.assertEqual(self.request('/meta-data/security-groups'), 'default\nother') + + def test_user_data_non_existing_fixed_address(self): + self.stubs.Set(api, 'instance_get_all_by_filters', + return_non_existing_server_by_address) + request = webob.Request.blank('/user-data') + request.remote_addr = "127.1.1.1" + response = request.get_response(self.app) + self.assertEqual(response.status_int, 404) + + def test_user_data_none_fixed_address(self): + self.stubs.Set(api, 'instance_get_all_by_filters', + return_non_existing_server_by_address) + request = webob.Request.blank('/user-data') + request.remote_addr = None + response = request.get_response(self.app) + self.assertEqual(response.status_int, 500) + + def test_user_data_invalid_url(self): + request = webob.Request.blank('/user-data-invalid') + request.remote_addr = "127.0.0.1" + response = request.get_response(self.app) + self.assertEqual(response.status_int, 404) + + def test_user_data_with_use_forwarded_header(self): + self.instance['user_data'] = ENCODE_USER_DATA_STRING + self.flags(use_forwarded_for=True) + request = webob.Request.blank('/user-data') + request.remote_addr = "127.0.0.1" + response = request.get_response(self.app) + self.assertEqual(response.status_int, 200) + self.assertEqual(response.body, USER_DATA_STRING) -- cgit