summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTushar Patil <tushar.vitthal.patil@gmail.com>2011-08-10 14:16:13 -0700
committerTushar Patil <tushar.vitthal.patil@gmail.com>2011-08-10 14:16:13 -0700
commit4f26dad3e25dcd3a48528e94035c63db9d23efbf (patch)
tree25d90fc9fa09a8086137f8b7beddb6f2336fc4e4
parentf73b6dc8e90b763da1fe86496fc6fd6a80b99f0a (diff)
parente78499c51b1cec93c0bdaadbcb78e71bf66d473d (diff)
downloadnova-4f26dad3e25dcd3a48528e94035c63db9d23efbf.tar.gz
nova-4f26dad3e25dcd3a48528e94035c63db9d23efbf.tar.xz
nova-4f26dad3e25dcd3a48528e94035c63db9d23efbf.zip
Fixed broken unit testcases
-rwxr-xr-xbin/nova-import-canonical-imagestore110
-rw-r--r--nova/api/openstack/__init__.py9
-rw-r--r--nova/api/openstack/contrib/floating_ips.py2
-rw-r--r--nova/api/openstack/contrib/keypairs.py145
-rw-r--r--nova/api/openstack/create_instance_helper.py2
-rw-r--r--nova/api/openstack/extensions.py6
-rw-r--r--nova/compute/api.py19
-rw-r--r--nova/crypto.py10
-rw-r--r--nova/db/sqlalchemy/api.py9
-rw-r--r--nova/objectstore/s3server.py5
-rw-r--r--nova/scheduler/least_cost.py3
-rw-r--r--nova/scheduler/manager.py4
-rw-r--r--nova/scheduler/zone_aware_scheduler.py4
-rw-r--r--nova/scheduler/zone_manager.py2
-rw-r--r--nova/tests/api/openstack/contrib/test_keypairs.py99
-rw-r--r--nova/tests/api/openstack/test_extensions.py5
-rw-r--r--nova/tests/api/openstack/test_limits.py5
-rw-r--r--nova/tests/scheduler/test_scheduler.py24
-rw-r--r--nova/tests/test_auth.py7
-rw-r--r--nova/tests/test_compute.py9
-rw-r--r--nova/tests/test_instance_types_extra_specs.py2
-rw-r--r--nova/tests/test_libvirt.py5
-rw-r--r--nova/tests/test_xenapi.py18
-rw-r--r--nova/virt/fake.py2
-rw-r--r--nova/virt/hyperv.py2
-rw-r--r--nova/virt/vmwareapi/io_util.py5
-rw-r--r--nova/virt/vmwareapi/vif.py2
-rw-r--r--nova/virt/vmwareapi/vim_util.py10
-rw-r--r--nova/virt/vmwareapi/vmware_images.py6
-rw-r--r--nova/virt/vmwareapi_conn.py2
-rw-r--r--nova/virt/xenapi/vm_utils.py2
-rw-r--r--nova/virt/xenapi_conn.py2
-rw-r--r--setup.py4
33 files changed, 372 insertions, 169 deletions
diff --git a/bin/nova-import-canonical-imagestore b/bin/nova-import-canonical-imagestore
deleted file mode 100755
index 404ae37f4..000000000
--- a/bin/nova-import-canonical-imagestore
+++ /dev/null
@@ -1,110 +0,0 @@
-#!/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.
-
-"""
- Download images from Canonical Image Store
-"""
-
-import gettext
-import json
-import os
-import tempfile
-import shutil
-import subprocess
-import sys
-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)
-
-gettext.install('nova', unicode=1)
-
-from nova import flags
-from nova import log as logging
-from nova import utils
-from nova.objectstore import image
-
-FLAGS = flags.FLAGS
-
-API_URL = 'https://imagestore.canonical.com/api/dashboard'
-
-
-def get_images():
- """Get a list of the images from the imagestore URL."""
- images = json.load(urllib2.urlopen(API_URL))['images']
- images = [img for img in images if img['title'].find('amd64') > -1]
- return images
-
-
-def download(img):
- """Download an image to the local filesystem."""
- # FIXME(ja): add checksum/signature checks
- tempdir = tempfile.mkdtemp(prefix='cis-')
-
- kernel_id = None
- ramdisk_id = None
-
- for f in img['files']:
- if f['kind'] == 'kernel':
- dest = os.path.join(tempdir, 'kernel')
- subprocess.call(['curl', '--fail', f['url'], '-o', dest])
- kernel_id = image.Image.add(dest,
- description='kernel/' + img['title'], kernel=True)
-
- for f in img['files']:
- if f['kind'] == 'ramdisk':
- dest = os.path.join(tempdir, 'ramdisk')
- subprocess.call(['curl', '--fail', f['url'], '-o', dest])
- ramdisk_id = image.Image.add(dest,
- description='ramdisk/' + img['title'], ramdisk=True)
-
- for f in img['files']:
- if f['kind'] == 'image':
- dest = os.path.join(tempdir, 'image')
- subprocess.call(['curl', '--fail', f['url'], '-o', dest])
- ramdisk_id = image.Image.add(dest,
- description=img['title'], kernel=kernel_id, ramdisk=ramdisk_id)
-
- shutil.rmtree(tempdir)
-
-
-def main():
- """Main entry point."""
- utils.default_flagfile()
- argv = FLAGS(sys.argv)
- logging.setup()
- images = get_images()
-
- if len(argv) == 2:
- for img in images:
- if argv[1] == 'all' or argv[1] == img['title']:
- download(img)
- else:
- print 'usage: %s (title|all)'
- print 'available images:'
- for img in images:
- print img['title']
-
-if __name__ == '__main__':
- main()
diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py
index 4d49df2ad..e0c1e9d04 100644
--- a/nova/api/openstack/__init__.py
+++ b/nova/api/openstack/__init__.py
@@ -85,7 +85,10 @@ class APIRouter(base_wsgi.Router):
self._setup_routes(mapper)
super(APIRouter, self).__init__(mapper)
- def _setup_routes(self, mapper, version):
+ def _setup_routes(self, mapper):
+ raise NotImplementedError(_("You must implement _setup_routes."))
+
+ def _setup_base_routes(self, mapper, version):
"""Routes common to all versions."""
server_members = self.server_members
@@ -156,7 +159,7 @@ class APIRouterV10(APIRouter):
"""Define routes specific to OpenStack API V1.0."""
def _setup_routes(self, mapper):
- super(APIRouterV10, self)._setup_routes(mapper, '1.0')
+ self._setup_base_routes(mapper, '1.0')
mapper.resource("shared_ip_group", "shared_ip_groups",
collection={'detail': 'GET'},
@@ -172,7 +175,7 @@ class APIRouterV11(APIRouter):
"""Define routes specific to OpenStack API V1.1."""
def _setup_routes(self, mapper):
- super(APIRouterV11, self)._setup_routes(mapper, '1.1')
+ self._setup_base_routes(mapper, '1.1')
image_metadata_controller = image_metadata.create_resource()
diff --git a/nova/api/openstack/contrib/floating_ips.py b/nova/api/openstack/contrib/floating_ips.py
index 52c9c6cf9..2aba1068a 100644
--- a/nova/api/openstack/contrib/floating_ips.py
+++ b/nova/api/openstack/contrib/floating_ips.py
@@ -102,7 +102,7 @@ class FloatingIPController(object):
def delete(self, req, id):
context = req.environ['nova.context']
ip = self.network_api.get_floating_ip(context, id)
-
+
if 'fixed_ip' in ip:
try:
self.disassociate(req, id, '')
diff --git a/nova/api/openstack/contrib/keypairs.py b/nova/api/openstack/contrib/keypairs.py
new file mode 100644
index 000000000..201648ab5
--- /dev/null
+++ b/nova/api/openstack/contrib/keypairs.py
@@ -0,0 +1,145 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 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.
+
+""" Keypair management extension"""
+
+import os
+import shutil
+import tempfile
+
+from webob import exc
+
+from nova import crypto
+from nova import db
+from nova import exception
+from nova.api.openstack import extensions
+
+
+class KeypairController(object):
+ """ Keypair API controller for the Openstack API """
+
+ # TODO(ja): both this file and nova.api.ec2.cloud.py have similar logic.
+ # move the common keypair logic to nova.compute.API?
+
+ def _gen_key(self):
+ """
+ Generate a key
+ """
+ private_key, public_key, fingerprint = crypto.generate_key_pair()
+ return {'private_key': private_key,
+ 'public_key': public_key,
+ 'fingerprint': fingerprint}
+
+ def create(self, req, body):
+ """
+ Create or import keypair.
+
+ Sending name will generate a key and return private_key
+ and fingerprint.
+
+ You can send a public_key to add an existing ssh key
+
+ params: keypair object with:
+ name (required) - string
+ public_key (optional) - string
+ """
+
+ context = req.environ['nova.context']
+ params = body['keypair']
+ name = params['name']
+
+ # NOTE(ja): generation is slow, so shortcut invalid name exception
+ try:
+ db.key_pair_get(context, context.user_id, name)
+ raise exception.KeyPairExists(key_name=name)
+ except exception.NotFound:
+ pass
+
+ keypair = {'user_id': context.user_id,
+ 'name': name}
+
+ # import if public_key is sent
+ if 'public_key' in params:
+ tmpdir = tempfile.mkdtemp()
+ fn = os.path.join(tmpdir, 'import.pub')
+ with open(fn, 'w') as pub:
+ pub.write(params['public_key'])
+ fingerprint = crypto.generate_fingerprint(fn)
+ shutil.rmtree(tmpdir)
+ keypair['public_key'] = params['public_key']
+ keypair['fingerprint'] = fingerprint
+ else:
+ generated_key = self._gen_key()
+ keypair['private_key'] = generated_key['private_key']
+ keypair['public_key'] = generated_key['public_key']
+ keypair['fingerprint'] = generated_key['fingerprint']
+
+ db.key_pair_create(context, keypair)
+ return {'keypair': keypair}
+
+ def delete(self, req, id):
+ """
+ Delete a keypair with a given name
+ """
+ context = req.environ['nova.context']
+ db.key_pair_destroy(context, context.user_id, id)
+ return exc.HTTPAccepted()
+
+ def index(self, req):
+ """
+ List of keypairs for a user
+ """
+ context = req.environ['nova.context']
+ key_pairs = db.key_pair_get_all_by_user(context, context.user_id)
+ rval = []
+ for key_pair in key_pairs:
+ rval.append({'keypair': {
+ 'name': key_pair['name'],
+ 'public_key': key_pair['public_key'],
+ 'fingerprint': key_pair['fingerprint'],
+ }})
+
+ return {'keypairs': rval}
+
+
+class Keypairs(extensions.ExtensionDescriptor):
+
+ def get_name(self):
+ return "Keypairs"
+
+ def get_alias(self):
+ return "os-keypairs"
+
+ def get_description(self):
+ return "Keypair Support"
+
+ def get_namespace(self):
+ return \
+ "http://docs.openstack.org/ext/keypairs/api/v1.1"
+
+ def get_updated(self):
+ return "2011-08-08T00:00:00+00:00"
+
+ def get_resources(self):
+ resources = []
+
+ res = extensions.ResourceExtension(
+ 'os-keypairs',
+ KeypairController())
+
+ resources.append(res)
+ return resources
diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py
index 894d47beb..1425521a9 100644
--- a/nova/api/openstack/create_instance_helper.py
+++ b/nova/api/openstack/create_instance_helper.py
@@ -14,8 +14,6 @@
# under the License.
import base64
-import re
-import webob
from webob import exc
from xml.dom import minidom
diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py
index f2b6342f6..bb407a045 100644
--- a/nova/api/openstack/extensions.py
+++ b/nova/api/openstack/extensions.py
@@ -465,8 +465,12 @@ class ResourceExtension(object):
"""Add top level resources to the OpenStack API in nova."""
def __init__(self, collection, controller, parent=None,
- collection_actions={}, member_actions={},
+ collection_actions=None, member_actions=None,
deserializer=None, serializer=None):
+ if not collection_actions:
+ collection_actions = {}
+ if not member_actions:
+ member_actions = {}
self.collection = collection
self.controller = controller
self.parent = parent
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 4ac0ffef2..91a0c93b2 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -122,8 +122,10 @@ class API(base.Base):
if len(content) > content_limit:
raise quota.QuotaError(code="OnsetFileContentLimitExceeded")
- def _check_metadata_properties_quota(self, context, metadata={}):
+ def _check_metadata_properties_quota(self, context, metadata=None):
"""Enforce quota limits on metadata properties."""
+ if not metadata:
+ metadata = {}
num_metadata = len(metadata)
quota_metadata = quota.allowed_metadata_items(context, num_metadata)
if quota_metadata < num_metadata:
@@ -149,7 +151,7 @@ class API(base.Base):
min_count=None, max_count=None,
display_name='', display_description='',
key_name=None, key_data=None, security_group='default',
- availability_zone=None, user_data=None, metadata={},
+ availability_zone=None, user_data=None, metadata=None,
injected_files=None, admin_password=None, zone_blob=None,
reservation_id=None):
"""Verify all the input parameters regardless of the provisioning
@@ -161,6 +163,8 @@ class API(base.Base):
min_count = 1
if not max_count:
max_count = min_count
+ if not metadata:
+ metadata = {}
num_instances = quota.allowed_instances(context, max_count,
instance_type)
@@ -436,12 +440,16 @@ class API(base.Base):
min_count=None, max_count=None,
display_name='', display_description='',
key_name=None, key_data=None, security_group='default',
- availability_zone=None, user_data=None, metadata={},
+ availability_zone=None, user_data=None, metadata=None,
injected_files=None, admin_password=None, zone_blob=None,
reservation_id=None, block_device_mapping=None):
"""Provision the instances by passing the whole request to
the Scheduler for execution. Returns a Reservation ID
related to the creation of all of these instances."""
+
+ if not metadata:
+ metadata = {}
+
num_instances, base_options, image = self._check_create_parameters(
context, instance_type,
image_href, kernel_id, ramdisk_id,
@@ -466,7 +474,7 @@ class API(base.Base):
min_count=None, max_count=None,
display_name='', display_description='',
key_name=None, key_data=None, security_group='default',
- availability_zone=None, user_data=None, metadata={},
+ availability_zone=None, user_data=None, metadata=None,
injected_files=None, admin_password=None, zone_blob=None,
reservation_id=None, block_device_mapping=None):
"""
@@ -481,6 +489,9 @@ class API(base.Base):
Returns a list of instance dicts.
"""
+ if not metadata:
+ metadata = {}
+
num_instances, base_options, image = self._check_create_parameters(
context, instance_type,
image_href, kernel_id, ramdisk_id,
diff --git a/nova/crypto.py b/nova/crypto.py
index 8d535f426..71bef80f2 100644
--- a/nova/crypto.py
+++ b/nova/crypto.py
@@ -104,6 +104,12 @@ def fetch_ca(project_id=None, chain=True):
return buffer
+def generate_fingerprint(public_key):
+ (out, err) = utils.execute('ssh-keygen', '-q', '-l', '-f', public_key)
+ fingerprint = out.split(' ')[1]
+ return fingerprint
+
+
def generate_key_pair(bits=1024):
# what is the magic 65537?
@@ -111,9 +117,7 @@ def generate_key_pair(bits=1024):
keyfile = os.path.join(tmpdir, 'temp')
utils.execute('ssh-keygen', '-q', '-b', bits, '-N', '',
'-f', keyfile)
- (out, err) = utils.execute('ssh-keygen', '-q', '-l', '-f',
- '%s.pub' % (keyfile))
- fingerprint = out.split(' ')[1]
+ fingerprint = generate_fingerprint('%s.pub' % (keyfile))
private_key = open(keyfile).read()
public_key = open(keyfile + '.pub').read()
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index d78eb65d7..8119cdfb8 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -3348,8 +3348,6 @@ def instance_metadata_update(context, instance_id, metadata, delete):
try:
meta_ref = instance_metadata_get_item(context, instance_id,
meta_key, session)
-
- # if the item doesn't exist, we also need to set key and instance_id
except exception.InstanceMetadataNotFound, e:
meta_ref = models.InstanceMetadata()
item.update({"key": meta_key, "instance_id": instance_id})
@@ -3447,6 +3445,7 @@ def instance_type_extra_specs_delete(context, instance_type_id, key):
@require_context
def instance_type_extra_specs_get_item(context, instance_type_id, key,
session=None):
+
if not session:
session = get_session()
@@ -3470,10 +3469,8 @@ def instance_type_extra_specs_update_or_create(context, instance_type_id,
spec_ref = None
for key, value in specs.iteritems():
try:
- spec_ref = instance_type_extra_specs_get_item(context,
- instance_type_id,
- key,
- session)
+ spec_ref = instance_type_extra_specs_get_item(
+ context, instance_type_id, key, session)
except exception.InstanceTypeExtraSpecsNotFound, e:
spec_ref = models.InstanceTypeExtraSpecs()
spec_ref.update({"key": key, "value": value,
diff --git a/nova/objectstore/s3server.py b/nova/objectstore/s3server.py
index 76025a1e3..1ab47b034 100644
--- a/nova/objectstore/s3server.py
+++ b/nova/objectstore/s3server.py
@@ -155,7 +155,10 @@ class BaseRequestHandler(object):
self.finish('<?xml version="1.0" encoding="UTF-8"?>\n' +
''.join(parts))
- def _render_parts(self, value, parts=[]):
+ def _render_parts(self, value, parts=None):
+ if not parts:
+ parts = []
+
if isinstance(value, basestring):
parts.append(utils.xhtml_escape(value))
elif isinstance(value, int) or isinstance(value, long):
diff --git a/nova/scheduler/least_cost.py b/nova/scheduler/least_cost.py
index 8c400d476..329107efe 100644
--- a/nova/scheduler/least_cost.py
+++ b/nova/scheduler/least_cost.py
@@ -96,7 +96,8 @@ class LeastCostScheduler(zone_aware_scheduler.ZoneAwareScheduler):
cost_fn_str=cost_fn_str)
try:
- weight = getattr(FLAGS, "%s_weight" % cost_fn.__name__)
+ flag_name = "%s_weight" % cost_fn.__name__
+ weight = getattr(FLAGS, flag_name)
except AttributeError:
raise exception.SchedulerWeightFlagNotFound(
flag_name=flag_name)
diff --git a/nova/scheduler/manager.py b/nova/scheduler/manager.py
index 749d66cad..c8b16b622 100644
--- a/nova/scheduler/manager.py
+++ b/nova/scheduler/manager.py
@@ -69,8 +69,10 @@ class SchedulerManager(manager.Manager):
return self.zone_manager.get_zone_capabilities(context)
def update_service_capabilities(self, context=None, service_name=None,
- host=None, capabilities={}):
+ host=None, capabilities=None):
"""Process a capability update from a service node."""
+ if not capability:
+ capability = {}
self.zone_manager.update_service_capabilities(service_name,
host, capabilities)
diff --git a/nova/scheduler/zone_aware_scheduler.py b/nova/scheduler/zone_aware_scheduler.py
index 047dafa6f..d1924c9f9 100644
--- a/nova/scheduler/zone_aware_scheduler.py
+++ b/nova/scheduler/zone_aware_scheduler.py
@@ -266,8 +266,8 @@ class ZoneAwareScheduler(driver.Scheduler):
"""
if topic != "compute":
- raise NotImplemented(_("Zone Aware Scheduler only understands "
- "Compute nodes (for now)"))
+ raise NotImplementedError(_("Zone Aware Scheduler only understands"
+ " Compute nodes (for now)"))
num_instances = request_spec.get('num_instances', 1)
instance_type = request_spec['instance_type']
diff --git a/nova/scheduler/zone_manager.py b/nova/scheduler/zone_manager.py
index 97bdf3d44..9d05ea42e 100644
--- a/nova/scheduler/zone_manager.py
+++ b/nova/scheduler/zone_manager.py
@@ -198,7 +198,7 @@ class ZoneManager(object):
def update_service_capabilities(self, service_name, host, capabilities):
"""Update the per-service capabilities based on this notification."""
logging.debug(_("Received %(service_name)s service update from "
- "%(host)s: %(capabilities)s") % locals())
+ "%(host)s.") % locals())
service_caps = self.service_states.get(host, {})
capabilities["timestamp"] = utils.utcnow() # Reported time
service_caps[service_name] = capabilities
diff --git a/nova/tests/api/openstack/contrib/test_keypairs.py b/nova/tests/api/openstack/contrib/test_keypairs.py
new file mode 100644
index 000000000..c9dc34d65
--- /dev/null
+++ b/nova/tests/api/openstack/contrib/test_keypairs.py
@@ -0,0 +1,99 @@
+# Copyright 2011 Eldar Nugaev
+# 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 json
+import webob
+
+from nova import context
+from nova import db
+from nova import test
+from nova.api.openstack.contrib.keypairs import KeypairController
+from nova.tests.api.openstack import fakes
+
+
+def fake_keypair(name):
+ return {'public_key': 'FAKE_KEY',
+ 'fingerprint': 'FAKE_FINGERPRINT',
+ 'name': name}
+
+def db_key_pair_get_all_by_user(self, user_id):
+ return [fake_keypair('FAKE')]
+
+
+def db_key_pair_create(self, keypair):
+ pass
+
+
+def db_key_pair_destroy(context, user_id, name):
+ if not (user_id and name):
+ raise Exception()
+
+
+class KeypairsTest(test.TestCase):
+
+ def setUp(self):
+ super(KeypairsTest, self).setUp()
+ self.controller = KeypairController()
+ fakes.stub_out_networking(self.stubs)
+ fakes.stub_out_rate_limiting(self.stubs)
+ self.stubs.Set(db, "key_pair_get_all_by_user",
+ db_key_pair_get_all_by_user)
+ self.stubs.Set(db, "key_pair_create",
+ db_key_pair_create)
+ self.stubs.Set(db, "key_pair_destroy",
+ db_key_pair_destroy)
+ self.context = context.get_admin_context()
+
+ def test_keypair_list(self):
+ req = webob.Request.blank('/v1.1/os-keypairs')
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ res_dict = json.loads(res.body)
+ response = {'keypairs': [{'keypair': fake_keypair('FAKE')}]}
+ self.assertEqual(res_dict, response)
+
+ def test_keypair_create(self):
+ body = {'keypair': {'name': 'create_test'}}
+ req = webob.Request.blank('/v1.1/os-keypairs')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers['Content-Type'] = 'application/json'
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ res_dict = json.loads(res.body)
+ self.assertTrue(len(res_dict['keypair']['fingerprint']) > 0)
+ self.assertTrue(len(res_dict['keypair']['private_key']) > 0)
+
+ def test_keypair_import(self):
+ body = {'keypair': {'name': 'create_test',
+ 'public_key': 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBYIznAx9D7118Q1VKGpXy2HDiKyUTM8XcUuhQpo0srqb9rboUp4a9NmCwpWpeElDLuva707GOUnfaBAvHBwsRXyxHJjRaI6YQj2oLJwqvaSaWUbyT1vtryRqy6J3TecN0WINY71f4uymiMZP0wby4bKBcYnac8KiCIlvkEl0ETjkOGUq8OyWRmn7ljj5SESEUdBP0JnuTFKddWTU/wD6wydeJaUhBTqOlHn0kX1GyqoNTE1UEhcM5ZRWgfUZfTjVyDF2kGj3vJLCJtJ8LoGcj7YaN4uPg1rBle+izwE/tLonRrds+cev8p6krSSrxWOwBbHkXa6OciiJDvkRzJXzf'}}
+ req = webob.Request.blank('/v1.1/os-keypairs')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers['Content-Type'] = 'application/json'
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ # FIXME(ja): sholud we check that public_key was sent to create?
+ res_dict = json.loads(res.body)
+ self.assertTrue(len(res_dict['keypair']['fingerprint']) > 0)
+ self.assertFalse('private_key' in res_dict['keypair'])
+
+ def test_keypair_delete(self):
+ req = webob.Request.blank('/v1.1/os-keypairs/FAKE')
+ req.method = 'DELETE'
+ req.headers['Content-Type'] = 'application/json'
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
+
diff --git a/nova/tests/api/openstack/test_extensions.py b/nova/tests/api/openstack/test_extensions.py
index a1ed72e4a..ea8fe68a7 100644
--- a/nova/tests/api/openstack/test_extensions.py
+++ b/nova/tests/api/openstack/test_extensions.py
@@ -97,7 +97,8 @@ class ExtensionControllerTest(test.TestCase):
names = [x['name'] for x in data['extensions']]
names.sort()
self.assertEqual(names, ["FlavorExtraSpecs", "Floating_ips",
- "Fox In Socks", "Hosts", "Multinic", "SecurityGroups", "Volumes"])
+ "Fox In Socks", "Hosts", "Keypairs", "Multinic", "SecurityGroups",
+ "Volumes"])
# Make sure that at least Fox in Sox is correct.
(fox_ext,) = [
@@ -144,7 +145,7 @@ class ExtensionControllerTest(test.TestCase):
# Make sure we have all the extensions.
exts = root.findall('{0}extension'.format(NS))
- self.assertEqual(len(exts), 7)
+ self.assertEqual(len(exts), 8)
# Make sure that at least Fox in Sox is correct.
(fox_ext,) = [x for x in exts if x.get('alias') == 'FOXNSOX']
diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py
index 6c3d531e3..1dc3c3a17 100644
--- a/nova/tests/api/openstack/test_limits.py
+++ b/nova/tests/api/openstack/test_limits.py
@@ -819,12 +819,15 @@ class FakeHttplibConnection(object):
self.app = app
self.host = host
- def request(self, method, path, body="", headers={}):
+ def request(self, method, path, body="", headers=None):
"""
Requests made via this connection actually get translated and routed
into our WSGI app, we then wait for the response and turn it back into
an `httplib.HTTPResponse`.
"""
+ if not headers:
+ headers = {}
+
req = webob.Request.blank(path)
req.method = method
req.headers = headers
diff --git a/nova/tests/scheduler/test_scheduler.py b/nova/tests/scheduler/test_scheduler.py
index 330dab5e5..7a26fd1bb 100644
--- a/nova/tests/scheduler/test_scheduler.py
+++ b/nova/tests/scheduler/test_scheduler.py
@@ -303,7 +303,7 @@ class SimpleDriverTestCase(test.TestCase):
db.compute_node_create(self.context, dic)
return db.service_get(self.context, s_ref['id'])
- def test_doesnt_report_disabled_hosts_as_up(self):
+ def test_doesnt_report_disabled_hosts_as_up_no_queue(self):
"""Ensures driver doesn't find hosts before they are enabled"""
# NOTE(vish): constructing service without create method
# because we are going to use it without queue
@@ -326,7 +326,7 @@ class SimpleDriverTestCase(test.TestCase):
compute1.kill()
compute2.kill()
- def test_reports_enabled_hosts_as_up(self):
+ def test_reports_enabled_hosts_as_up_no_queue(self):
"""Ensures driver can find the hosts that are up"""
# NOTE(vish): constructing service without create method
# because we are going to use it without queue
@@ -345,7 +345,7 @@ class SimpleDriverTestCase(test.TestCase):
compute1.kill()
compute2.kill()
- def test_least_busy_host_gets_instance(self):
+ def test_least_busy_host_gets_instance_no_queue(self):
"""Ensures the host with less cores gets the next one"""
compute1 = service.Service('host1',
'nova-compute',
@@ -368,7 +368,7 @@ class SimpleDriverTestCase(test.TestCase):
compute1.kill()
compute2.kill()
- def test_specific_host_gets_instance(self):
+ def test_specific_host_gets_instance_no_queue(self):
"""Ensures if you set availability_zone it launches on that zone"""
compute1 = service.Service('host1',
'nova-compute',
@@ -391,7 +391,7 @@ class SimpleDriverTestCase(test.TestCase):
compute1.kill()
compute2.kill()
- def test_wont_sechedule_if_specified_host_is_down(self):
+ def test_wont_sechedule_if_specified_host_is_down_no_queue(self):
compute1 = service.Service('host1',
'nova-compute',
'compute',
@@ -410,7 +410,7 @@ class SimpleDriverTestCase(test.TestCase):
db.instance_destroy(self.context, instance_id2)
compute1.kill()
- def test_will_schedule_on_disabled_host_if_specified(self):
+ def test_will_schedule_on_disabled_host_if_specified_no_queue(self):
compute1 = service.Service('host1',
'nova-compute',
'compute',
@@ -425,7 +425,7 @@ class SimpleDriverTestCase(test.TestCase):
db.instance_destroy(self.context, instance_id2)
compute1.kill()
- def test_too_many_cores(self):
+ def test_too_many_cores_no_queue(self):
"""Ensures we don't go over max cores"""
compute1 = service.Service('host1',
'nova-compute',
@@ -458,7 +458,7 @@ class SimpleDriverTestCase(test.TestCase):
compute1.kill()
compute2.kill()
- def test_least_busy_host_gets_volume(self):
+ def test_least_busy_host_gets_volume_no_queue(self):
"""Ensures the host with less gigabytes gets the next one"""
volume1 = service.Service('host1',
'nova-volume',
@@ -479,7 +479,7 @@ class SimpleDriverTestCase(test.TestCase):
volume1.delete_volume(self.context, volume_id1)
db.volume_destroy(self.context, volume_id2)
- def test_doesnt_report_disabled_hosts_as_up(self):
+ def test_doesnt_report_disabled_hosts_as_up2(self):
"""Ensures driver doesn't find hosts before they are enabled"""
compute1 = self.start_service('compute', host='host1')
compute2 = self.start_service('compute', host='host2')
@@ -992,7 +992,7 @@ class ZoneRedirectTest(test.TestCase):
decorator = FakeRerouteCompute("foo", id_to_return=FAKE_UUID_NOT_FOUND)
try:
result = decorator(go_boom)(None, None, 1)
- self.assertFail(_("Should have rerouted."))
+ self.fail(_("Should have rerouted."))
except api.RedirectResult, e:
self.assertEquals(e.results['magic'], 'found me')
@@ -1080,10 +1080,10 @@ class DynamicNovaClientTest(test.TestCase):
class FakeZonesProxy(object):
- def do_something(*args, **kwargs):
+ def do_something(self, *args, **kwargs):
return 42
- def raises_exception(*args, **kwargs):
+ def raises_exception(self, *args, **kwargs):
raise Exception('testing')
diff --git a/nova/tests/test_auth.py b/nova/tests/test_auth.py
index 2e24b7d6e..4561eb7f2 100644
--- a/nova/tests/test_auth.py
+++ b/nova/tests/test_auth.py
@@ -62,7 +62,12 @@ class project_generator(object):
class user_and_project_generator(object):
- def __init__(self, manager, user_state={}, project_state={}):
+ def __init__(self, manager, user_state=None, project_state=None):
+ if not user_state:
+ user_state = {}
+ if not project_state:
+ project_state = {}
+
self.manager = manager
if 'name' not in user_state:
user_state['name'] = 'test1'
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index 80f7ff489..73c9bd78d 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -76,9 +76,9 @@ class ComputeTestCase(test.TestCase):
def _create_instance(self, params=None):
"""Create a test instance"""
-
- if params is None:
+ if not params:
params = {}
+
inst = {}
inst['image_ref'] = 1
inst['reservation_id'] = 'r-fakeres'
@@ -91,8 +91,11 @@ class ComputeTestCase(test.TestCase):
inst.update(params)
return db.instance_create(self.context, inst)['id']
- def _create_instance_type(self, params={}):
+ def _create_instance_type(self, params=None):
"""Create a test instance"""
+ if not params:
+ params = {}
+
context = self.context.elevated()
inst = {}
inst['name'] = 'm1.small'
diff --git a/nova/tests/test_instance_types_extra_specs.py b/nova/tests/test_instance_types_extra_specs.py
index 393ed1e36..205601277 100644
--- a/nova/tests/test_instance_types_extra_specs.py
+++ b/nova/tests/test_instance_types_extra_specs.py
@@ -136,7 +136,7 @@ class InstanceTypeExtraSpecsTestCase(test.TestCase):
"m1.small")
self.assertEquals(instance_type['extra_specs'], {})
- def test_instance_type_get_with_extra_specs(self):
+ def test_instance_type_get_by_flavor_id_with_extra_specs(self):
instance_type = db.api.instance_type_get_by_flavor_id(
context.get_admin_context(),
105)
diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py
index c04851d59..17f1be967 100644
--- a/nova/tests/test_libvirt.py
+++ b/nova/tests/test_libvirt.py
@@ -1194,8 +1194,11 @@ class NWFilterTestCase(test.TestCase):
'project_id': 'fake',
'instance_type_id': 1})
- def _create_instance_type(self, params={}):
+ def _create_instance_type(self, params=None):
"""Create a test instance"""
+ if not params:
+ params = {}
+
context = self.context.elevated()
inst = {}
inst['name'] = 'm1.small'
diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py
index dfc1eeb0a..952277e3f 100644
--- a/nova/tests/test_xenapi.py
+++ b/nova/tests/test_xenapi.py
@@ -654,6 +654,24 @@ class XenAPIVMTestCase(test.TestCase):
# Ensure that it will not unrescue a non-rescued instance.
self.assertRaises(Exception, conn.unrescue, instance, None)
+ def test_revert_migration(self):
+ instance = self._create_instance()
+
+ class VMOpsMock():
+
+ def __init__(self):
+ self.revert_migration_called = False
+
+ def revert_migration(self, instance):
+ self.revert_migration_called = True
+
+ stubs.stubout_session(self.stubs, stubs.FakeSessionForMigrationTests)
+
+ conn = xenapi_conn.get_connection(False)
+ conn._vmops = VMOpsMock()
+ conn.revert_migration(instance)
+ self.assertTrue(conn._vmops.revert_migration_called)
+
def _create_instance(self, instance_id=1, spawn=True):
"""Creates and spawns a test instance."""
stubs.stubout_loopingcall_start(self.stubs)
diff --git a/nova/virt/fake.py b/nova/virt/fake.py
index 93c54a27d..880702af1 100644
--- a/nova/virt/fake.py
+++ b/nova/virt/fake.py
@@ -294,7 +294,7 @@ class FakeConnection(driver.ComputeDriver):
"""
pass
- def destroy(self, instance, network_info):
+ def destroy(self, instance, network_info, cleanup=True):
key = instance.name
if key in self.instances:
del self.instances[key]
diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py
index 43658a6c2..03a78db1f 100644
--- a/nova/virt/hyperv.py
+++ b/nova/virt/hyperv.py
@@ -374,7 +374,7 @@ class HyperVConnection(driver.ComputeDriver):
raise exception.InstanceNotFound(instance_id=instance.id)
self._set_vm_state(instance.name, 'Reboot')
- def destroy(self, instance, network_info):
+ def destroy(self, instance, network_info, cleanup=True):
"""Destroy the VM. Also destroy the associated VHD disk files"""
LOG.debug(_("Got request to destroy vm %s"), instance.name)
vm = self._lookup(instance.name)
diff --git a/nova/virt/vmwareapi/io_util.py b/nova/virt/vmwareapi/io_util.py
index 2ec773b7b..409242800 100644
--- a/nova/virt/vmwareapi/io_util.py
+++ b/nova/virt/vmwareapi/io_util.py
@@ -68,7 +68,10 @@ class GlanceWriteThread(object):
"""Ensures that image data is written to in the glance client and that
it is in correct ('active')state."""
- def __init__(self, input, glance_client, image_id, image_meta={}):
+ def __init__(self, input, glance_client, image_id, image_meta=None):
+ if not image_meta:
+ image_meta = {}
+
self.input = input
self.glance_client = glance_client
self.image_id = image_id
diff --git a/nova/virt/vmwareapi/vif.py b/nova/virt/vmwareapi/vif.py
index b3e43b209..fb6548b34 100644
--- a/nova/virt/vmwareapi/vif.py
+++ b/nova/virt/vmwareapi/vif.py
@@ -63,7 +63,7 @@ class VMWareVlanBridgeDriver(VIFDriver):
vswitch_associated = network_utils.get_vswitch_for_vlan_interface(
session, vlan_interface)
if vswitch_associated is None:
- raise exception.SwicthNotFoundForNetworkAdapter(
+ raise exception.SwitchNotFoundForNetworkAdapter(
adapter=vlan_interface)
# Check whether bridge already exists and retrieve the the ref of the
# network whose name_label is "bridge"
diff --git a/nova/virt/vmwareapi/vim_util.py b/nova/virt/vmwareapi/vim_util.py
index 11214231c..e03daddac 100644
--- a/nova/virt/vmwareapi/vim_util.py
+++ b/nova/virt/vmwareapi/vim_util.py
@@ -95,9 +95,12 @@ def build_recursive_traversal_spec(client_factory):
def build_property_spec(client_factory, type="VirtualMachine",
- properties_to_collect=["name"],
+ properties_to_collect=None,
all_properties=False):
"""Builds the Property Spec."""
+ if not properties_to_collect:
+ properties_to_collect = ["name"]
+
property_spec = client_factory.create('ns0:PropertySpec')
property_spec.all = all_properties
property_spec.pathSet = properties_to_collect
@@ -155,8 +158,11 @@ def get_dynamic_property(vim, mobj, type, property_name):
return property_value
-def get_objects(vim, type, properties_to_collect=["name"], all=False):
+def get_objects(vim, type, properties_to_collect=None, all=False):
"""Gets the list of objects of the type specified."""
+ if not properties_to_collect:
+ properties_to_collect = ["name"]
+
client_factory = vim.client.factory
object_spec = build_object_spec(client_factory,
vim.get_service_content().rootFolder,
diff --git a/nova/virt/vmwareapi/vmware_images.py b/nova/virt/vmwareapi/vmware_images.py
index 70adba74f..f5f75dae2 100644
--- a/nova/virt/vmwareapi/vmware_images.py
+++ b/nova/virt/vmwareapi/vmware_images.py
@@ -33,11 +33,15 @@ QUEUE_BUFFER_SIZE = 10
def start_transfer(read_file_handle, data_size, write_file_handle=None,
- glance_client=None, image_id=None, image_meta={}):
+ glance_client=None, image_id=None, image_meta=None):
"""Start the data transfer from the reader to the writer.
Reader writes to the pipe and the writer reads from the pipe. This means
that the total transfer time boils down to the slower of the read/write
and not the addition of the two times."""
+
+ if not image_meta:
+ image_meta = {}
+
# The pipe that acts as an intermediate store of data for reader to write
# to and writer to grab from.
thread_safe_pipe = io_util.ThreadSafePipe(QUEUE_BUFFER_SIZE, data_size)
diff --git a/nova/virt/vmwareapi_conn.py b/nova/virt/vmwareapi_conn.py
index aaa384374..243ee64f5 100644
--- a/nova/virt/vmwareapi_conn.py
+++ b/nova/virt/vmwareapi_conn.py
@@ -137,7 +137,7 @@ class VMWareESXConnection(driver.ComputeDriver):
"""Reboot VM instance."""
self._vmops.reboot(instance, network_info)
- def destroy(self, instance, network_info):
+ def destroy(self, instance, network_info, cleanup=True):
"""Destroy VM instance."""
self._vmops.destroy(instance, network_info)
diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py
index 6d2340ccd..d20746076 100644
--- a/nova/virt/xenapi/vm_utils.py
+++ b/nova/virt/xenapi/vm_utils.py
@@ -797,7 +797,7 @@ def get_vdi_for_vm_safely(session, vm_ref):
else:
num_vdis = len(vdi_refs)
if num_vdis != 1:
- raise exception.Exception(_("Unexpected number of VDIs"
+ raise exception.Error(_("Unexpected number of VDIs"
"(%(num_vdis)s) found"
" for VM %(vm_ref)s") % locals())
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index 91df80950..76b6c57fc 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -217,7 +217,7 @@ class XenAPIConnection(driver.ComputeDriver):
"""
self._vmops.inject_file(instance, b64_path, b64_contents)
- def destroy(self, instance, network_info):
+ def destroy(self, instance, network_info, cleanup=True):
"""Destroy VM instance"""
self._vmops.destroy(instance, network_info)
diff --git a/setup.py b/setup.py
index 8121e250b..9b11fb95a 100644
--- a/setup.py
+++ b/setup.py
@@ -123,7 +123,6 @@ setup(name='nova',
'bin/nova-console',
'bin/nova-dhcpbridge',
'bin/nova-direct-api',
- 'bin/nova-import-canonical-imagestore',
'bin/nova-logspool',
'bin/nova-manage',
'bin/nova-network',
@@ -133,4 +132,5 @@ setup(name='nova',
'bin/stack',
'bin/nova-volume',
'bin/nova-vncproxy',
- 'tools/nova-debug'])
+ 'tools/nova-debug'],
+ py_modules=[])