Separate metadata api into its own service

part 1 of blueprint separate-nova-metadata

 * adds api/metadata/ and moves code from ec2
 * moves metadata into separate binary
 * changes metadata forward to use metadata host and port
 * moves the metadata accept rule to the metadata api
 * adds nova-api-* to setup.py

Change-Id: I7f5d8e6cafc55b5c383cd88991f29c6059fb8d82
This commit is contained in:
Vishvananda Ishaya 2011-11-05 14:10:17 -07:00
parent 097d122609
commit e6073532e5
18 changed files with 150 additions and 226 deletions

47
bin/nova-api-metadata Executable file
View File

@ -0,0 +1,47 @@
#!/usr/bin/env python
# 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.
"""Starter script for Nova Metadata API."""
import eventlet
eventlet.monkey_patch()
import os
import sys
possible_topdir = os.path.normpath(os.path.join(os.path.abspath(
sys.argv[0]), os.pardir, os.pardir))
if os.path.exists(os.path.join(possible_topdir, "nova", "__init__.py")):
sys.path.insert(0, possible_topdir)
from nova import flags
from nova import log as logging
from nova import service
from nova import utils
if __name__ == '__main__':
utils.default_flagfile()
flags.FLAGS(sys.argv)
logging.setup()
utils.monkey_patch()
server = service.WSGIService('metadata')
service.serve(server)
service.wait()

View File

@ -1,21 +1,39 @@
############
# Metadata #
############
[composite:metadata]
use = egg:Paste#urlmap
/: metaversions
/latest: meta
/2007-01-19: meta
/2007-03-01: meta
/2007-08-29: meta
/2007-10-10: meta
/2007-12-15: meta
/2008-02-01: meta
/2008-09-01: meta
/2009-04-04: meta
[pipeline:metaversions]
pipeline = ec2faultwrap logrequest metaverapp
[pipeline:meta]
pipeline = ec2faultwrap logrequest metaapp
[app:metaverapp]
paste.app_factory = nova.api.metadata.handler:Versions.factory
[app:metaapp]
paste.app_factory = nova.api.metadata.handler:MetadataRequestHandler.factory
#######
# EC2 #
#######
[composite:ec2]
use = egg:Paste#urlmap
/: ec2versions
/services/Cloud: ec2cloud
/services/Admin: ec2admin
/latest: ec2metadata
/2007-01-19: ec2metadata
/2007-03-01: ec2metadata
/2007-08-29: ec2metadata
/2007-10-10: ec2metadata
/2007-12-15: ec2metadata
/2008-02-01: ec2metadata
/2008-09-01: ec2metadata
/2009-04-04: ec2metadata
[pipeline:ec2cloud]
pipeline = ec2faultwrap logrequest ec2noauth cloudrequest authorizer ec2executor
@ -27,12 +45,6 @@ pipeline = ec2faultwrap logrequest ec2noauth adminrequest authorizer ec2executor
# NOTE(vish): use the following pipeline for deprecated auth
#pipeline = ec2faultwrap logrequest authenticate adminrequest authorizer ec2executor
[pipeline:ec2metadata]
pipeline = ec2faultwrap logrequest ec2md
[pipeline:ec2versions]
pipeline = ec2faultwrap logrequest ec2ver
[filter:ec2faultwrap]
paste.filter_factory = nova.api.ec2:FaultWrapper.factory
@ -62,12 +74,6 @@ paste.filter_factory = nova.api.ec2:Authorizer.factory
[app:ec2executor]
paste.app_factory = nova.api.ec2:Executor.factory
[app:ec2ver]
paste.app_factory = nova.api.ec2:Versions.factory
[app:ec2md]
paste.app_factory = nova.api.ec2.metadatarequesthandler:MetadataRequestHandler.factory
#############
# Openstack #
#############

View File

@ -25,7 +25,7 @@
:synopsis: Infrastructure-as-a-Service Cloud platform.
.. moduleauthor:: Jesse Andrews <jesse@ansolabs.com>
.. moduleauthor:: Devin Carlen <devin.carlen@gmail.com>
.. moduleauthor:: Vishvananda Ishaya <vishvananda@yahoo.com>
.. moduleauthor:: Vishvananda Ishaya <vishvananda@gmail.com>
.. moduleauthor:: Joshua McKenty <joshua@cognition.ca>
.. moduleauthor:: Manish Singh <yosh@gimp.org>
.. moduleauthor:: Andy Smith <andy@anarkystic.com>

View File

@ -20,10 +20,7 @@ Starting point for routing EC2 requests.
"""
from urlparse import urlparse
import eventlet
from eventlet.green import httplib
import webob
import webob.dec
import webob.exc
@ -437,23 +434,3 @@ class Executor(wsgi.Application):
(utils.utf8(code), utils.utf8(message),
utils.utf8(context.request_id)))
return resp
class Versions(wsgi.Application):
@webob.dec.wsgify(RequestClass=wsgi.Request)
def __call__(self, req):
"""Respond to a request for all EC2 versions."""
# available api versions
versions = [
'1.0',
'2007-01-19',
'2007-03-01',
'2007-08-29',
'2007-10-10',
'2007-12-15',
'2008-02-01',
'2008-09-01',
'2009-04-04',
]
return ''.join('%s\n' % v for v in versions)

View File

@ -23,14 +23,14 @@ from nova import utils
FLAGS = flags.FLAGS
class EC2Manager(manager.Manager):
"""EC2 API manager.
class MetadataManager(manager.Manager):
"""Metadata Manager.
This class manages the EC2 API service initialization. Currently, it
This class manages the Metadata API service initialization. Currently, it
just adds an iptables filter rule for the metadata service.
"""
def __init__(self, *args, **kwargs):
super(EC2Manager, self).__init__(*args, **kwargs)
super(MetadataManager, self).__init__(*args, **kwargs)
self.network_driver = utils.import_object(FLAGS.network_driver)
def init_host(self):

View File

@ -0,0 +1,25 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 Openstack, LLC.
#
# 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.
"""
:mod:`nova.api.metadata` -- Nova Metadata Server
================================================
.. automodule:: nova.api.metadata
:platform: Unix
:synopsis: Metadata Server for Nova
.. moduleauthor:: Vishvananda Ishaya <vishvananda@gmail.com>
"""

View File

@ -23,18 +23,37 @@ import webob.exc
from nova import log as logging
from nova import flags
from nova import utils
from nova import wsgi
from nova.api.ec2 import cloud
LOG = logging.getLogger('nova.api.ec2.metadata')
LOG = logging.getLogger('nova.api.metadata')
FLAGS = flags.FLAGS
flags.DECLARE('use_forwarded_for', 'nova.api.auth')
class Versions(wsgi.Application):
@webob.dec.wsgify(RequestClass=wsgi.Request)
def __call__(self, req):
"""Respond to a request for all versions."""
# available api versions
versions = [
'1.0',
'2007-01-19',
'2007-03-01',
'2007-08-29',
'2007-10-10',
'2007-12-15',
'2008-02-01',
'2008-09-01',
'2009-04-04',
]
return ''.join('%s\n' % v for v in versions)
class MetadataRequestHandler(wsgi.Application):
"""Serve metadata from the EC2 API."""
"""Serve metadata."""
def __init__(self):
self.cc = cloud.CloudController()

View File

@ -23,6 +23,6 @@
:platform: Unix
:synopsis: User-and-Project based RBAC using LDAP, SAML.
.. moduleauthor:: Jesse Andrews <jesse@ansolabs.com>
.. moduleauthor:: Vishvananda Ishaya <vishvananda@yahoo.com>
.. moduleauthor:: Vishvananda Ishaya <vishvananda@gmail.com>
.. moduleauthor:: Joshua McKenty <joshua@cognition.ca>
"""

View File

@ -24,6 +24,6 @@
:platform: Unix
:synopsis: An OpenVPN server for every nova user.
.. moduleauthor:: Devin Carlen <devin.carlen@gmail.com>
.. moduleauthor:: Vishvananda Ishaya <vishvananda@yahoo.com>
.. moduleauthor:: Vishvananda Ishaya <vishvananda@gmail.com>
.. moduleauthor:: Joshua McKenty <jmckenty@gmail.com>
"""

View File

@ -361,7 +361,7 @@ DEFINE_integer('rabbit_max_retries', 0,
'maximum rabbit connection attempts (0=try forever)')
DEFINE_string('control_exchange', 'nova', 'the main exchange to connect to')
DEFINE_boolean('rabbit_durable_queues', False, 'use durable queues')
DEFINE_list('enabled_apis', ['ec2', 'osapi'],
DEFINE_list('enabled_apis', ['ec2', 'osapi', 'metadata'],
'list of APIs to enable by default')
DEFINE_string('ec2_host', '$my_ip', 'ip of api server')
DEFINE_string('ec2_dmz_host', '$my_ip', 'internal ip of api server')
@ -377,7 +377,8 @@ DEFINE_integer('osapi_port', 8774, 'OpenStack API port')
DEFINE_string('osapi_path', '/v1.1/', 'suffix for openstack')
DEFINE_integer('osapi_max_limit', 1000,
'max number of items returned in a collection response')
DEFINE_string('metadata_host', '$my_ip', 'ip of metadata server')
DEFINE_integer('metadata_port', 8775, 'Metadata API port')
DEFINE_string('default_project', 'openstack', 'default project for openstack')
DEFINE_string('default_image', 'ami-11111',
'default image to use, testing only')

View File

@ -377,7 +377,8 @@ def metadata_forward():
'-s 0.0.0.0/0 -d 169.254.169.254/32 '
'-p tcp -m tcp --dport 80 -j DNAT '
'--to-destination %s:%s' % \
(FLAGS.ec2_dmz_host, FLAGS.ec2_port))
(FLAGS.metadata_host,
FLAGS.metadata_port))
iptables_manager.apply()
@ -387,8 +388,8 @@ def metadata_accept():
'-s 0.0.0.0/0 -d %s '
'-p tcp -m tcp --dport %s '
'-j ACCEPT' % \
(FLAGS.ec2_dmz_host,
FLAGS.ec2_port))
(FLAGS.metadata_host,
FLAGS.metadata_port))
iptables_manager.apply()

View File

@ -25,7 +25,7 @@
:synopsis: Currently a trivial file-based system, getting extended w/ swift.
.. moduleauthor:: Jesse Andrews <jesse@ansolabs.com>
.. moduleauthor:: Devin Carlen <devin.carlen@gmail.com>
.. moduleauthor:: Vishvananda Ishaya <vishvananda@yahoo.com>
.. moduleauthor:: Vishvananda Ishaya <vishvananda@gmail.com>
.. moduleauthor:: Joshua McKenty <joshua@cognition.ca>
.. moduleauthor:: Manish Singh <yosh@gimp.org>
.. moduleauthor:: Andy Smith <andy@anarkystic.com>

View File

@ -45,16 +45,18 @@ flags.DEFINE_integer('report_interval', 10,
flags.DEFINE_integer('periodic_interval', 60,
'seconds between running periodic tasks',
lower_bound=1)
flags.DEFINE_string('ec2_manager', 'nova.api.manager.EC2Manager',
'EC2 API service manager')
flags.DEFINE_string('ec2_listen', "0.0.0.0",
'IP address for EC2 API to listen')
flags.DEFINE_integer('ec2_listen_port', 8773, 'port for ec2 api to listen')
flags.DEFINE_string('osapi_manager', None,
'OpenStack API service manager')
flags.DEFINE_string('osapi_listen', "0.0.0.0",
'IP address for OpenStack API to listen')
flags.DEFINE_integer('osapi_listen_port', 8774, 'port for os api to listen')
flags.DEFINE_string('metadata_manager', 'nova.api.manager.MetadataManager',
'OpenStack metadata service manager')
flags.DEFINE_string('metadata_listen', "0.0.0.0",
'IP address for metadata api to listen')
flags.DEFINE_integer('metadata_listen_port', 8775,
'port for metadata api to listen')
flags.DEFINE_string('api_paste_config', "api-paste.ini",
'File name for the paste.deploy config for nova-api')

View File

@ -24,7 +24,7 @@
:platform: Unix
.. moduleauthor:: Jesse Andrews <jesse@ansolabs.com>
.. moduleauthor:: Devin Carlen <devin.carlen@gmail.com>
.. moduleauthor:: Vishvananda Ishaya <vishvananda@yahoo.com>
.. moduleauthor:: Vishvananda Ishaya <vishvananda@gmail.com>
.. moduleauthor:: Joshua McKenty <joshua@cognition.ca>
.. moduleauthor:: Manish Singh <yosh@gimp.org>
.. moduleauthor:: Andy Smith <andy@anarkystic.com>

View File

@ -93,6 +93,7 @@ class _IntegratedTestBase(test.TestCase):
# Auto-assign ports to allow concurrent tests
f['ec2_listen_port'] = 0
f['osapi_listen_port'] = 0
f['metadata_listen_port'] = 0
f['image_service'] = 'nova.image.fake.FakeImageService'
f['fake_network'] = True

View File

@ -21,7 +21,7 @@
import base64
import webob
from nova.api.ec2 import metadatarequesthandler
from nova.api.metadata import handler
from nova.db.sqlalchemy import api
from nova import exception
from nova import flags
@ -86,7 +86,7 @@ class MetadataTestCase(test.TestCase):
self.stubs.Set(api, 'instance_get', instance_get)
self.stubs.Set(api, 'instance_get_all_by_filters', instance_get_list)
self.stubs.Set(api, 'instance_get_floating_address', floating_get)
self.app = metadatarequesthandler.MetadataRequestHandler()
self.app = handler.MetadataRequestHandler()
network_manager = fake_network.FakeNetworkManager()
self.stubs.Set(self.app.cc.network_api,
'get_instance_uuids_by_ip_filter',

View File

@ -119,6 +119,9 @@ setup(name='nova',
data_files=find_data_files('share/nova', 'tools'),
scripts=['bin/nova-ajax-console-proxy',
'bin/nova-api',
'bin/nova-api-ec2',
'bin/nova-api-metadata',
'bin/nova-api-os',
'bin/nova-compute',
'bin/nova-console',
'bin/nova-dhcpbridge',

View File

@ -1,158 +0,0 @@
#!/usr/bin/env bash
# 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.
# NOTE(vish): This script sets up some reasonable defaults for iptables and
# creates nova-specific chains. If you use this script you should
# run nova-network and nova-compute with --use_nova_chains=True
# NOTE(vish): If you run nova-api on a different port, make sure to change
# the port here
API_PORT=${API_PORT:-"8773"}
if [ -n "$1" ]; then
CMD=$1
else
CMD="all"
fi
if [ -n "$2" ]; then
IP=$2
else
# NOTE(vish): This will just get the first ip in the list, so if you
# have more than one eth device set up, this will fail, and
# you should explicitly pass in the ip of the instance
IP=`LC_ALL=C ifconfig | grep -m 1 'inet addr:'| cut -d: -f2 | awk '{print $1}'`
fi
if [ -n "$3" ]; then
PRIVATE_RANGE=$3
else
PRIVATE_RANGE="10.0.0.0/12"
fi
if [ -n "$4" ]; then
# NOTE(vish): Management IP is the ip over which to allow ssh traffic. It
# will also allow traffic to nova-api
MGMT_IP=$4
else
MGMT_IP="$IP"
fi
if [ "$CMD" == "clear" ]; then
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
iptables -F
iptables -t nat -F
iptables -F nova_input
iptables -F nova_output
iptables -F nova_forward
iptables -t nat -F nova_input
iptables -t nat -F nova_output
iptables -t nat -F nova_forward
iptables -t nat -X
iptables -X
fi
if [ "$CMD" == "base" ] || [ "$CMD" == "all" ]; then
iptables -P INPUT DROP
iptables -A INPUT -m state --state INVALID -j DROP
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -m tcp -p tcp -d $MGMT_IP --dport 22 -j ACCEPT
iptables -A INPUT -m udp -p udp --dport 123 -j ACCEPT
iptables -N nova_input
iptables -A INPUT -j nova_input
iptables -A INPUT -p icmp -j ACCEPT
iptables -A INPUT -p tcp -j REJECT --reject-with tcp-reset
iptables -A INPUT -j REJECT --reject-with icmp-port-unreachable
iptables -P FORWARD DROP
iptables -A FORWARD -m state --state INVALID -j DROP
iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
iptables -N nova_forward
iptables -A FORWARD -j nova_forward
# NOTE(vish): DROP on output is too restrictive for now. We need to add
# in a bunch of more specific output rules to use it.
# iptables -P OUTPUT DROP
iptables -A OUTPUT -m state --state INVALID -j DROP
iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -N nova_output
iptables -A OUTPUT -j nova_output
iptables -t nat -N nova_prerouting
iptables -t nat -A PREROUTING -j nova_prerouting
iptables -t nat -N nova_postrouting
iptables -t nat -A POSTROUTING -j nova_postrouting
iptables -t nat -N nova_output
iptables -t nat -A OUTPUT -j nova_output
fi
if [ "$CMD" == "ganglia" ] || [ "$CMD" == "all" ]; then
iptables -A nova_input -m tcp -p tcp -d $IP --dport 8649 -j ACCEPT
iptables -A nova_input -m udp -p udp -d $IP --dport 8649 -j ACCEPT
fi
if [ "$CMD" == "web" ] || [ "$CMD" == "all" ]; then
# NOTE(vish): This opens up ports for web access, allowing web-based
# dashboards to work.
iptables -A nova_input -m tcp -p tcp -d $IP --dport 80 -j ACCEPT
iptables -A nova_input -m tcp -p tcp -d $IP --dport 443 -j ACCEPT
fi
if [ "$CMD" == "objectstore" ] || [ "$CMD" == "all" ]; then
iptables -A nova_input -m tcp -p tcp -d $IP --dport 3333 -j ACCEPT
fi
if [ "$CMD" == "api" ] || [ "$CMD" == "all" ]; then
iptables -A nova_input -m tcp -p tcp -d $IP --dport $API_PORT -j ACCEPT
if [ "$IP" != "$MGMT_IP" ]; then
iptables -A nova_input -m tcp -p tcp -d $MGMT_IP --dport $API_PORT -j ACCEPT
fi
fi
if [ "$CMD" == "redis" ] || [ "$CMD" == "all" ]; then
iptables -A nova_input -m tcp -p tcp -d $IP --dport 6379 -j ACCEPT
fi
if [ "$CMD" == "mysql" ] || [ "$CMD" == "all" ]; then
iptables -A nova_input -m tcp -p tcp -d $IP --dport 3306 -j ACCEPT
fi
if [ "$CMD" == "rabbitmq" ] || [ "$CMD" == "all" ]; then
iptables -A nova_input -m tcp -p tcp -d $IP --dport 4369 -j ACCEPT
iptables -A nova_input -m tcp -p tcp -d $IP --dport 5672 -j ACCEPT
iptables -A nova_input -m tcp -p tcp -d $IP --dport 53284 -j ACCEPT
fi
if [ "$CMD" == "dnsmasq" ] || [ "$CMD" == "all" ]; then
# NOTE(vish): this could theoretically be setup per network
# for each host, but it seems like overkill
iptables -A nova_input -m tcp -p tcp -s $PRIVATE_RANGE --dport 53 -j ACCEPT
iptables -A nova_input -m udp -p udp -s $PRIVATE_RANGE --dport 53 -j ACCEPT
iptables -A nova_input -m udp -p udp --dport 67 -j ACCEPT
fi
if [ "$CMD" == "ldap" ] || [ "$CMD" == "all" ]; then
iptables -A nova_input -m tcp -p tcp -d $IP --dport 389 -j ACCEPT
fi