merge from upstream and fix small issues
This commit is contained in:
2
.mailmap
2
.mailmap
@@ -16,6 +16,8 @@
|
|||||||
<jmckenty@gmail.com> <jmckenty@joshua-mckentys-macbook-pro.local>
|
<jmckenty@gmail.com> <jmckenty@joshua-mckentys-macbook-pro.local>
|
||||||
<jmckenty@gmail.com> <joshua.mckenty@nasa.gov>
|
<jmckenty@gmail.com> <joshua.mckenty@nasa.gov>
|
||||||
<justin@fathomdb.com> <justinsb@justinsb-desktop>
|
<justin@fathomdb.com> <justinsb@justinsb-desktop>
|
||||||
|
<masumotok@nttdata.co.jp> <root@openstack2-api>
|
||||||
|
<masumotok@nttdata.co.jp> Masumoto<masumotok@nttdata.co.jp>
|
||||||
<mordred@inaugust.com> <mordred@hudson>
|
<mordred@inaugust.com> <mordred@hudson>
|
||||||
<paul@openstack.org> <pvoccio@castor.local>
|
<paul@openstack.org> <pvoccio@castor.local>
|
||||||
<paul@openstack.org> <paul.voccio@rackspace.com>
|
<paul@openstack.org> <paul.voccio@rackspace.com>
|
||||||
|
2
Authors
2
Authors
@@ -26,6 +26,7 @@ Josh Durgin <joshd@hq.newdream.net>
|
|||||||
Josh Kearney <josh.kearney@rackspace.com>
|
Josh Kearney <josh.kearney@rackspace.com>
|
||||||
Joshua McKenty <jmckenty@gmail.com>
|
Joshua McKenty <jmckenty@gmail.com>
|
||||||
Justin Santa Barbara <justin@fathomdb.com>
|
Justin Santa Barbara <justin@fathomdb.com>
|
||||||
|
Kei Masumoto <masumotok@nttdata.co.jp>
|
||||||
Ken Pepple <ken.pepple@gmail.com>
|
Ken Pepple <ken.pepple@gmail.com>
|
||||||
Koji Iida <iida.koji@lab.ntt.co.jp>
|
Koji Iida <iida.koji@lab.ntt.co.jp>
|
||||||
Lorin Hochstein <lorin@isi.edu>
|
Lorin Hochstein <lorin@isi.edu>
|
||||||
@@ -34,6 +35,7 @@ Michael Gundlach <michael.gundlach@rackspace.com>
|
|||||||
Monsyne Dragon <mdragon@rackspace.com>
|
Monsyne Dragon <mdragon@rackspace.com>
|
||||||
Monty Taylor <mordred@inaugust.com>
|
Monty Taylor <mordred@inaugust.com>
|
||||||
MORITA Kazutaka <morita.kazutaka@gmail.com>
|
MORITA Kazutaka <morita.kazutaka@gmail.com>
|
||||||
|
Muneyuki Noguchi <noguchimn@nttdata.co.jp>
|
||||||
Nachi Ueno <ueno.nachi@lab.ntt.co.jp> <openstack@lab.ntt.co.jp> <nati.ueno@gmail.com> <nova@u4>
|
Nachi Ueno <ueno.nachi@lab.ntt.co.jp> <openstack@lab.ntt.co.jp> <nati.ueno@gmail.com> <nova@u4>
|
||||||
Paul Voccio <paul@openstack.org>
|
Paul Voccio <paul@openstack.org>
|
||||||
Rick Clark <rick@openstack.org>
|
Rick Clark <rick@openstack.org>
|
||||||
|
@@ -12,6 +12,7 @@ include nova/cloudpipe/bootscript.sh
|
|||||||
include nova/cloudpipe/client.ovpn.template
|
include nova/cloudpipe/client.ovpn.template
|
||||||
include nova/compute/fakevirtinstance.xml
|
include nova/compute/fakevirtinstance.xml
|
||||||
include nova/compute/interfaces.template
|
include nova/compute/interfaces.template
|
||||||
|
include nova/db/sqlalchemy/migrate_repo/migrate.cfg
|
||||||
include nova/virt/interfaces.template
|
include nova/virt/interfaces.template
|
||||||
include nova/virt/libvirt*.xml.template
|
include nova/virt/libvirt*.xml.template
|
||||||
include nova/tests/CA/
|
include nova/tests/CA/
|
||||||
|
51
bin/nova-api
51
bin/nova-api
@@ -34,22 +34,53 @@ if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
|
|||||||
|
|
||||||
gettext.install('nova', unicode=1)
|
gettext.install('nova', unicode=1)
|
||||||
|
|
||||||
from nova import api
|
|
||||||
from nova import flags
|
from nova import flags
|
||||||
from nova import utils
|
from nova import log as logging
|
||||||
from nova import wsgi
|
from nova import wsgi
|
||||||
|
|
||||||
|
logging.basicConfig()
|
||||||
|
LOG = logging.getLogger('nova.api')
|
||||||
|
LOG.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
flags.DEFINE_string('osapi_host', '0.0.0.0', 'OpenStack API host')
|
|
||||||
flags.DEFINE_integer('ec2api_port', 8773, 'EC2 API port')
|
API_ENDPOINTS = ['ec2', 'osapi']
|
||||||
flags.DEFINE_string('ec2api_host', '0.0.0.0', 'EC2 API host')
|
|
||||||
|
|
||||||
|
def run_app(paste_config_file):
|
||||||
|
LOG.debug(_("Using paste.deploy config at: %s"), paste_config_file)
|
||||||
|
apps = []
|
||||||
|
for api in API_ENDPOINTS:
|
||||||
|
config = wsgi.load_paste_configuration(paste_config_file, api)
|
||||||
|
if config is None:
|
||||||
|
LOG.debug(_("No paste configuration for app: %s"), api)
|
||||||
|
continue
|
||||||
|
LOG.debug(_("App Config: %s\n%r"), api, config)
|
||||||
|
wsgi.paste_config_to_flags(config, {
|
||||||
|
"verbose": FLAGS.verbose,
|
||||||
|
"%s_host" % api: config.get('host', '0.0.0.0'),
|
||||||
|
"%s_port" % api: getattr(FLAGS, "%s_port" % api)})
|
||||||
|
LOG.info(_("Running %s API"), api)
|
||||||
|
app = wsgi.load_paste_app(paste_config_file, api)
|
||||||
|
apps.append((app, getattr(FLAGS, "%s_port" % api),
|
||||||
|
getattr(FLAGS, "%s_host" % api)))
|
||||||
|
if len(apps) == 0:
|
||||||
|
LOG.error(_("No known API applications configured in %s."),
|
||||||
|
paste_config_file)
|
||||||
|
return
|
||||||
|
|
||||||
|
# NOTE(todd): redo logging config, verbose could be set in paste config
|
||||||
|
logging.basicConfig()
|
||||||
|
server = wsgi.Server()
|
||||||
|
for app in apps:
|
||||||
|
server.start(*app)
|
||||||
|
server.wait()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
utils.default_flagfile()
|
|
||||||
FLAGS(sys.argv)
|
FLAGS(sys.argv)
|
||||||
server = wsgi.Server()
|
conf = wsgi.paste_config_file('nova-api.conf')
|
||||||
server.start(api.API('os'), FLAGS.osapi_port, host=FLAGS.osapi_host)
|
if conf:
|
||||||
server.start(api.API('ec2'), FLAGS.ec2api_port, host=FLAGS.ec2api_host)
|
run_app(conf)
|
||||||
server.wait()
|
else:
|
||||||
|
LOG.error(_("No paste configuration found for: %s"), 'nova-api.conf')
|
||||||
|
@@ -1,109 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# pylint: disable-msg=C0103
|
|
||||||
# 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 API."""
|
|
||||||
|
|
||||||
import gettext
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from paste import deploy
|
|
||||||
|
|
||||||
# If ../nova/__init__.py exists, add ../ to Python search path, so that
|
|
||||||
# it will override what happens to be installed in /usr/(local/)lib/python...
|
|
||||||
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)
|
|
||||||
|
|
||||||
gettext.install('nova', unicode=1)
|
|
||||||
|
|
||||||
from nova import flags
|
|
||||||
from nova import log as logging
|
|
||||||
from nova import wsgi
|
|
||||||
|
|
||||||
LOG = logging.getLogger('nova.api')
|
|
||||||
LOG.setLevel(logging.DEBUG)
|
|
||||||
LOG.addHandler(logging.StreamHandler())
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
|
||||||
|
|
||||||
API_ENDPOINTS = ['ec2', 'openstack']
|
|
||||||
|
|
||||||
|
|
||||||
def load_configuration(paste_config):
|
|
||||||
"""Load the paste configuration from the config file and return it."""
|
|
||||||
config = None
|
|
||||||
# Try each known name to get the global DEFAULTS, which will give ports
|
|
||||||
for name in API_ENDPOINTS:
|
|
||||||
try:
|
|
||||||
config = deploy.appconfig("config:%s" % paste_config, name=name)
|
|
||||||
except LookupError:
|
|
||||||
pass
|
|
||||||
if config:
|
|
||||||
verbose = config.get('verbose', None)
|
|
||||||
if verbose:
|
|
||||||
FLAGS.verbose = int(verbose) == 1
|
|
||||||
if FLAGS.verbose:
|
|
||||||
logging.getLogger().setLevel(logging.DEBUG)
|
|
||||||
return config
|
|
||||||
LOG.debug(_("Paste config at %s has no secion for known apis"),
|
|
||||||
paste_config)
|
|
||||||
print _("Paste config at %s has no secion for any known apis") % \
|
|
||||||
paste_config
|
|
||||||
os.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def launch_api(paste_config_file, section, server, port, host):
|
|
||||||
"""Launch an api server from the specified port and IP."""
|
|
||||||
LOG.debug(_("Launching %s api on %s:%s"), section, host, port)
|
|
||||||
app = deploy.loadapp('config:%s' % paste_config_file, name=section)
|
|
||||||
server.start(app, int(port), host)
|
|
||||||
|
|
||||||
|
|
||||||
def run_app(paste_config_file):
|
|
||||||
LOG.debug(_("Using paste.deploy config at: %s"), configfile)
|
|
||||||
config = load_configuration(paste_config_file)
|
|
||||||
LOG.debug(_("Configuration: %r"), config)
|
|
||||||
server = wsgi.Server()
|
|
||||||
ip = config.get('host', '0.0.0.0')
|
|
||||||
for api in API_ENDPOINTS:
|
|
||||||
port = config.get("%s_port" % api, None)
|
|
||||||
if not port:
|
|
||||||
continue
|
|
||||||
host = config.get("%s_host" % api, ip)
|
|
||||||
launch_api(configfile, api, server, port, host)
|
|
||||||
LOG.debug(_("All api servers launched, now waiting"))
|
|
||||||
server.wait()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
FLAGS(sys.argv)
|
|
||||||
configfiles = ['/etc/nova/nova-api.conf']
|
|
||||||
if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
|
|
||||||
configfiles.insert(0,
|
|
||||||
os.path.join(possible_topdir, 'etc', 'nova-api.conf'))
|
|
||||||
for configfile in configfiles:
|
|
||||||
if os.path.exists(configfile):
|
|
||||||
run_app(configfile)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
LOG.debug(_("Skipping missing configuration: %s"), configfile)
|
|
@@ -36,22 +36,20 @@ if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
|
|||||||
|
|
||||||
gettext.install('nova', unicode=1)
|
gettext.install('nova', unicode=1)
|
||||||
|
|
||||||
from nova import api
|
|
||||||
from nova import flags
|
from nova import flags
|
||||||
|
from nova import log as logging
|
||||||
from nova import service
|
from nova import service
|
||||||
from nova import utils
|
from nova import utils
|
||||||
from nova import wsgi
|
from nova import wsgi
|
||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
flags.DEFINE_string('osapi_host', '0.0.0.0', 'OpenStack API host')
|
|
||||||
flags.DEFINE_integer('ec2api_port', 8773, 'EC2 API port')
|
|
||||||
flags.DEFINE_string('ec2api_host', '0.0.0.0', 'EC2 API host')
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
utils.default_flagfile()
|
utils.default_flagfile()
|
||||||
FLAGS(sys.argv)
|
FLAGS(sys.argv)
|
||||||
|
logging.basicConfig()
|
||||||
|
|
||||||
compute = service.Service.create(binary='nova-compute')
|
compute = service.Service.create(binary='nova-compute')
|
||||||
network = service.Service.create(binary='nova-network')
|
network = service.Service.create(binary='nova-network')
|
||||||
@@ -61,7 +59,22 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
service.serve(compute, network, volume, scheduler)
|
service.serve(compute, network, volume, scheduler)
|
||||||
|
|
||||||
server = wsgi.Server()
|
apps = []
|
||||||
server.start(api.API('os'), FLAGS.osapi_port, host=FLAGS.osapi_host)
|
paste_config_file = wsgi.paste_config_file('nova-api.conf')
|
||||||
server.start(api.API('ec2'), FLAGS.ec2api_port, host=FLAGS.ec2api_host)
|
for api in ['osapi', 'ec2']:
|
||||||
server.wait()
|
config = wsgi.load_paste_configuration(paste_config_file, api)
|
||||||
|
if config is None:
|
||||||
|
continue
|
||||||
|
wsgi.paste_config_to_flags(config, {
|
||||||
|
"verbose": FLAGS.verbose,
|
||||||
|
"%s_host" % api: config.get('host', '0.0.0.0'),
|
||||||
|
"%s_port" % api: getattr(FLAGS, "%s_port" % api)})
|
||||||
|
app = wsgi.load_paste_app(paste_config_file, api)
|
||||||
|
apps.append((app, getattr(FLAGS, "%s_port" % api),
|
||||||
|
getattr(FLAGS, "%s_host" % api)))
|
||||||
|
if len(apps) > 0:
|
||||||
|
logging.basicConfig()
|
||||||
|
server = wsgi.Server()
|
||||||
|
for app in apps:
|
||||||
|
server.start(*app)
|
||||||
|
server.wait()
|
||||||
|
61
bin/nova-direct-api
Executable file
61
bin/nova-direct-api
Executable file
@@ -0,0 +1,61 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# pylint: disable-msg=C0103
|
||||||
|
# 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 Direct API."""
|
||||||
|
|
||||||
|
import gettext
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# If ../nova/__init__.py exists, add ../ to Python search path, so that
|
||||||
|
# it will override what happens to be installed in /usr/(local/)lib/python...
|
||||||
|
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)
|
||||||
|
|
||||||
|
gettext.install('nova', unicode=1)
|
||||||
|
|
||||||
|
from nova import flags
|
||||||
|
from nova import utils
|
||||||
|
from nova import wsgi
|
||||||
|
from nova.api import direct
|
||||||
|
from nova.compute import api as compute_api
|
||||||
|
|
||||||
|
|
||||||
|
FLAGS = flags.FLAGS
|
||||||
|
flags.DEFINE_integer('direct_port', 8001, 'Direct API port')
|
||||||
|
flags.DEFINE_string('direct_host', '0.0.0.0', 'Direct API host')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
utils.default_flagfile()
|
||||||
|
FLAGS(sys.argv)
|
||||||
|
|
||||||
|
direct.register_service('compute', compute_api.ComputeAPI())
|
||||||
|
direct.register_service('reflect', direct.Reflection())
|
||||||
|
router = direct.Router()
|
||||||
|
with_json = direct.JsonParamsMiddleware(router)
|
||||||
|
with_req = direct.PostParamsMiddleware(with_json)
|
||||||
|
with_auth = direct.DelegatedAuthMiddleware(with_req)
|
||||||
|
|
||||||
|
server = wsgi.Server()
|
||||||
|
server.start(with_auth, FLAGS.direct_port, host=FLAGS.direct_host)
|
||||||
|
server.wait()
|
@@ -527,12 +527,11 @@ class DbCommands(object):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def sync(self, version=None):
|
def sync(self, version=None):
|
||||||
"""adds role to user
|
"""Sync the database up to the most recent version."""
|
||||||
if project is specified, adds project specific role
|
|
||||||
arguments: user, role [project]"""
|
|
||||||
return migration.db_sync(version)
|
return migration.db_sync(version)
|
||||||
|
|
||||||
def version(self):
|
def version(self):
|
||||||
|
"""Print the current database version."""
|
||||||
print migration.db_version()
|
print migration.db_version()
|
||||||
|
|
||||||
|
|
||||||
|
145
bin/stack
Executable file
145
bin/stack
Executable file
@@ -0,0 +1,145 @@
|
|||||||
|
#!/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.
|
||||||
|
|
||||||
|
"""CLI for the Direct API."""
|
||||||
|
|
||||||
|
import eventlet
|
||||||
|
eventlet.monkey_patch()
|
||||||
|
|
||||||
|
import os
|
||||||
|
import pprint
|
||||||
|
import sys
|
||||||
|
import textwrap
|
||||||
|
import urllib
|
||||||
|
import urllib2
|
||||||
|
|
||||||
|
# If ../nova/__init__.py exists, add ../ to Python search path, so that
|
||||||
|
# it will override what happens to be installed in /usr/(local/)lib/python...
|
||||||
|
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)
|
||||||
|
|
||||||
|
import gflags
|
||||||
|
from nova import utils
|
||||||
|
|
||||||
|
|
||||||
|
FLAGS = gflags.FLAGS
|
||||||
|
gflags.DEFINE_string('host', '127.0.0.1', 'Direct API host')
|
||||||
|
gflags.DEFINE_integer('port', 8001, 'Direct API host')
|
||||||
|
gflags.DEFINE_string('user', 'user1', 'Direct API username')
|
||||||
|
gflags.DEFINE_string('project', 'proj1', 'Direct API project')
|
||||||
|
|
||||||
|
|
||||||
|
USAGE = """usage: stack [options] <controller> <method> [arg1=value arg2=value]
|
||||||
|
|
||||||
|
`stack help` should output the list of available controllers
|
||||||
|
`stack <controller>` should output the available methods for that controller
|
||||||
|
`stack help <controller>` should do the same
|
||||||
|
`stack help <controller> <method>` should output info for a method
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def format_help(d):
|
||||||
|
"""Format help text, keys are labels and values are descriptions."""
|
||||||
|
indent = max([len(k) for k in d])
|
||||||
|
out = []
|
||||||
|
for k, v in d.iteritems():
|
||||||
|
t = textwrap.TextWrapper(initial_indent=' %s ' % k.ljust(indent),
|
||||||
|
subsequent_indent=' ' * (indent + 6))
|
||||||
|
out.extend(t.wrap(v))
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def help_all():
|
||||||
|
rv = do_request('reflect', 'get_controllers')
|
||||||
|
out = format_help(rv)
|
||||||
|
return (USAGE + str(FLAGS.MainModuleHelp()) +
|
||||||
|
'\n\nAvailable controllers:\n' +
|
||||||
|
'\n'.join(out) + '\n')
|
||||||
|
|
||||||
|
|
||||||
|
def help_controller(controller):
|
||||||
|
rv = do_request('reflect', 'get_methods')
|
||||||
|
methods = dict([(k.split('/')[2], v) for k, v in rv.iteritems()
|
||||||
|
if k.startswith('/%s' % controller)])
|
||||||
|
return ('Available methods for %s:\n' % controller +
|
||||||
|
'\n'.join(format_help(methods)))
|
||||||
|
|
||||||
|
|
||||||
|
def help_method(controller, method):
|
||||||
|
rv = do_request('reflect',
|
||||||
|
'get_method_info',
|
||||||
|
{'method': '/%s/%s' % (controller, method)})
|
||||||
|
|
||||||
|
sig = '%s(%s):' % (method, ', '.join(['='.join(x) for x in rv['args']]))
|
||||||
|
out = textwrap.wrap(sig, subsequent_indent=' ' * len('%s(' % method))
|
||||||
|
out.append('\n' + rv['doc'])
|
||||||
|
return '\n'.join(out)
|
||||||
|
|
||||||
|
|
||||||
|
def do_request(controller, method, params=None):
|
||||||
|
if params:
|
||||||
|
data = urllib.urlencode(params)
|
||||||
|
else:
|
||||||
|
data = None
|
||||||
|
|
||||||
|
url = 'http://%s:%s/%s/%s' % (FLAGS.host, FLAGS.port, controller, method)
|
||||||
|
headers = {'X-OpenStack-User': FLAGS.user,
|
||||||
|
'X-OpenStack-Project': FLAGS.project}
|
||||||
|
|
||||||
|
req = urllib2.Request(url, data, headers)
|
||||||
|
resp = urllib2.urlopen(req)
|
||||||
|
return utils.loads(resp.read())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
args = FLAGS(sys.argv)
|
||||||
|
|
||||||
|
cmd = args.pop(0)
|
||||||
|
if not args:
|
||||||
|
print help_all()
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
first = args.pop(0)
|
||||||
|
if first == 'help':
|
||||||
|
action = help_all
|
||||||
|
params = []
|
||||||
|
if args:
|
||||||
|
params.append(args.pop(0))
|
||||||
|
action = help_controller
|
||||||
|
if args:
|
||||||
|
params.append(args.pop(0))
|
||||||
|
action = help_method
|
||||||
|
print action(*params)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
controller = first
|
||||||
|
if not args:
|
||||||
|
print help_controller(controller)
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
method = args.pop(0)
|
||||||
|
params = {}
|
||||||
|
for x in args:
|
||||||
|
key, value = x.split('=', 1)
|
||||||
|
params[key] = value
|
||||||
|
|
||||||
|
pprint.pprint(do_request(controller, method, params))
|
@@ -682,7 +682,7 @@ class AuthManager(object):
|
|||||||
region, _sep, region_host = item.partition("=")
|
region, _sep, region_host = item.partition("=")
|
||||||
regions[region] = region_host
|
regions[region] = region_host
|
||||||
else:
|
else:
|
||||||
regions = {'nova': FLAGS.cc_host}
|
regions = {'nova': FLAGS.ec2_host}
|
||||||
for region, host in regions.iteritems():
|
for region, host in regions.iteritems():
|
||||||
rc = self.__generate_rc(user,
|
rc = self.__generate_rc(user,
|
||||||
pid,
|
pid,
|
||||||
@@ -727,28 +727,28 @@ class AuthManager(object):
|
|||||||
def __generate_rc(user, pid, use_dmz=True, host=None):
|
def __generate_rc(user, pid, use_dmz=True, host=None):
|
||||||
"""Generate rc file for user"""
|
"""Generate rc file for user"""
|
||||||
if use_dmz:
|
if use_dmz:
|
||||||
cc_host = FLAGS.cc_dmz
|
ec2_host = FLAGS.ec2_dmz_host
|
||||||
else:
|
else:
|
||||||
cc_host = FLAGS.cc_host
|
ec2_host = FLAGS.ec2_host
|
||||||
# NOTE(vish): Always use the dmz since it is used from inside the
|
# NOTE(vish): Always use the dmz since it is used from inside the
|
||||||
# instance
|
# instance
|
||||||
s3_host = FLAGS.s3_dmz
|
s3_host = FLAGS.s3_dmz
|
||||||
if host:
|
if host:
|
||||||
s3_host = host
|
s3_host = host
|
||||||
cc_host = host
|
ec2_host = host
|
||||||
rc = open(FLAGS.credentials_template).read()
|
rc = open(FLAGS.credentials_template).read()
|
||||||
rc = rc % {'access': user.access,
|
rc = rc % {'access': user.access,
|
||||||
'project': pid,
|
'project': pid,
|
||||||
'secret': user.secret,
|
'secret': user.secret,
|
||||||
'ec2': '%s://%s:%s%s' % (FLAGS.ec2_prefix,
|
'ec2': '%s://%s:%s%s' % (FLAGS.ec2_scheme,
|
||||||
cc_host,
|
ec2_host,
|
||||||
FLAGS.cc_port,
|
FLAGS.ec2_port,
|
||||||
FLAGS.ec2_suffix),
|
FLAGS.ec2_path),
|
||||||
's3': 'http://%s:%s' % (s3_host, FLAGS.s3_port),
|
's3': 'http://%s:%s' % (s3_host, FLAGS.s3_port),
|
||||||
'os': '%s://%s:%s%s' % (FLAGS.os_prefix,
|
'os': '%s://%s:%s%s' % (FLAGS.osapi_scheme,
|
||||||
cc_host,
|
ec2_host,
|
||||||
FLAGS.osapi_port,
|
FLAGS.osapi_port,
|
||||||
FLAGS.os_suffix),
|
FLAGS.osapi_path),
|
||||||
'user': user.name,
|
'user': user.name,
|
||||||
'nova': FLAGS.ca_file,
|
'nova': FLAGS.ca_file,
|
||||||
'cert': FLAGS.credential_cert_file,
|
'cert': FLAGS.credential_cert_file,
|
||||||
|
@@ -254,14 +254,15 @@ DEFINE_string('rabbit_virtual_host', '/', 'rabbit virtual host')
|
|||||||
DEFINE_integer('rabbit_retry_interval', 10, 'rabbit connection retry interval')
|
DEFINE_integer('rabbit_retry_interval', 10, 'rabbit connection retry interval')
|
||||||
DEFINE_integer('rabbit_max_retries', 12, 'rabbit connection attempts')
|
DEFINE_integer('rabbit_max_retries', 12, 'rabbit connection attempts')
|
||||||
DEFINE_string('control_exchange', 'nova', 'the main exchange to connect to')
|
DEFINE_string('control_exchange', 'nova', 'the main exchange to connect to')
|
||||||
DEFINE_string('ec2_prefix', 'http', 'prefix for ec2')
|
DEFINE_string('ec2_host', '$my_ip', 'ip of api server')
|
||||||
DEFINE_string('os_prefix', 'http', 'prefix for openstack')
|
DEFINE_string('ec2_dmz_host', '$my_ip', 'internal ip of api server')
|
||||||
DEFINE_string('cc_host', '$my_ip', 'ip of api server')
|
DEFINE_integer('ec2_port', 8773, 'cloud controller port')
|
||||||
DEFINE_string('cc_dmz', '$my_ip', 'internal ip of api server')
|
DEFINE_string('ec2_scheme', 'http', 'prefix for ec2')
|
||||||
DEFINE_integer('cc_port', 8773, 'cloud controller port')
|
DEFINE_string('ec2_path', '/services/Cloud', 'suffix for ec2')
|
||||||
|
DEFINE_string('osapi_host', '$my_ip', 'ip of api server')
|
||||||
|
DEFINE_string('osapi_scheme', 'http', 'prefix for openstack')
|
||||||
DEFINE_integer('osapi_port', 8774, 'OpenStack API port')
|
DEFINE_integer('osapi_port', 8774, 'OpenStack API port')
|
||||||
DEFINE_string('ec2_suffix', '/services/Cloud', 'suffix for ec2')
|
DEFINE_string('osapi_path', '/v1.0/', 'suffix for openstack')
|
||||||
DEFINE_string('os_suffix', '/v1.0/', 'suffix for openstack')
|
|
||||||
|
|
||||||
DEFINE_string('default_project', 'openstack', 'default project for openstack')
|
DEFINE_string('default_project', 'openstack', 'default project for openstack')
|
||||||
DEFINE_string('default_image', 'ami-11111',
|
DEFINE_string('default_image', 'ami-11111',
|
||||||
|
@@ -116,6 +116,8 @@ def basicConfig():
|
|||||||
handler.setFormatter(_formatter)
|
handler.setFormatter(_formatter)
|
||||||
if FLAGS.verbose:
|
if FLAGS.verbose:
|
||||||
logging.root.setLevel(logging.DEBUG)
|
logging.root.setLevel(logging.DEBUG)
|
||||||
|
else:
|
||||||
|
logging.root.setLevel(logging.INFO)
|
||||||
if FLAGS.use_syslog:
|
if FLAGS.use_syslog:
|
||||||
syslog = SysLogHandler(address='/dev/log')
|
syslog = SysLogHandler(address='/dev/log')
|
||||||
syslog.setFormatter(_formatter)
|
syslog.setFormatter(_formatter)
|
||||||
|
@@ -20,21 +20,31 @@ import unittest
|
|||||||
import webob
|
import webob
|
||||||
|
|
||||||
from nova import context
|
from nova import context
|
||||||
from nova import exception
|
|
||||||
from nova import flags
|
from nova import flags
|
||||||
from nova import test
|
from nova import test
|
||||||
from nova.api import ec2
|
from nova.api import ec2
|
||||||
from nova.auth import manager
|
from nova.auth import manager
|
||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
|
|
||||||
|
|
||||||
class Context(object):
|
class FakeControllerClass(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class FakeApiRequest(object):
|
||||||
|
def __init__(self, action):
|
||||||
|
self.controller = FakeControllerClass()
|
||||||
|
self.action = action
|
||||||
|
|
||||||
|
|
||||||
class AccessTestCase(test.TestCase):
|
class AccessTestCase(test.TestCase):
|
||||||
|
def _env_for(self, ctxt, action):
|
||||||
|
env = {}
|
||||||
|
env['ec2.context'] = ctxt
|
||||||
|
env['ec2.request'] = FakeApiRequest(action)
|
||||||
|
return env
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(AccessTestCase, self).setUp()
|
super(AccessTestCase, self).setUp()
|
||||||
um = manager.AuthManager()
|
um = manager.AuthManager()
|
||||||
@@ -64,7 +74,7 @@ class AccessTestCase(test.TestCase):
|
|||||||
return ['']
|
return ['']
|
||||||
|
|
||||||
self.mw = ec2.Authorizer(noopWSGIApp)
|
self.mw = ec2.Authorizer(noopWSGIApp)
|
||||||
self.mw.action_roles = {'str': {
|
self.mw.action_roles = {'FakeControllerClass': {
|
||||||
'_allow_all': ['all'],
|
'_allow_all': ['all'],
|
||||||
'_allow_none': [],
|
'_allow_none': [],
|
||||||
'_allow_project_manager': ['projectmanager'],
|
'_allow_project_manager': ['projectmanager'],
|
||||||
@@ -84,9 +94,7 @@ class AccessTestCase(test.TestCase):
|
|||||||
|
|
||||||
def response_status(self, user, methodName):
|
def response_status(self, user, methodName):
|
||||||
ctxt = context.RequestContext(user, self.project)
|
ctxt = context.RequestContext(user, self.project)
|
||||||
environ = {'ec2.context': ctxt,
|
environ = self._env_for(ctxt, methodName)
|
||||||
'ec2.controller': 'some string',
|
|
||||||
'ec2.action': methodName}
|
|
||||||
req = webob.Request.blank('/', environ)
|
req = webob.Request.blank('/', environ)
|
||||||
resp = req.get_response(self.mw)
|
resp = req.get_response(self.mw)
|
||||||
return resp.status_int
|
return resp.status_int
|
||||||
|
@@ -26,9 +26,8 @@ import StringIO
|
|||||||
import webob
|
import webob
|
||||||
|
|
||||||
from nova import context
|
from nova import context
|
||||||
from nova import flags
|
|
||||||
from nova import test
|
from nova import test
|
||||||
from nova import api
|
from nova.api import ec2
|
||||||
from nova.api.ec2 import cloud
|
from nova.api.ec2 import cloud
|
||||||
from nova.api.ec2 import apirequest
|
from nova.api.ec2 import apirequest
|
||||||
from nova.auth import manager
|
from nova.auth import manager
|
||||||
@@ -100,12 +99,10 @@ class ApiEc2TestCase(test.TestCase):
|
|||||||
"""Unit test for the cloud controller on an EC2 API"""
|
"""Unit test for the cloud controller on an EC2 API"""
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(ApiEc2TestCase, self).setUp()
|
super(ApiEc2TestCase, self).setUp()
|
||||||
|
|
||||||
self.manager = manager.AuthManager()
|
self.manager = manager.AuthManager()
|
||||||
|
|
||||||
self.host = '127.0.0.1'
|
self.host = '127.0.0.1'
|
||||||
|
self.app = ec2.Authenticate(ec2.Requestify(ec2.Executor(),
|
||||||
self.app = api.API('ec2')
|
'nova.api.ec2.cloud.CloudController'))
|
||||||
|
|
||||||
def expect_http(self, host=None, is_secure=False):
|
def expect_http(self, host=None, is_secure=False):
|
||||||
"""Returns a new EC2 connection"""
|
"""Returns a new EC2 connection"""
|
||||||
|
@@ -21,6 +21,7 @@ import json
|
|||||||
from M2Crypto import BIO
|
from M2Crypto import BIO
|
||||||
from M2Crypto import RSA
|
from M2Crypto import RSA
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@@ -50,6 +51,8 @@ IMAGES_PATH = os.path.join(OSS_TEMPDIR, 'images')
|
|||||||
os.makedirs(IMAGES_PATH)
|
os.makedirs(IMAGES_PATH)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO(termie): these tests are rather fragile, they should at the lest be
|
||||||
|
# wiping database state after each run
|
||||||
class CloudTestCase(test.TestCase):
|
class CloudTestCase(test.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(CloudTestCase, self).setUp()
|
super(CloudTestCase, self).setUp()
|
||||||
@@ -287,6 +290,7 @@ class CloudTestCase(test.TestCase):
|
|||||||
db.service_destroy(self.context, comp1['id'])
|
db.service_destroy(self.context, comp1['id'])
|
||||||
|
|
||||||
def test_instance_update_state(self):
|
def test_instance_update_state(self):
|
||||||
|
# TODO(termie): what is this code even testing?
|
||||||
def instance(num):
|
def instance(num):
|
||||||
return {
|
return {
|
||||||
'reservation_id': 'r-1',
|
'reservation_id': 'r-1',
|
||||||
@@ -305,7 +309,8 @@ class CloudTestCase(test.TestCase):
|
|||||||
'state': 0x01,
|
'state': 0x01,
|
||||||
'user_data': ''}
|
'user_data': ''}
|
||||||
rv = self.cloud._format_describe_instances(self.context)
|
rv = self.cloud._format_describe_instances(self.context)
|
||||||
self.assert_(len(rv['reservationSet']) == 0)
|
logging.error(str(rv))
|
||||||
|
self.assertEqual(len(rv['reservationSet']), 0)
|
||||||
|
|
||||||
# simulate launch of 5 instances
|
# simulate launch of 5 instances
|
||||||
# self.cloud.instances['pending'] = {}
|
# self.cloud.instances['pending'] = {}
|
||||||
@@ -368,6 +373,7 @@ class CloudTestCase(test.TestCase):
|
|||||||
self.assertEqual('Foo Img', img.metadata['description'])
|
self.assertEqual('Foo Img', img.metadata['description'])
|
||||||
self._fake_set_image_description(self.context, 'ami-testing', '')
|
self._fake_set_image_description(self.context, 'ami-testing', '')
|
||||||
self.assertEqual('', img.metadata['description'])
|
self.assertEqual('', img.metadata['description'])
|
||||||
|
shutil.rmtree(pathdir)
|
||||||
|
|
||||||
def test_update_of_instance_display_fields(self):
|
def test_update_of_instance_display_fields(self):
|
||||||
inst = db.instance_create(self.context, {})
|
inst = db.instance_create(self.context, {})
|
||||||
|
@@ -32,8 +32,9 @@ from nova import utils
|
|||||||
from nova.auth import manager
|
from nova.auth import manager
|
||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
|
||||||
LOG = logging.getLogger('nova.tests.compute')
|
LOG = logging.getLogger('nova.tests.compute')
|
||||||
|
FLAGS = flags.FLAGS
|
||||||
|
flags.DECLARE('stub_network', 'nova.compute.manager')
|
||||||
|
|
||||||
|
|
||||||
class ComputeTestCase(test.TestCase):
|
class ComputeTestCase(test.TestCase):
|
||||||
@@ -75,7 +76,7 @@ class ComputeTestCase(test.TestCase):
|
|||||||
ref = self.compute_api.create(self.context,
|
ref = self.compute_api.create(self.context,
|
||||||
FLAGS.default_instance_type, None, **instance)
|
FLAGS.default_instance_type, None, **instance)
|
||||||
try:
|
try:
|
||||||
self.assertNotEqual(ref[0].display_name, None)
|
self.assertNotEqual(ref[0]['display_name'], None)
|
||||||
finally:
|
finally:
|
||||||
db.instance_destroy(self.context, ref[0]['id'])
|
db.instance_destroy(self.context, ref[0]['id'])
|
||||||
|
|
||||||
@@ -86,10 +87,14 @@ class ComputeTestCase(test.TestCase):
|
|||||||
'user_id': self.user.id,
|
'user_id': self.user.id,
|
||||||
'project_id': self.project.id}
|
'project_id': self.project.id}
|
||||||
group = db.security_group_create(self.context, values)
|
group = db.security_group_create(self.context, values)
|
||||||
ref = self.compute_api.create(self.context,
|
ref = self.compute_api.create(
|
||||||
FLAGS.default_instance_type, None, security_group=['default'])
|
self.context,
|
||||||
|
instance_type=FLAGS.default_instance_type,
|
||||||
|
image_id=None,
|
||||||
|
security_group=['default'])
|
||||||
try:
|
try:
|
||||||
self.assertEqual(len(ref[0]['security_groups']), 1)
|
self.assertEqual(len(db.security_group_get_by_instance(
|
||||||
|
self.context, ref[0]['id'])), 1)
|
||||||
finally:
|
finally:
|
||||||
db.security_group_destroy(self.context, group['id'])
|
db.security_group_destroy(self.context, group['id'])
|
||||||
db.instance_destroy(self.context, ref[0]['id'])
|
db.instance_destroy(self.context, ref[0]['id'])
|
||||||
|
@@ -111,12 +111,14 @@ class ConsoleTestCase(test.TestCase):
|
|||||||
|
|
||||||
console_instances = [con['instance_id'] for con in pool.consoles]
|
console_instances = [con['instance_id'] for con in pool.consoles]
|
||||||
self.assert_(instance_id in console_instances)
|
self.assert_(instance_id in console_instances)
|
||||||
|
db.instance_destroy(self.context, instance_id)
|
||||||
|
|
||||||
def test_add_console_does_not_duplicate(self):
|
def test_add_console_does_not_duplicate(self):
|
||||||
instance_id = self._create_instance()
|
instance_id = self._create_instance()
|
||||||
cons1 = self.console.add_console(self.context, instance_id)
|
cons1 = self.console.add_console(self.context, instance_id)
|
||||||
cons2 = self.console.add_console(self.context, instance_id)
|
cons2 = self.console.add_console(self.context, instance_id)
|
||||||
self.assertEqual(cons1, cons2)
|
self.assertEqual(cons1, cons2)
|
||||||
|
db.instance_destroy(self.context, instance_id)
|
||||||
|
|
||||||
def test_remove_console(self):
|
def test_remove_console(self):
|
||||||
instance_id = self._create_instance()
|
instance_id = self._create_instance()
|
||||||
@@ -127,3 +129,4 @@ class ConsoleTestCase(test.TestCase):
|
|||||||
db.console_get,
|
db.console_get,
|
||||||
self.context,
|
self.context,
|
||||||
console_id)
|
console_id)
|
||||||
|
db.instance_destroy(self.context, instance_id)
|
||||||
|
103
nova/tests/test_direct.py
Normal file
103
nova/tests/test_direct.py
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
"""Tests for Direct API."""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import webob
|
||||||
|
|
||||||
|
from nova import compute
|
||||||
|
from nova import context
|
||||||
|
from nova import exception
|
||||||
|
from nova import test
|
||||||
|
from nova import utils
|
||||||
|
from nova.api import direct
|
||||||
|
from nova.tests import test_cloud
|
||||||
|
|
||||||
|
|
||||||
|
class FakeService(object):
|
||||||
|
def echo(self, context, data):
|
||||||
|
return {'data': data}
|
||||||
|
|
||||||
|
def context(self, context):
|
||||||
|
return {'user': context.user_id,
|
||||||
|
'project': context.project_id}
|
||||||
|
|
||||||
|
|
||||||
|
class DirectTestCase(test.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(DirectTestCase, self).setUp()
|
||||||
|
direct.register_service('fake', FakeService())
|
||||||
|
self.router = direct.PostParamsMiddleware(
|
||||||
|
direct.JsonParamsMiddleware(
|
||||||
|
direct.Router()))
|
||||||
|
self.auth_router = direct.DelegatedAuthMiddleware(self.router)
|
||||||
|
self.context = context.RequestContext('user1', 'proj1')
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
direct.ROUTES = {}
|
||||||
|
|
||||||
|
def test_delegated_auth(self):
|
||||||
|
req = webob.Request.blank('/fake/context')
|
||||||
|
req.headers['X-OpenStack-User'] = 'user1'
|
||||||
|
req.headers['X-OpenStack-Project'] = 'proj1'
|
||||||
|
resp = req.get_response(self.auth_router)
|
||||||
|
data = json.loads(resp.body)
|
||||||
|
self.assertEqual(data['user'], 'user1')
|
||||||
|
self.assertEqual(data['project'], 'proj1')
|
||||||
|
|
||||||
|
def test_json_params(self):
|
||||||
|
req = webob.Request.blank('/fake/echo')
|
||||||
|
req.environ['openstack.context'] = self.context
|
||||||
|
req.method = 'POST'
|
||||||
|
req.body = 'json=%s' % json.dumps({'data': 'foo'})
|
||||||
|
resp = req.get_response(self.router)
|
||||||
|
resp_parsed = json.loads(resp.body)
|
||||||
|
self.assertEqual(resp_parsed['data'], 'foo')
|
||||||
|
|
||||||
|
def test_post_params(self):
|
||||||
|
req = webob.Request.blank('/fake/echo')
|
||||||
|
req.environ['openstack.context'] = self.context
|
||||||
|
req.method = 'POST'
|
||||||
|
req.body = 'data=foo'
|
||||||
|
resp = req.get_response(self.router)
|
||||||
|
resp_parsed = json.loads(resp.body)
|
||||||
|
self.assertEqual(resp_parsed['data'], 'foo')
|
||||||
|
|
||||||
|
def test_proxy(self):
|
||||||
|
proxy = direct.Proxy(self.router)
|
||||||
|
rv = proxy.fake.echo(self.context, data='baz')
|
||||||
|
self.assertEqual(rv['data'], 'baz')
|
||||||
|
|
||||||
|
|
||||||
|
class DirectCloudTestCase(test_cloud.CloudTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(DirectCloudTestCase, self).setUp()
|
||||||
|
compute_handle = compute.API(image_service=self.cloud.image_service,
|
||||||
|
network_api=self.cloud.network_api,
|
||||||
|
volume_api=self.cloud.volume_api)
|
||||||
|
direct.register_service('compute', compute_handle)
|
||||||
|
self.router = direct.JsonParamsMiddleware(direct.Router())
|
||||||
|
proxy = direct.Proxy(self.router)
|
||||||
|
self.cloud.compute_api = proxy.compute
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
super(DirectCloudTestCase, self).tearDown()
|
||||||
|
direct.ROUTES = {}
|
@@ -122,10 +122,10 @@ class LibvirtConnTestCase(test.TestCase):
|
|||||||
|
|
||||||
if rescue:
|
if rescue:
|
||||||
check = (lambda t: t.find('./os/kernel').text.split('/')[1],
|
check = (lambda t: t.find('./os/kernel').text.split('/')[1],
|
||||||
'rescue-kernel')
|
'kernel.rescue')
|
||||||
check_list.append(check)
|
check_list.append(check)
|
||||||
check = (lambda t: t.find('./os/initrd').text.split('/')[1],
|
check = (lambda t: t.find('./os/initrd').text.split('/')[1],
|
||||||
'rescue-ramdisk')
|
'ramdisk.rescue')
|
||||||
check_list.append(check)
|
check_list.append(check)
|
||||||
else:
|
else:
|
||||||
if expect_kernel:
|
if expect_kernel:
|
||||||
@@ -161,13 +161,16 @@ class LibvirtConnTestCase(test.TestCase):
|
|||||||
if rescue:
|
if rescue:
|
||||||
common_checks += [
|
common_checks += [
|
||||||
(lambda t: t.findall('./devices/disk/source')[0].get(
|
(lambda t: t.findall('./devices/disk/source')[0].get(
|
||||||
'file').split('/')[1], 'rescue-disk'),
|
'file').split('/')[1], 'disk.rescue'),
|
||||||
(lambda t: t.findall('./devices/disk/source')[1].get(
|
(lambda t: t.findall('./devices/disk/source')[1].get(
|
||||||
'file').split('/')[1], 'disk')]
|
'file').split('/')[1], 'disk')]
|
||||||
else:
|
else:
|
||||||
common_checks += [(lambda t: t.findall(
|
common_checks += [(lambda t: t.findall(
|
||||||
'./devices/disk/source')[0].get('file').split('/')[1],
|
'./devices/disk/source')[0].get('file').split('/')[1],
|
||||||
'disk')]
|
'disk')]
|
||||||
|
common_checks += [(lambda t: t.findall(
|
||||||
|
'./devices/disk/source')[1].get('file').split('/')[1],
|
||||||
|
'disk.local')]
|
||||||
|
|
||||||
for (libvirt_type, (expected_uri, checks)) in type_uri_map.iteritems():
|
for (libvirt_type, (expected_uri, checks)) in type_uri_map.iteritems():
|
||||||
FLAGS.libvirt_type = libvirt_type
|
FLAGS.libvirt_type = libvirt_type
|
||||||
|
@@ -34,6 +34,7 @@ from nova.virt.xenapi import volume_utils
|
|||||||
from nova.virt.xenapi.vmops import SimpleDH
|
from nova.virt.xenapi.vmops import SimpleDH
|
||||||
from nova.tests.db import fakes as db_fakes
|
from nova.tests.db import fakes as db_fakes
|
||||||
from nova.tests.xenapi import stubs
|
from nova.tests.xenapi import stubs
|
||||||
|
from nova.tests.glance import stubs as glance_stubs
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
|
|
||||||
@@ -108,18 +109,16 @@ class XenAPIVolumeTestCase(test.TestCase):
|
|||||||
conn = xenapi_conn.get_connection(False)
|
conn = xenapi_conn.get_connection(False)
|
||||||
volume = self._create_volume()
|
volume = self._create_volume()
|
||||||
instance = db.instance_create(self.values)
|
instance = db.instance_create(self.values)
|
||||||
xenapi_fake.create_vm(instance.name, 'Running')
|
vm = xenapi_fake.create_vm(instance.name, 'Running')
|
||||||
result = conn.attach_volume(instance.name, volume['id'], '/dev/sdc')
|
result = conn.attach_volume(instance.name, volume['id'], '/dev/sdc')
|
||||||
|
|
||||||
def check():
|
def check():
|
||||||
# check that the VM has a VBD attached to it
|
# check that the VM has a VBD attached to it
|
||||||
# Get XenAPI reference for the VM
|
|
||||||
vms = xenapi_fake.get_all('VM')
|
|
||||||
# Get XenAPI record for VBD
|
# Get XenAPI record for VBD
|
||||||
vbds = xenapi_fake.get_all('VBD')
|
vbds = xenapi_fake.get_all('VBD')
|
||||||
vbd = xenapi_fake.get_record('VBD', vbds[0])
|
vbd = xenapi_fake.get_record('VBD', vbds[0])
|
||||||
vm_ref = vbd['VM']
|
vm_ref = vbd['VM']
|
||||||
self.assertEqual(vm_ref, vms[0])
|
self.assertEqual(vm_ref, vm)
|
||||||
|
|
||||||
check()
|
check()
|
||||||
|
|
||||||
@@ -157,9 +156,14 @@ class XenAPIVMTestCase(test.TestCase):
|
|||||||
FLAGS.xenapi_connection_url = 'test_url'
|
FLAGS.xenapi_connection_url = 'test_url'
|
||||||
FLAGS.xenapi_connection_password = 'test_pass'
|
FLAGS.xenapi_connection_password = 'test_pass'
|
||||||
xenapi_fake.reset()
|
xenapi_fake.reset()
|
||||||
|
xenapi_fake.create_local_srs()
|
||||||
db_fakes.stub_out_db_instance_api(self.stubs)
|
db_fakes.stub_out_db_instance_api(self.stubs)
|
||||||
xenapi_fake.create_network('fake', FLAGS.flat_network_bridge)
|
xenapi_fake.create_network('fake', FLAGS.flat_network_bridge)
|
||||||
stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
|
stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
|
||||||
|
stubs.stubout_get_this_vm_uuid(self.stubs)
|
||||||
|
stubs.stubout_stream_disk(self.stubs)
|
||||||
|
glance_stubs.stubout_glance_client(self.stubs,
|
||||||
|
glance_stubs.FakeGlance)
|
||||||
self.conn = xenapi_conn.get_connection(False)
|
self.conn = xenapi_conn.get_connection(False)
|
||||||
|
|
||||||
def test_list_instances_0(self):
|
def test_list_instances_0(self):
|
||||||
@@ -207,40 +211,70 @@ class XenAPIVMTestCase(test.TestCase):
|
|||||||
|
|
||||||
check()
|
check()
|
||||||
|
|
||||||
def test_spawn(self):
|
def check_vm_record(self, conn):
|
||||||
instance = self._create_instance()
|
instances = conn.list_instances()
|
||||||
|
self.assertEquals(instances, [1])
|
||||||
|
|
||||||
def check():
|
# Get Nova record for VM
|
||||||
instances = self.conn.list_instances()
|
vm_info = conn.get_info(1)
|
||||||
self.assertEquals(instances, [1])
|
|
||||||
|
|
||||||
# Get Nova record for VM
|
# Get XenAPI record for VM
|
||||||
vm_info = self.conn.get_info(1)
|
vms = [rec for ref, rec
|
||||||
|
in xenapi_fake.get_all_records('VM').iteritems()
|
||||||
|
if not rec['is_control_domain']]
|
||||||
|
vm = vms[0]
|
||||||
|
|
||||||
# Get XenAPI record for VM
|
# Check that m1.large above turned into the right thing.
|
||||||
vms = xenapi_fake.get_all('VM')
|
instance_type = instance_types.INSTANCE_TYPES['m1.large']
|
||||||
vm = xenapi_fake.get_record('VM', vms[0])
|
mem_kib = long(instance_type['memory_mb']) << 10
|
||||||
|
mem_bytes = str(mem_kib << 10)
|
||||||
|
vcpus = instance_type['vcpus']
|
||||||
|
self.assertEquals(vm_info['max_mem'], mem_kib)
|
||||||
|
self.assertEquals(vm_info['mem'], mem_kib)
|
||||||
|
self.assertEquals(vm['memory_static_max'], mem_bytes)
|
||||||
|
self.assertEquals(vm['memory_dynamic_max'], mem_bytes)
|
||||||
|
self.assertEquals(vm['memory_dynamic_min'], mem_bytes)
|
||||||
|
self.assertEquals(vm['VCPUs_max'], str(vcpus))
|
||||||
|
self.assertEquals(vm['VCPUs_at_startup'], str(vcpus))
|
||||||
|
|
||||||
# Check that m1.large above turned into the right thing.
|
# Check that the VM is running according to Nova
|
||||||
instance_type = instance_types.INSTANCE_TYPES['m1.large']
|
self.assertEquals(vm_info['state'], power_state.RUNNING)
|
||||||
mem_kib = long(instance_type['memory_mb']) << 10
|
|
||||||
mem_bytes = str(mem_kib << 10)
|
|
||||||
vcpus = instance_type['vcpus']
|
|
||||||
self.assertEquals(vm_info['max_mem'], mem_kib)
|
|
||||||
self.assertEquals(vm_info['mem'], mem_kib)
|
|
||||||
self.assertEquals(vm['memory_static_max'], mem_bytes)
|
|
||||||
self.assertEquals(vm['memory_dynamic_max'], mem_bytes)
|
|
||||||
self.assertEquals(vm['memory_dynamic_min'], mem_bytes)
|
|
||||||
self.assertEquals(vm['VCPUs_max'], str(vcpus))
|
|
||||||
self.assertEquals(vm['VCPUs_at_startup'], str(vcpus))
|
|
||||||
|
|
||||||
# Check that the VM is running according to Nova
|
# Check that the VM is running according to XenAPI.
|
||||||
self.assertEquals(vm_info['state'], power_state.RUNNING)
|
self.assertEquals(vm['power_state'], 'Running')
|
||||||
|
|
||||||
# Check that the VM is running according to XenAPI.
|
def _test_spawn(self, image_id, kernel_id, ramdisk_id):
|
||||||
self.assertEquals(vm['power_state'], 'Running')
|
stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
|
||||||
|
values = {'name': 1,
|
||||||
|
'id': 1,
|
||||||
|
'project_id': self.project.id,
|
||||||
|
'user_id': self.user.id,
|
||||||
|
'image_id': image_id,
|
||||||
|
'kernel_id': kernel_id,
|
||||||
|
'ramdisk_id': ramdisk_id,
|
||||||
|
'instance_type': 'm1.large',
|
||||||
|
'mac_address': 'aa:bb:cc:dd:ee:ff',
|
||||||
|
}
|
||||||
|
conn = xenapi_conn.get_connection(False)
|
||||||
|
instance = db.instance_create(values)
|
||||||
|
conn.spawn(instance)
|
||||||
|
self.check_vm_record(conn)
|
||||||
|
|
||||||
check()
|
def test_spawn_raw_objectstore(self):
|
||||||
|
FLAGS.xenapi_image_service = 'objectstore'
|
||||||
|
self._test_spawn(1, None, None)
|
||||||
|
|
||||||
|
def test_spawn_objectstore(self):
|
||||||
|
FLAGS.xenapi_image_service = 'objectstore'
|
||||||
|
self._test_spawn(1, 2, 3)
|
||||||
|
|
||||||
|
def test_spawn_raw_glance(self):
|
||||||
|
FLAGS.xenapi_image_service = 'glance'
|
||||||
|
self._test_spawn(1, None, None)
|
||||||
|
|
||||||
|
def test_spawn_glance(self):
|
||||||
|
FLAGS.xenapi_image_service = 'glance'
|
||||||
|
self._test_spawn(1, 2, 3)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
super(XenAPIVMTestCase, self).tearDown()
|
super(XenAPIVMTestCase, self).tearDown()
|
||||||
|
@@ -115,6 +115,21 @@ def stub_out_get_target(stubs):
|
|||||||
stubs.Set(volume_utils, '_get_target', fake_get_target)
|
stubs.Set(volume_utils, '_get_target', fake_get_target)
|
||||||
|
|
||||||
|
|
||||||
|
def stubout_get_this_vm_uuid(stubs):
|
||||||
|
def f():
|
||||||
|
vms = [rec['uuid'] for ref, rec
|
||||||
|
in fake.get_all_records('VM').iteritems()
|
||||||
|
if rec['is_control_domain']]
|
||||||
|
return vms[0]
|
||||||
|
stubs.Set(vm_utils, 'get_this_vm_uuid', f)
|
||||||
|
|
||||||
|
|
||||||
|
def stubout_stream_disk(stubs):
|
||||||
|
def f(_1, _2, _3, _4):
|
||||||
|
pass
|
||||||
|
stubs.Set(vm_utils, '_stream_disk', f)
|
||||||
|
|
||||||
|
|
||||||
class FakeSessionForVMTests(fake.SessionBase):
|
class FakeSessionForVMTests(fake.SessionBase):
|
||||||
""" Stubs out a XenAPISession for VM tests """
|
""" Stubs out a XenAPISession for VM tests """
|
||||||
def __init__(self, uri):
|
def __init__(self, uri):
|
||||||
@@ -124,7 +139,10 @@ class FakeSessionForVMTests(fake.SessionBase):
|
|||||||
return self.xenapi.network.get_all_records()
|
return self.xenapi.network.get_all_records()
|
||||||
|
|
||||||
def host_call_plugin(self, _1, _2, _3, _4, _5):
|
def host_call_plugin(self, _1, _2, _3, _4, _5):
|
||||||
return ''
|
sr_ref = fake.get_all('SR')[0]
|
||||||
|
vdi_ref = fake.create_vdi('', False, sr_ref, False)
|
||||||
|
vdi_rec = fake.get_record('VDI', vdi_ref)
|
||||||
|
return '<string>%s</string>' % vdi_rec['uuid']
|
||||||
|
|
||||||
def VM_start(self, _1, ref, _2, _3):
|
def VM_start(self, _1, ref, _2, _3):
|
||||||
vm = fake.get_record('VM', ref)
|
vm = fake.get_record('VM', ref)
|
||||||
@@ -159,10 +177,6 @@ class FakeSessionForVolumeTests(fake.SessionBase):
|
|||||||
def __init__(self, uri):
|
def __init__(self, uri):
|
||||||
super(FakeSessionForVolumeTests, self).__init__(uri)
|
super(FakeSessionForVolumeTests, self).__init__(uri)
|
||||||
|
|
||||||
def VBD_plug(self, _1, ref):
|
|
||||||
rec = fake.get_record('VBD', ref)
|
|
||||||
rec['currently-attached'] = True
|
|
||||||
|
|
||||||
def VDI_introduce(self, _1, uuid, _2, _3, _4, _5,
|
def VDI_introduce(self, _1, uuid, _2, _3, _4, _5,
|
||||||
_6, _7, _8, _9, _10, _11):
|
_6, _7, _8, _9, _10, _11):
|
||||||
valid_vdi = False
|
valid_vdi = False
|
||||||
|
Reference in New Issue
Block a user