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
This commit is contained in:
@@ -69,7 +69,6 @@ use = egg:Paste#urlmap
|
|||||||
/: osversions
|
/: osversions
|
||||||
/v1.0: openstackapi10
|
/v1.0: openstackapi10
|
||||||
/v1.1: openstackapi11
|
/v1.1: openstackapi11
|
||||||
/latest: osuserdata
|
|
||||||
|
|
||||||
[pipeline:openstackapi10]
|
[pipeline:openstackapi10]
|
||||||
pipeline = faultwrap auth ratelimit osapiapp10
|
pipeline = faultwrap auth ratelimit osapiapp10
|
||||||
@@ -77,9 +76,6 @@ pipeline = faultwrap auth ratelimit osapiapp10
|
|||||||
[pipeline:openstackapi11]
|
[pipeline:openstackapi11]
|
||||||
pipeline = faultwrap auth ratelimit extensions osapiapp11
|
pipeline = faultwrap auth ratelimit extensions osapiapp11
|
||||||
|
|
||||||
[pipeline:osuserdata]
|
|
||||||
pipeline = logrequest osappud
|
|
||||||
|
|
||||||
[filter:faultwrap]
|
[filter:faultwrap]
|
||||||
paste.filter_factory = nova.api.openstack:FaultWrapper.factory
|
paste.filter_factory = nova.api.openstack:FaultWrapper.factory
|
||||||
|
|
||||||
@@ -103,6 +99,3 @@ pipeline = faultwrap osversionapp
|
|||||||
|
|
||||||
[app:osversionapp]
|
[app:osversionapp]
|
||||||
paste.app_factory = nova.api.openstack.versions:Versions.factory
|
paste.app_factory = nova.api.openstack.versions:Versions.factory
|
||||||
|
|
||||||
[app:osappud]
|
|
||||||
paste.app_factory = nova.api.openstack.userdatarequesthandler:UserdataRequestHandler.factory
|
|
||||||
|
|||||||
@@ -15,9 +15,3 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# 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.')
|
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ from nova.auth import manager
|
|||||||
|
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
LOG = logging.getLogger("nova.api")
|
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,
|
flags.DEFINE_integer('lockout_attempts', 5,
|
||||||
'Number of failed auths before lockout.')
|
'Number of failed auths before lockout.')
|
||||||
flags.DEFINE_integer('lockout_minutes', 15,
|
flags.DEFINE_integer('lockout_minutes', 15,
|
||||||
|
|||||||
@@ -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)
|
|
||||||
@@ -371,11 +371,6 @@ def metadata_forward():
|
|||||||
'-p tcp -m tcp --dport 80 -j DNAT '
|
'-p tcp -m tcp --dport 80 -j DNAT '
|
||||||
'--to-destination %s:%s' % \
|
'--to-destination %s:%s' % \
|
||||||
(FLAGS.ec2_dmz_host, FLAGS.ec2_port))
|
(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()
|
iptables_manager.apply()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ from nova.api.openstack import auth
|
|||||||
from nova.api.openstack import extensions
|
from nova.api.openstack import extensions
|
||||||
from nova.api.openstack import versions
|
from nova.api.openstack import versions
|
||||||
from nova.api.openstack import limits
|
from nova.api.openstack import limits
|
||||||
from nova.api.openstack import userdatarequesthandler
|
|
||||||
from nova.auth.manager import User, Project
|
from nova.auth.manager import User, Project
|
||||||
import nova.image.fake
|
import nova.image.fake
|
||||||
from nova.image import glance
|
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.0'] = api10
|
||||||
mapper['/v1.1'] = api11
|
mapper['/v1.1'] = api11
|
||||||
mapper['/'] = openstack.FaultWrapper(versions.Versions())
|
mapper['/'] = openstack.FaultWrapper(versions.Versions())
|
||||||
mapper['/latest'] = userdatarequesthandler.UserdataRequestHandler()
|
|
||||||
return mapper
|
return mapper
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
|
||||||
Reference in New Issue
Block a user