summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/api_samples/os-volumes/snapshot-create-resp.json23
-rw-r--r--doc/api_samples/os-volumes/snapshot-create-resp.xml2
-rw-r--r--nova/api/openstack/compute/contrib/disk_config.py4
-rw-r--r--nova/api/openstack/compute/contrib/evacuate.py3
-rw-r--r--nova/api/openstack/compute/contrib/flavormanage.py16
-rw-r--r--nova/api/openstack/compute/contrib/volumes.py3
-rw-r--r--nova/api/openstack/compute/flavors.py23
-rw-r--r--nova/api/openstack/compute/servers.py10
-rw-r--r--nova/cmd/all.py1
-rw-r--r--nova/cmd/api.py1
-rw-r--r--nova/cmd/api_ec2.py1
-rw-r--r--nova/cmd/api_metadata.py1
-rw-r--r--nova/cmd/api_os_compute.py1
-rw-r--r--nova/cmd/baremetal_manage.py1
-rw-r--r--nova/cmd/cells.py1
-rw-r--r--nova/cmd/cert.py1
-rw-r--r--nova/cmd/clear_rabbit_queues.py1
-rw-r--r--nova/cmd/compute.py1
-rw-r--r--nova/cmd/conductor.py1
-rw-r--r--nova/cmd/console.py1
-rw-r--r--nova/cmd/consoleauth.py1
-rw-r--r--nova/cmd/dhcpbridge.py1
-rw-r--r--nova/cmd/manage.py6
-rw-r--r--nova/cmd/network.py1
-rw-r--r--nova/cmd/novncproxy.py1
-rw-r--r--nova/cmd/objectstore.py2
-rw-r--r--nova/cmd/rpc_zmq_receiver.py1
-rw-r--r--nova/cmd/scheduler.py1
-rw-r--r--nova/cmd/spicehtml5proxy.py1
-rw-r--r--nova/cmd/xvpvncproxy.py1
-rw-r--r--nova/compute/api.py3
-rw-r--r--nova/compute/flavors.py40
-rw-r--r--nova/db/sqlalchemy/api.py21
-rw-r--r--nova/db/sqlalchemy/models.py1
-rw-r--r--nova/network/api.py2
-rw-r--r--nova/network/manager.py10
-rw-r--r--nova/openstack/common/strutils.py150
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_snapshots.py4
-rw-r--r--nova/tests/api/openstack/compute/test_flavors.py34
-rw-r--r--nova/tests/api/openstack/compute/test_servers.py4
-rw-r--r--nova/tests/api/openstack/fakes.py4
-rw-r--r--nova/tests/compute/test_compute.py22
-rw-r--r--nova/tests/integrated/api_samples/os-volumes/snapshot-create-resp.json.tpl23
-rw-r--r--nova/tests/integrated/api_samples/os-volumes/snapshot-create-resp.xml.tpl2
-rw-r--r--nova/tests/test_db_api.py197
-rw-r--r--nova/tests/test_instance_types.py296
-rw-r--r--nova/tests/test_utils.py22
-rw-r--r--nova/utils.py13
-rw-r--r--nova/virt/xenapi/vm_utils.py6
-rw-r--r--openstack-common.conf1
50 files changed, 562 insertions, 405 deletions
diff --git a/doc/api_samples/os-volumes/snapshot-create-resp.json b/doc/api_samples/os-volumes/snapshot-create-resp.json
index 1a14bea01..a8dd57d84 100644
--- a/doc/api_samples/os-volumes/snapshot-create-resp.json
+++ b/doc/api_samples/os-volumes/snapshot-create-resp.json
@@ -6,27 +6,6 @@
"id": 100,
"size": 100,
"status": "available",
- "volumeId": {
- "attach_status": "attached",
- "availability_zone": "fakeaz",
- "created_at": "1999-01-01T01:01:01.000000",
- "display_description": "displaydesc",
- "display_name": "displayname",
- "host": "fakehost",
- "id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c",
- "instance_uuid": "fakeuuid",
- "mountpoint": "/",
- "name": "vol name",
- "project_id": "fakeproject",
- "size": 1,
- "snapshot_id": null,
- "status": "fakestatus",
- "user_id": "fakeuser",
- "volume_metadata": [],
- "volume_type": {
- "name": "vol_type_name"
- },
- "volume_type_id": "fakevoltype"
- }
+ "volumeId": "521752a6-acf6-4b2d-bc7a-119f9148cd8c"
}
} \ No newline at end of file
diff --git a/doc/api_samples/os-volumes/snapshot-create-resp.xml b/doc/api_samples/os-volumes/snapshot-create-resp.xml
index ad815f723..654bf3d34 100644
--- a/doc/api_samples/os-volumes/snapshot-create-resp.xml
+++ b/doc/api_samples/os-volumes/snapshot-create-resp.xml
@@ -1,2 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
-<snapshot status="available" displayDescription="Daily backup" displayName="snap-001" volumeId="{'instance_uuid': 'fakeuuid', 'status': 'fakestatus', 'user_id': 'fakeuser', 'name': 'vol name', 'display_name': 'displayname', 'availability_zone': 'fakeaz', 'created_at': datetime.datetime(1999, 1, 1, 1, 1, 1), 'attach_status': 'attached', 'display_description': 'displaydesc', 'host': 'fakehost', 'volume_type_id': 'fakevoltype', 'volume_metadata': [], 'volume_type': {'name': 'vol_type_name'}, 'snapshot_id': None, 'mountpoint': '/', 'project_id': 'fakeproject', 'id': u'521752a6-acf6-4b2d-bc7a-119f9148cd8c', 'size': 1}" id="100" createdAt="2013-02-25 16:27:36.840121" size="100"/> \ No newline at end of file
+<snapshot status="available" displayDescription="Daily backup" displayName="snap-001" volumeId="521752a6-acf6-4b2d-bc7a-119f9148cd8c" id="100" createdAt="2013-02-25 16:27:36.840121" size="100"/> \ No newline at end of file
diff --git a/nova/api/openstack/compute/contrib/disk_config.py b/nova/api/openstack/compute/contrib/disk_config.py
index 2c4d24332..f2b906144 100644
--- a/nova/api/openstack/compute/contrib/disk_config.py
+++ b/nova/api/openstack/compute/contrib/disk_config.py
@@ -21,7 +21,7 @@ from webob import exc
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
-from nova import utils
+from nova.openstack.common import strutils
ALIAS = 'OS-DCF'
XMLNS_DCF = "http://docs.openstack.org/compute/ext/disk_config/api/v1.1"
@@ -65,7 +65,7 @@ class ImageDiskConfigController(wsgi.Controller):
metadata = image['metadata']
if INTERNAL_DISK_CONFIG in metadata:
raw_value = metadata[INTERNAL_DISK_CONFIG]
- value = utils.bool_from_str(raw_value)
+ value = strutils.bool_from_string(raw_value)
image[API_DISK_CONFIG] = disk_config_to_api(value)
@wsgi.extends
diff --git a/nova/api/openstack/compute/contrib/evacuate.py b/nova/api/openstack/compute/contrib/evacuate.py
index 587e231d1..7eee99ed1 100644
--- a/nova/api/openstack/compute/contrib/evacuate.py
+++ b/nova/api/openstack/compute/contrib/evacuate.py
@@ -21,6 +21,7 @@ from nova.api.openstack import wsgi
from nova import compute
from nova import exception
from nova.openstack.common import log as logging
+from nova.openstack.common import strutils
from nova import utils
LOG = logging.getLogger(__name__)
@@ -47,7 +48,7 @@ class Controller(wsgi.Controller):
evacuate_body = body["evacuate"]
host = evacuate_body["host"]
- on_shared_storage = utils.bool_from_str(
+ on_shared_storage = strutils.bool_from_string(
evacuate_body["onSharedStorage"])
password = None
diff --git a/nova/api/openstack/compute/contrib/flavormanage.py b/nova/api/openstack/compute/contrib/flavormanage.py
index c36b40125..086c541dc 100644
--- a/nova/api/openstack/compute/contrib/flavormanage.py
+++ b/nova/api/openstack/compute/contrib/flavormanage.py
@@ -58,18 +58,20 @@ class FlavorManageController(wsgi.Controller):
vals = body['flavor']
name = vals['name']
flavorid = vals.get('id')
- memory_mb = vals.get('ram')
+ memory = vals.get('ram')
vcpus = vals.get('vcpus')
root_gb = vals.get('disk')
- ephemeral_gb = vals.get('OS-FLV-EXT-DATA:ephemeral')
- swap = vals.get('swap')
- rxtx_factor = vals.get('rxtx_factor')
+ ephemeral_gb = vals.get('OS-FLV-EXT-DATA:ephemeral', 0)
+ swap = vals.get('swap', 0)
+ rxtx_factor = vals.get('rxtx_factor', 1.0)
is_public = vals.get('os-flavor-access:is_public', True)
try:
- flavor = flavors.create(name, memory_mb, vcpus,
- root_gb, ephemeral_gb, flavorid,
- swap, rxtx_factor, is_public)
+ flavor = flavors.create(name, memory, vcpus, root_gb,
+ ephemeral_gb=ephemeral_gb,
+ flavorid=flavorid, swap=swap,
+ rxtx_factor=rxtx_factor,
+ is_public=is_public)
req.cache_db_flavor(flavor)
except (exception.InstanceTypeExists,
exception.InstanceTypeIdExists) as err:
diff --git a/nova/api/openstack/compute/contrib/volumes.py b/nova/api/openstack/compute/contrib/volumes.py
index 5b2097365..ea1fb1f21 100644
--- a/nova/api/openstack/compute/contrib/volumes.py
+++ b/nova/api/openstack/compute/contrib/volumes.py
@@ -25,6 +25,7 @@ from nova.api.openstack import xmlutil
from nova import compute
from nova import exception
from nova.openstack.common import log as logging
+from nova.openstack.common import strutils
from nova.openstack.common import uuidutils
from nova import utils
from nova import volume
@@ -624,7 +625,7 @@ class SnapshotController(wsgi.Controller):
msg = _("Invalid value '%s' for force.") % force
raise exception.InvalidParameterValue(err=msg)
- if utils.bool_from_str(force):
+ if strutils.bool_from_string(force):
new_snapshot = self.volume_api.create_snapshot_force(context,
vol,
snapshot.get('display_name'),
diff --git a/nova/api/openstack/compute/flavors.py b/nova/api/openstack/compute/flavors.py
index 42b627cf4..744fe5e93 100644
--- a/nova/api/openstack/compute/flavors.py
+++ b/nova/api/openstack/compute/flavors.py
@@ -23,6 +23,7 @@ from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.compute import flavors
from nova import exception
+from nova.openstack.common import strutils
def make_flavor(elem, detailed=False):
@@ -91,25 +92,20 @@ class Controller(wsgi.Controller):
return self._view_builder.show(req, flavor)
- def _get_is_public(self, req):
+ def _parse_is_public(self, is_public):
"""Parse is_public into something usable."""
- is_public = req.params.get('is_public', None)
if is_public is None:
# preserve default value of showing only public flavors
return True
- elif is_public is True or \
- is_public.lower() in ['t', 'true', 'yes', '1']:
- return True
- elif is_public is False or \
- is_public.lower() in ['f', 'false', 'no', '0']:
- return False
- elif is_public.lower() == 'none':
- # value to match all flavors, ignore is_public
+ elif is_public == 'none':
return None
else:
- msg = _('Invalid is_public filter [%s]') % req.params['is_public']
- raise webob.exc.HTTPBadRequest(explanation=msg)
+ try:
+ return strutils.bool_from_string(is_public, strict=True)
+ except ValueError:
+ msg = _('Invalid is_public filter [%s]') % is_public
+ raise webob.exc.HTTPBadRequest(explanation=msg)
def _get_flavors(self, req):
"""Helper function that returns a list of flavor dicts."""
@@ -118,7 +114,8 @@ class Controller(wsgi.Controller):
context = req.environ['nova.context']
if context.is_admin:
# Only admin has query access to all flavor types
- filters['is_public'] = self._get_is_public(req)
+ filters['is_public'] = self._parse_is_public(
+ req.params.get('is_public', None))
else:
filters['is_public'] = True
filters['disabled'] = False
diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py
index 30f8e6fe8..cb3f7ad49 100644
--- a/nova/api/openstack/compute/servers.py
+++ b/nova/api/openstack/compute/servers.py
@@ -33,6 +33,7 @@ from nova import exception
from nova.openstack.common import importutils
from nova.openstack.common import log as logging
from nova.openstack.common.rpc import common as rpc_common
+from nova.openstack.common import strutils
from nova.openstack.common import timeutils
from nova.openstack.common import uuidutils
from nova import utils
@@ -185,7 +186,8 @@ class CommonDeserializer(wsgi.MetadataXMLDeserializer):
res_id = server_node.getAttribute('return_reservation_id')
if res_id:
- server['return_reservation_id'] = utils.bool_from_str(res_id)
+ server['return_reservation_id'] = \
+ strutils.bool_from_string(res_id)
scheduler_hints = self._extract_scheduler_hints(server_node)
if scheduler_hints:
@@ -253,7 +255,7 @@ class CommonDeserializer(wsgi.MetadataXMLDeserializer):
for attr in attributes:
value = child.getAttribute(attr)
if value:
- mapping[attr] = utils.bool_from_str(value)
+ mapping[attr] = strutils.bool_from_string(value)
block_device_mapping.append(mapping)
return block_device_mapping
else:
@@ -826,7 +828,7 @@ class Controller(wsgi.Controller):
for bdm in block_device_mapping:
self._validate_device_name(bdm["device_name"])
if 'delete_on_termination' in bdm:
- bdm['delete_on_termination'] = utils.bool_from_str(
+ bdm['delete_on_termination'] = strutils.bool_from_string(
bdm['delete_on_termination'])
ret_resv_id = False
@@ -991,7 +993,7 @@ class Controller(wsgi.Controller):
update_dict['access_ip_v6'] = access_ipv6.strip()
if 'auto_disk_config' in body['server']:
- auto_disk_config = utils.bool_from_str(
+ auto_disk_config = strutils.bool_from_string(
body['server']['auto_disk_config'])
update_dict['auto_disk_config'] = auto_disk_config
diff --git a/nova/cmd/all.py b/nova/cmd/all.py
index a6426ed33..f510069b6 100644
--- a/nova/cmd/all.py
+++ b/nova/cmd/all.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack Foundation
diff --git a/nova/cmd/api.py b/nova/cmd/api.py
index 811171afc..a7f6313b0 100644
--- a/nova/cmd/api.py
+++ b/nova/cmd/api.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
diff --git a/nova/cmd/api_ec2.py b/nova/cmd/api_ec2.py
index 2d78c58e5..2b3b942c8 100644
--- a/nova/cmd/api_ec2.py
+++ b/nova/cmd/api_ec2.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
diff --git a/nova/cmd/api_metadata.py b/nova/cmd/api_metadata.py
index b2acee33c..ab235df57 100644
--- a/nova/cmd/api_metadata.py
+++ b/nova/cmd/api_metadata.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
diff --git a/nova/cmd/api_os_compute.py b/nova/cmd/api_os_compute.py
index c4cb7982e..196abfef5 100644
--- a/nova/cmd/api_os_compute.py
+++ b/nova/cmd/api_os_compute.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
diff --git a/nova/cmd/baremetal_manage.py b/nova/cmd/baremetal_manage.py
index 4b659db31..e1224664a 100644
--- a/nova/cmd/baremetal_manage.py
+++ b/nova/cmd/baremetal_manage.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
diff --git a/nova/cmd/cells.py b/nova/cmd/cells.py
index 9e6fae402..35fa9b64f 100644
--- a/nova/cmd/cells.py
+++ b/nova/cmd/cells.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright (c) 2012 Rackspace Hosting
diff --git a/nova/cmd/cert.py b/nova/cmd/cert.py
index 668d8b0a4..1338b8dc8 100644
--- a/nova/cmd/cert.py
+++ b/nova/cmd/cert.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 OpenStack Foundation
diff --git a/nova/cmd/clear_rabbit_queues.py b/nova/cmd/clear_rabbit_queues.py
index 6748949ae..c15c2b058 100644
--- a/nova/cmd/clear_rabbit_queues.py
+++ b/nova/cmd/clear_rabbit_queues.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2011 OpenStack Foundation
diff --git a/nova/cmd/compute.py b/nova/cmd/compute.py
index 644462dde..0aae286a4 100644
--- a/nova/cmd/compute.py
+++ b/nova/cmd/compute.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
diff --git a/nova/cmd/conductor.py b/nova/cmd/conductor.py
index ba1ef2032..b9723f2d2 100644
--- a/nova/cmd/conductor.py
+++ b/nova/cmd/conductor.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 IBM Corp.
diff --git a/nova/cmd/console.py b/nova/cmd/console.py
index 2aa099f0c..4fdc090f6 100644
--- a/nova/cmd/console.py
+++ b/nova/cmd/console.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2010 OpenStack Foundation
diff --git a/nova/cmd/consoleauth.py b/nova/cmd/consoleauth.py
index ea28a2faf..130f7ad65 100644
--- a/nova/cmd/consoleauth.py
+++ b/nova/cmd/consoleauth.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2012 OpenStack Foundation
diff --git a/nova/cmd/dhcpbridge.py b/nova/cmd/dhcpbridge.py
index 10ccfbd1d..faf49805d 100644
--- a/nova/cmd/dhcpbridge.py
+++ b/nova/cmd/dhcpbridge.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
diff --git a/nova/cmd/manage.py b/nova/cmd/manage.py
index 604528160..599b9a299 100644
--- a/nova/cmd/manage.py
+++ b/nova/cmd/manage.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
@@ -887,8 +886,9 @@ class InstanceTypeCommands(object):
"""Creates instance types / flavors."""
try:
flavors.create(name, memory, vcpus, root_gb,
- ephemeral_gb, flavorid, swap, rxtx_factor,
- is_public)
+ ephemeral_gb=ephemeral_gb, flavorid=flavorid,
+ swap=swap, rxtx_factor=rxtx_factor,
+ is_public=is_public)
except exception.InvalidInput as e:
print _("Must supply valid parameters to create instance_type")
print e
diff --git a/nova/cmd/network.py b/nova/cmd/network.py
index 72eac2a19..1af0c0d7d 100644
--- a/nova/cmd/network.py
+++ b/nova/cmd/network.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
diff --git a/nova/cmd/novncproxy.py b/nova/cmd/novncproxy.py
index cf70b83c5..449aea76e 100644
--- a/nova/cmd/novncproxy.py
+++ b/nova/cmd/novncproxy.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2012 OpenStack Foundation
diff --git a/nova/cmd/objectstore.py b/nova/cmd/objectstore.py
index eb8257f9c..12e08beb8 100644
--- a/nova/cmd/objectstore.py
+++ b/nova/cmd/objectstore.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
diff --git a/nova/cmd/rpc_zmq_receiver.py b/nova/cmd/rpc_zmq_receiver.py
index a587af689..f4f5214e3 100644
--- a/nova/cmd/rpc_zmq_receiver.py
+++ b/nova/cmd/rpc_zmq_receiver.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack Foundation
diff --git a/nova/cmd/scheduler.py b/nova/cmd/scheduler.py
index 40486f5db..b8e6b99aa 100644
--- a/nova/cmd/scheduler.py
+++ b/nova/cmd/scheduler.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
diff --git a/nova/cmd/spicehtml5proxy.py b/nova/cmd/spicehtml5proxy.py
index 190e7e77a..8e005bcad 100644
--- a/nova/cmd/spicehtml5proxy.py
+++ b/nova/cmd/spicehtml5proxy.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2012 OpenStack Foundation
diff --git a/nova/cmd/xvpvncproxy.py b/nova/cmd/xvpvncproxy.py
index 0f62e2083..7d0c87627 100644
--- a/nova/cmd/xvpvncproxy.py
+++ b/nova/cmd/xvpvncproxy.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2010 OpenStack Foundation
diff --git a/nova/compute/api.py b/nova/compute/api.py
index d95e65f38..aa0ae7d96 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -53,6 +53,7 @@ from nova import notifications
from nova.openstack.common import excutils
from nova.openstack.common import jsonutils
from nova.openstack.common import log as logging
+from nova.openstack.common import strutils
from nova.openstack.common import timeutils
from nova.openstack.common import uuidutils
import nova.policy
@@ -439,7 +440,7 @@ class API(base.Base):
if value is not None:
if prop_type == 'bool':
- value = utils.bool_from_str(value)
+ value = strutils.bool_from_string(value)
return value
diff --git a/nova/compute/flavors.py b/nova/compute/flavors.py
index c4ce550eb..2958769e1 100644
--- a/nova/compute/flavors.py
+++ b/nova/compute/flavors.py
@@ -30,6 +30,7 @@ from nova import db
from nova import exception
from nova.openstack.common.db import exception as db_exc
from nova.openstack.common import log as logging
+from nova.openstack.common import strutils
from nova import utils
instance_type_opts = [
@@ -65,18 +66,11 @@ system_metadata_instance_type_props = {
}
-def create(name, memory, vcpus, root_gb, ephemeral_gb=None, flavorid=None,
- swap=None, rxtx_factor=None, is_public=True):
+def create(name, memory, vcpus, root_gb, ephemeral_gb=0, flavorid=None,
+ swap=0, rxtx_factor=1.0, is_public=True):
"""Creates instance types."""
-
- if flavorid is None or flavorid == '':
+ if not flavorid:
flavorid = uuid.uuid4()
- if swap is None:
- swap = 0
- if rxtx_factor is None:
- rxtx_factor = 1.0
- if ephemeral_gb is None:
- ephemeral_gb = 0
kwargs = {
'memory_mb': memory,
@@ -96,13 +90,23 @@ def create(name, memory, vcpus, root_gb, ephemeral_gb=None, flavorid=None,
msg = _("names can only contain [a-zA-Z0-9_.- ]")
raise exception.InvalidInput(reason=msg)
- # ensure some attributes are integers and greater than or equal to 0
- for option in ['memory_mb', 'vcpus', 'root_gb', 'ephemeral_gb', 'swap']:
+ # Some attributes are positive ( > 0) integers
+ for option in ['memory_mb', 'vcpus']:
+ try:
+ kwargs[option] = int(kwargs[option])
+ assert kwargs[option] > 0
+ except (ValueError, AssertionError):
+ msg = _("'%s' argument must be greater than 0") % option
+ raise exception.InvalidInput(reason=msg)
+
+ # Some attributes are non-negative ( >= 0) integers
+ for option in ['root_gb', 'ephemeral_gb', 'swap']:
try:
kwargs[option] = int(kwargs[option])
assert kwargs[option] >= 0
except (ValueError, AssertionError):
- msg = _("'%s' argument must be a positive integer") % option
+ msg = _("'%s' argument must be greater than or equal"
+ " to 0") % option
raise exception.InvalidInput(reason=msg)
# rxtx_factor should be a positive float
@@ -113,14 +117,6 @@ def create(name, memory, vcpus, root_gb, ephemeral_gb=None, flavorid=None,
msg = _("'rxtx_factor' argument must be a positive float")
raise exception.InvalidInput(reason=msg)
- # some value are required to be nonzero, not just positive
- for option in ['memory_mb', 'vcpus']:
- try:
- assert kwargs[option] > 0
- except AssertionError:
- msg = _("'%s' argument must be greater than 0") % option
- raise exception.InvalidInput(reason=msg)
-
kwargs['name'] = name
# NOTE(vish): Internally, flavorid is stored as a string but it comes
# in through json as an integer, so we convert it here.
@@ -130,7 +126,7 @@ def create(name, memory, vcpus, root_gb, ephemeral_gb=None, flavorid=None,
if not utils.is_valid_boolstr(is_public):
msg = _("is_public must be a boolean")
raise exception.InvalidInput(reason=msg)
- kwargs['is_public'] = utils.bool_from_str(is_public)
+ kwargs['is_public'] = strutils.bool_from_string(is_public)
try:
return db.instance_type_create(context.get_admin_context(), kwargs)
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 730ca641c..1fc273bec 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -1914,14 +1914,23 @@ def instance_get_floating_address(context, instance_id):
@require_context
def instance_floating_address_get_all(context, instance_uuid):
- fixed_ips = fixed_ip_get_by_instance(context, instance_uuid)
+ if not uuidutils.is_uuid_like(instance_uuid):
+ raise exception.InvalidUUID(uuid=instance_uuid)
+
+ fixed_ip_ids = model_query(context, models.FixedIp.id,
+ base_model=models.FixedIp).\
+ filter_by(instance_uuid=instance_uuid).\
+ all()
+ if not fixed_ip_ids:
+ raise exception.FixedIpNotFoundForInstance(instance_uuid=instance_uuid)
- floating_ips = []
- for fixed_ip in fixed_ips:
- _floating_ips = floating_ip_get_by_fixed_ip_id(context, fixed_ip['id'])
- floating_ips += _floating_ips
+ fixed_ip_ids = [fixed_ip_id.id for fixed_ip_id in fixed_ip_ids]
- return floating_ips
+ floating_ips = model_query(context, models.FloatingIp.address,
+ base_model=models.FloatingIp).\
+ filter(models.FloatingIp.fixed_ip_id.in_(fixed_ip_ids)).\
+ all()
+ return [floating_ip.address for floating_ip in floating_ips]
@require_admin_context
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index c4a22f4c5..f10bc8c32 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -552,6 +552,7 @@ class ProviderFirewallRule(BASE, NovaBase):
class KeyPair(BASE, NovaBase):
"""Represents a public key pair for ssh."""
__tablename__ = 'key_pairs'
+ __table_args__ = (schema.UniqueConstraint("name", "user_id"), )
id = Column(Integer, primary_key=True)
name = Column(String(255))
diff --git a/nova/network/api.py b/nova/network/api.py
index 3091a8fa1..26bf03446 100644
--- a/nova/network/api.py
+++ b/nova/network/api.py
@@ -484,7 +484,7 @@ class API(base.Base):
def _get_floating_ip_addresses(self, context, instance):
floating_ips = self.db.instance_floating_address_get_all(context,
instance['uuid'])
- return [floating_ip['address'] for floating_ip in floating_ips]
+ return floating_ips
@wrap_check_policy
def migrate_instance_start(self, context, instance, migration):
diff --git a/nova/network/manager.py b/nova/network/manager.py
index e34233ea9..5d58edb97 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -69,6 +69,7 @@ from nova.openstack.common import jsonutils
from nova.openstack.common import log as logging
from nova.openstack.common import periodic_task
from nova.openstack.common.rpc import common as rpc_common
+from nova.openstack.common import strutils
from nova.openstack.common import timeutils
from nova.openstack.common import uuidutils
from nova import quota
@@ -1029,10 +1030,11 @@ class NetworkManager(manager.Manager):
else:
kwargs["network_size"] = CONF.network_size
- kwargs["multi_host"] = (CONF.multi_host
- if kwargs["multi_host"] is None
- else
- utils.bool_from_str(kwargs["multi_host"]))
+ kwargs["multi_host"] = (
+ CONF.multi_host
+ if kwargs["multi_host"] is None
+ else strutils.bool_from_string(kwargs["multi_host"]))
+
kwargs["vlan_start"] = kwargs.get("vlan_start") or CONF.vlan_start
kwargs["vpn_start"] = kwargs.get("vpn_start") or CONF.vpn_start
kwargs["dns1"] = kwargs["dns1"] or CONF.flat_network_dns
diff --git a/nova/openstack/common/strutils.py b/nova/openstack/common/strutils.py
new file mode 100644
index 000000000..cdf70cb20
--- /dev/null
+++ b/nova/openstack/common/strutils.py
@@ -0,0 +1,150 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 OpenStack Foundation.
+# 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.
+
+"""
+System-level utilities and helper functions.
+"""
+
+import sys
+
+from nova.openstack.common.gettextutils import _
+
+
+TRUE_STRINGS = ('1', 't', 'true', 'on', 'y', 'yes')
+FALSE_STRINGS = ('0', 'f', 'false', 'off', 'n', 'no')
+
+
+def int_from_bool_as_string(subject):
+ """
+ Interpret a string as a boolean and return either 1 or 0.
+
+ Any string value in:
+
+ ('True', 'true', 'On', 'on', '1')
+
+ is interpreted as a boolean True.
+
+ Useful for JSON-decoded stuff and config file parsing
+ """
+ return bool_from_string(subject) and 1 or 0
+
+
+def bool_from_string(subject, strict=False):
+ """
+ Interpret a string as a boolean.
+
+ A case-insensitive match is performed such that strings matching 't',
+ 'true', 'on', 'y', 'yes', or '1' are considered True and, when
+ `strict=False`, anything else is considered False.
+
+ Useful for JSON-decoded stuff and config file parsing.
+
+ If `strict=True`, unrecognized values, including None, will raise a
+ ValueError which is useful when parsing values passed in from an API call.
+ Strings yielding False are 'f', 'false', 'off', 'n', 'no', or '0'.
+ """
+ if not isinstance(subject, basestring):
+ subject = str(subject)
+
+ lowered = subject.strip().lower()
+
+ if lowered in TRUE_STRINGS:
+ return True
+ elif lowered in FALSE_STRINGS:
+ return False
+ elif strict:
+ acceptable = ', '.join(
+ "'%s'" % s for s in sorted(TRUE_STRINGS + FALSE_STRINGS))
+ msg = _("Unrecognized value '%(val)s', acceptable values are:"
+ " %(acceptable)s") % {'val': subject,
+ 'acceptable': acceptable}
+ raise ValueError(msg)
+ else:
+ return False
+
+
+def safe_decode(text, incoming=None, errors='strict'):
+ """
+ Decodes incoming str using `incoming` if they're
+ not already unicode.
+
+ :param incoming: Text's current encoding
+ :param errors: Errors handling policy. See here for valid
+ values http://docs.python.org/2/library/codecs.html
+ :returns: text or a unicode `incoming` encoded
+ representation of it.
+ :raises TypeError: If text is not an isntance of basestring
+ """
+ if not isinstance(text, basestring):
+ raise TypeError("%s can't be decoded" % type(text))
+
+ if isinstance(text, unicode):
+ return text
+
+ if not incoming:
+ incoming = (sys.stdin.encoding or
+ sys.getdefaultencoding())
+
+ try:
+ return text.decode(incoming, errors)
+ except UnicodeDecodeError:
+ # Note(flaper87) If we get here, it means that
+ # sys.stdin.encoding / sys.getdefaultencoding
+ # didn't return a suitable encoding to decode
+ # text. This happens mostly when global LANG
+ # var is not set correctly and there's no
+ # default encoding. In this case, most likely
+ # python will use ASCII or ANSI encoders as
+ # default encodings but they won't be capable
+ # of decoding non-ASCII characters.
+ #
+ # Also, UTF-8 is being used since it's an ASCII
+ # extension.
+ return text.decode('utf-8', errors)
+
+
+def safe_encode(text, incoming=None,
+ encoding='utf-8', errors='strict'):
+ """
+ Encodes incoming str/unicode using `encoding`. If
+ incoming is not specified, text is expected to
+ be encoded with current python's default encoding.
+ (`sys.getdefaultencoding`)
+
+ :param incoming: Text's current encoding
+ :param encoding: Expected encoding for text (Default UTF-8)
+ :param errors: Errors handling policy. See here for valid
+ values http://docs.python.org/2/library/codecs.html
+ :returns: text or a bytestring `encoding` encoded
+ representation of it.
+ :raises TypeError: If text is not an isntance of basestring
+ """
+ if not isinstance(text, basestring):
+ raise TypeError("%s can't be encoded" % type(text))
+
+ if not incoming:
+ incoming = (sys.stdin.encoding or
+ sys.getdefaultencoding())
+
+ if isinstance(text, unicode):
+ return text.encode(encoding, errors)
+ elif text and encoding != incoming:
+ # Decode text before encoding it with `encoding`
+ text = safe_decode(text, incoming, errors)
+ return text.encode(encoding, errors)
+
+ return text
diff --git a/nova/tests/api/openstack/compute/contrib/test_snapshots.py b/nova/tests/api/openstack/compute/contrib/test_snapshots.py
index a890abe6f..8e042adf8 100644
--- a/nova/tests/api/openstack/compute/contrib/test_snapshots.py
+++ b/nova/tests/api/openstack/compute/contrib/test_snapshots.py
@@ -67,6 +67,8 @@ class SnapshotApiTest(test.TestCase):
snapshot['display_name'])
self.assertEqual(resp_dict['snapshot']['displayDescription'],
snapshot['display_description'])
+ self.assertEqual(resp_dict['snapshot']['volumeId'],
+ snapshot['volume_id'])
def test_snapshot_create_force(self):
snapshot = {"volume_id": 12,
@@ -88,6 +90,8 @@ class SnapshotApiTest(test.TestCase):
snapshot['display_name'])
self.assertEqual(resp_dict['snapshot']['displayDescription'],
snapshot['display_description'])
+ self.assertEqual(resp_dict['snapshot']['volumeId'],
+ snapshot['volume_id'])
# Test invalid force paramter
snapshot = {"volume_id": 12,
diff --git a/nova/tests/api/openstack/compute/test_flavors.py b/nova/tests/api/openstack/compute/test_flavors.py
index 45eeeb34b..13206b6f8 100644
--- a/nova/tests/api/openstack/compute/test_flavors.py
+++ b/nova/tests/api/openstack/compute/test_flavors.py
@@ -762,3 +762,37 @@ class DisabledFlavorsWithRealDBTest(test.TestCase):
self.req, self.disabled_type['flavorid'])['flavor']
self.assertEqual(flavor['name'], self.disabled_type['name'])
+
+
+class ParseIsPublicTest(test.TestCase):
+ def setUp(self):
+ super(ParseIsPublicTest, self).setUp()
+ self.controller = flavors.Controller()
+
+ def assertPublic(self, expected, is_public):
+ self.assertIs(expected, self.controller._parse_is_public(is_public),
+ '%s did not return %s' % (is_public, expected))
+
+ def test_None(self):
+ self.assertPublic(True, None)
+
+ def test_truthy(self):
+ self.assertPublic(True, True)
+ self.assertPublic(True, 't')
+ self.assertPublic(True, 'true')
+ self.assertPublic(True, 'yes')
+ self.assertPublic(True, '1')
+
+ def test_falsey(self):
+ self.assertPublic(False, False)
+ self.assertPublic(False, 'f')
+ self.assertPublic(False, 'false')
+ self.assertPublic(False, 'no')
+ self.assertPublic(False, '0')
+
+ def test_string_none(self):
+ self.assertPublic(None, 'none')
+
+ def test_other(self):
+ self.assertRaises(
+ webob.exc.HTTPBadRequest, self.assertPublic, None, 'other')
diff --git a/nova/tests/api/openstack/compute/test_servers.py b/nova/tests/api/openstack/compute/test_servers.py
index 2744d620f..5d2118564 100644
--- a/nova/tests/api/openstack/compute/test_servers.py
+++ b/nova/tests/api/openstack/compute/test_servers.py
@@ -2436,7 +2436,7 @@ class ServersControllerCreateTest(test.TestCase):
{'device_name': 'foo3', 'delete_on_termination': 'invalid'},
{'device_name': 'foo4', 'delete_on_termination': 0},
{'device_name': 'foo5', 'delete_on_termination': False}]
- expected_dbm = [
+ expected_bdm = [
{'device_name': 'foo1', 'delete_on_termination': True},
{'device_name': 'foo2', 'delete_on_termination': True},
{'device_name': 'foo3', 'delete_on_termination': False},
@@ -2446,7 +2446,7 @@ class ServersControllerCreateTest(test.TestCase):
old_create = compute_api.API.create
def create(*args, **kwargs):
- self.assertEqual(kwargs['block_device_mapping'], expected_dbm)
+ self.assertEqual(expected_bdm, kwargs['block_device_mapping'])
return old_create(*args, **kwargs)
self.stubs.Set(compute_api.API, 'create', create)
diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py
index 0a78020bd..24566d4d0 100644
--- a/nova/tests/api/openstack/fakes.py
+++ b/nova/tests/api/openstack/fakes.py
@@ -611,8 +611,8 @@ def stub_snapshot(id, **kwargs):
return snapshot
-def stub_snapshot_create(self, context, volume_id, name, description):
- return stub_snapshot(100, volume_id=volume_id, display_name=name,
+def stub_snapshot_create(self, context, volume, name, description):
+ return stub_snapshot(100, volume_id=volume['id'], display_name=name,
display_description=description)
diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py
index d185c6867..9560fc78c 100644
--- a/nova/tests/compute/test_compute.py
+++ b/nova/tests/compute/test_compute.py
@@ -6050,11 +6050,8 @@ class ComputeAPITestCase(BaseTestCase):
name = 'test_resize_new_flavor'
flavorid = 11
- memory_mb = 128
- root_gb = 0
- vcpus = 1
- flavors.create(name, memory_mb, vcpus, root_gb, 0,
- flavorid, 0, 1.0, True)
+ flavors.create(name, 128, 1, 0, ephemeral_gb=0, flavorid=flavorid,
+ swap=0, rxtx_factor=1.0, is_public=True)
flavors.destroy(name)
self.assertRaises(exception.FlavorNotFound, self.compute_api.resize,
self.context, instance, flavorid)
@@ -6082,11 +6079,8 @@ class ComputeAPITestCase(BaseTestCase):
name = 'test_resize_with_big_mem'
flavorid = 11
- memory_mb = 102400
- root_gb = 0
- vcpus = 1
- flavors.create(name, memory_mb, vcpus, root_gb, 0,
- flavorid, 0, 1.0, True)
+ flavors.create(name, 102400, 1, 0, ephemeral_gb=0, flavorid=flavorid,
+ swap=0, rxtx_factor=1.0, is_public=True)
self.assertRaises(exception.TooManyInstances, self.compute_api.resize,
self.context, instance, flavorid)
@@ -6096,11 +6090,9 @@ class ComputeAPITestCase(BaseTestCase):
def test_resize_revert_deleted_flavor_fails(self):
orig_name = 'test_resize_revert_orig_flavor'
orig_flavorid = 11
- memory_mb = 128
- root_gb = 0
- vcpus = 1
- flavors.create(orig_name, memory_mb, vcpus, root_gb, 0,
- orig_flavorid, 0, 1.0, True)
+ flavors.create(orig_name, 128, 1, 0, ephemeral_gb=0,
+ flavorid=orig_flavorid, swap=0, rxtx_factor=1.0,
+ is_public=True)
instance = self._create_fake_instance(type_name=orig_name)
instance = db.instance_get_by_uuid(self.context, instance['uuid'])
diff --git a/nova/tests/integrated/api_samples/os-volumes/snapshot-create-resp.json.tpl b/nova/tests/integrated/api_samples/os-volumes/snapshot-create-resp.json.tpl
index 73cd02d9d..ddffd97a3 100644
--- a/nova/tests/integrated/api_samples/os-volumes/snapshot-create-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/os-volumes/snapshot-create-resp.json.tpl
@@ -6,27 +6,6 @@
"id": 100,
"size": 100,
"status": "available",
- "volumeId": {
- "attach_status": "attached",
- "availability_zone": "fakeaz",
- "created_at": "%(timestamp)s",
- "display_description": "displaydesc",
- "display_name": "displayname",
- "host": "fakehost",
- "id": "%(uuid)s",
- "instance_uuid": "fakeuuid",
- "mountpoint": "/",
- "name": "vol name",
- "project_id": "fakeproject",
- "size": 1,
- "snapshot_id": null,
- "status": "fakestatus",
- "user_id": "fakeuser",
- "volume_metadata": [],
- "volume_type": {
- "name": "vol_type_name"
- },
- "volume_type_id": "fakevoltype"
- }
+ "volumeId": "%(uuid)s"
}
}
diff --git a/nova/tests/integrated/api_samples/os-volumes/snapshot-create-resp.xml.tpl b/nova/tests/integrated/api_samples/os-volumes/snapshot-create-resp.xml.tpl
index aa713311f..d75ae7ddd 100644
--- a/nova/tests/integrated/api_samples/os-volumes/snapshot-create-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/os-volumes/snapshot-create-resp.xml.tpl
@@ -1,2 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
-<snapshot status="available" displayDescription="%(description)s" displayName="%(snapshot_name)s" volumeId="{'instance_uuid': 'fakeuuid', 'status': 'fakestatus', 'user_id': 'fakeuser', 'name': 'vol name', 'display_name': 'displayname', 'availability_zone': 'fakeaz', 'created_at': datetime.datetime(1999, 1, 1, 1, 1, 1), 'attach_status': 'attached', 'display_description': 'displaydesc', 'host': 'fakehost', 'volume_type_id': 'fakevoltype', 'volume_metadata': [], 'volume_type': {'name': 'vol_type_name'}, 'snapshot_id': None, 'mountpoint': '/', 'project_id': 'fakeproject', 'id': u'521752a6-acf6-4b2d-bc7a-119f9148cd8c', 'size': 1}" id="100" createdAt="%(timestamp)s" size="100"/>
+<snapshot status="available" displayDescription="%(description)s" displayName="%(snapshot_name)s" volumeId="521752a6-acf6-4b2d-bc7a-119f9148cd8c" id="100" createdAt="%(timestamp)s" size="100"/>
diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py
index bf7cc003a..13a1dedff 100644
--- a/nova/tests/test_db_api.py
+++ b/nova/tests/test_db_api.py
@@ -1024,6 +1024,34 @@ class DbApiTestCase(DbTestCase):
self.assertEqual(db.network_in_use_on_host(ctxt, 1, 'foo'), True)
self.assertEqual(db.network_in_use_on_host(ctxt, 1, 'bar'), False)
+ def test_instance_floating_address_get_all(self):
+ ctxt = context.get_admin_context()
+
+ instance1 = db.instance_create(ctxt, {'host': 'h1', 'hostname': 'n1'})
+ instance2 = db.instance_create(ctxt, {'host': 'h2', 'hostname': 'n2'})
+
+ fixed_addresses = ['1.1.1.1', '1.1.1.2', '1.1.1.3']
+ float_addresses = ['2.1.1.1', '2.1.1.2', '2.1.1.3']
+ instance_uuids = [instance1['uuid'], instance1['uuid'],
+ instance2['uuid']]
+
+ for fixed_addr, float_addr, instance_uuid in zip(fixed_addresses,
+ float_addresses,
+ instance_uuids):
+ db.fixed_ip_create(ctxt, {'address': fixed_addr,
+ 'instance_uuid': instance_uuid})
+ fixed_id = db.fixed_ip_get_by_address(ctxt, fixed_addr)['id']
+ db.floating_ip_create(ctxt,
+ {'address': float_addr,
+ 'fixed_ip_id': fixed_id})
+
+ real_float_addresses = \
+ db.instance_floating_address_get_all(ctxt, instance_uuids[0])
+ self.assertEqual(set(float_addresses[:2]), set(real_float_addresses))
+ real_float_addresses = \
+ db.instance_floating_address_get_all(ctxt, instance_uuids[2])
+ self.assertEqual(set([float_addresses[2]]), set(real_float_addresses))
+
def test_get_vol_mapping_non_admin(self):
ref = db.ec2_volume_create(self.context, 'fake-uuid')
ec2_id = db.get_ec2_volume_id_by_uuid(self.context, 'fake-uuid')
@@ -1100,67 +1128,6 @@ class DbApiTestCase(DbTestCase):
_compare(bw_usages[2], expected_bw_usages[2])
timeutils.clear_time_override()
- def test_key_pair_create(self):
- ctxt = context.get_admin_context()
- values = {'name': 'test_keypair', 'public_key': 'test-public-key',
- 'user_id': 'test_user_id', 'fingerprint': 'test_fingerprint'}
- keypair = db.key_pair_create(ctxt, values)
- self.assertNotEqual(None, keypair)
- for name, value in values.iteritems():
- self.assertEqual(keypair.get(name), value)
-
- def test_key_pair_create_with_duplicate_name(self):
- ctxt = context.get_admin_context()
- values = {'name': 'test_keypair', 'public_key': 'test-public-key',
- 'user_id': 'test_user_id', 'fingerprint': 'test_fingerprint'}
- keypair = db.key_pair_create(ctxt, values)
- self.assertRaises(exception.KeyPairExists,
- db.key_pair_create, ctxt, values)
-
- def test_admin_get_deleted_keypair(self):
- # Test deleted keypair can be read by admin user.
- ctxt = context.get_admin_context()
- values = {'name': 'test_keypair', 'public_key': 'test-public-key',
- 'user_id': 'test_user_id', 'fingerprint': 'test_fingerprint'}
- keypair = db.key_pair_create(ctxt, values)
- db.key_pair_destroy(ctxt, keypair['user_id'], keypair['name'])
-
- # Raise exception when read_deleted is 'no'.
- self.assertRaises(exception.KeypairNotFound, db.key_pair_get, ctxt,
- keypair['user_id'], keypair['name'])
- ctxt = ctxt.elevated(read_deleted='yes')
- db_keypair = db.key_pair_get(ctxt, keypair['user_id'],
- keypair['name'])
- self.assertEqual(db_keypair['name'], keypair['name'])
- self.assertEqual(db_keypair['deleted'], keypair['id'])
-
- def test_admin_get_all_keypairs_including_deleted(self):
- # Test all deleted/non-deleted keypairs can be read by admin user.
- ctxt = context.get_admin_context()
- keypair1_values = {'name': 'test_keypair1',
- 'public_key': 'test-public-key1',
- 'user_id': 'test_user_id',
- 'fingerprint': 'test_fingerprint1'}
- keypair2_values = {'name': 'test_keypair2',
- 'public_key': 'test-public-key2',
- 'user_id': 'test_user_id',
- 'fingerprint': 'test_fingerprint2'}
- keypair1 = db.key_pair_create(ctxt, keypair1_values)
- keypair2 = db.key_pair_create(ctxt, keypair2_values)
- db.key_pair_destroy(ctxt, keypair1['user_id'], keypair1['name'])
- db.key_pair_destroy(ctxt, keypair2['user_id'], keypair2['name'])
- # Returns non-deleted keypairs.
- result = db.key_pair_get_all_by_user(ctxt, keypair1['user_id'])
- self.assertEqual(result, [])
- ctxt = ctxt.elevated(read_deleted='yes')
- # Returns deleted and non-deleted keypairs.
- db_keypairs = db.key_pair_get_all_by_user(ctxt, keypair1['user_id'])
- expected_deleted_ids = [keypair1['id'], keypair2['id']]
- expected_keypair_names = [keypair1['name'], keypair2['name']]
- for keypair in db_keypairs:
- self.assertTrue(keypair['name'] in expected_keypair_names)
- self.assertTrue(keypair['deleted'] in expected_deleted_ids)
-
def _get_fake_aggr_values():
return {'name': 'fake_aggregate'}
@@ -3604,6 +3571,114 @@ class VirtualInterfaceTestCase(test.TestCase, ModelsObjectComparatorMixin):
self._assertEqualListsOfObjects(vifs, real_vifs)
+class KeyPairTestCase(test.TestCase, ModelsObjectComparatorMixin):
+ def setUp(self):
+ super(KeyPairTestCase, self).setUp()
+ self.ctxt = context.get_admin_context()
+
+ def _create_key_pair(self, values):
+ return db.key_pair_create(self.ctxt, values)
+
+ def test_key_pair_create(self):
+ param = {
+ 'name': 'test_1',
+ 'user_id': 'test_user_id_1',
+ 'public_key': 'test_public_key_1',
+ 'fingerprint': 'test_fingerprint_1'
+ }
+ key_pair = self._create_key_pair(param)
+
+ self.assertTrue(key_pair['id'] is not None)
+ ignored_keys = ['deleted', 'created_at', 'updated_at',
+ 'deleted_at', 'id']
+ self._assertEqualObjects(key_pair, param, ignored_keys)
+
+ def test_key_pair_create_with_duplicate_name(self):
+ params = {'name': 'test_name', 'user_id': 'test_user_id'}
+ self._create_key_pair(params)
+ self.assertRaises(exception.KeyPairExists, self._create_key_pair,
+ params)
+
+ def test_key_pair_get(self):
+ params = [
+ {'name': 'test_1', 'user_id': 'test_user_id_1'},
+ {'name': 'test_2', 'user_id': 'test_user_id_2'},
+ {'name': 'test_3', 'user_id': 'test_user_id_3'}
+ ]
+ key_pairs = [self._create_key_pair(p) for p in params]
+
+ for key in key_pairs:
+ real_key = db.key_pair_get(self.ctxt, key['user_id'], key['name'])
+ self._assertEqualObjects(key, real_key)
+
+ def test_key_pair_get_no_results(self):
+ param = {'name': 'test_1', 'user_id': 'test_user_id_1'}
+ self.assertRaises(exception.KeypairNotFound, db.key_pair_get,
+ self.ctxt, param['user_id'], param['name'])
+
+ def test_key_pair_get_deleted(self):
+ param = {'name': 'test_1', 'user_id': 'test_user_id_1'}
+ key_pair_created = self._create_key_pair(param)
+
+ db.key_pair_destroy(self.ctxt, param['user_id'], param['name'])
+ self.assertRaises(exception.KeypairNotFound, db.key_pair_get,
+ self.ctxt, param['user_id'], param['name'])
+
+ ctxt = self.ctxt.elevated(read_deleted='yes')
+ key_pair_deleted = db.key_pair_get(ctxt, param['user_id'],
+ param['name'])
+ ignored_keys = ['deleted', 'created_at', 'updated_at', 'deleted_at']
+ self._assertEqualObjects(key_pair_deleted, key_pair_created,
+ ignored_keys)
+ self.assertEqual(key_pair_deleted['deleted'], key_pair_deleted['id'])
+
+ def test_key_pair_get_all_by_user(self):
+ params = [
+ {'name': 'test_1', 'user_id': 'test_user_id_1'},
+ {'name': 'test_2', 'user_id': 'test_user_id_1'},
+ {'name': 'test_3', 'user_id': 'test_user_id_2'}
+ ]
+ key_pairs_user_1 = [self._create_key_pair(p) for p in params
+ if p['user_id'] == 'test_user_id_1']
+ key_pairs_user_2 = [self._create_key_pair(p) for p in params
+ if p['user_id'] == 'test_user_id_2']
+
+ real_keys_1 = db.key_pair_get_all_by_user(self.ctxt, 'test_user_id_1')
+ real_keys_2 = db.key_pair_get_all_by_user(self.ctxt, 'test_user_id_2')
+
+ self._assertEqualListsOfObjects(key_pairs_user_1, real_keys_1)
+ self._assertEqualListsOfObjects(key_pairs_user_2, real_keys_2)
+
+ def test_key_pair_count_by_user(self):
+ params = [
+ {'name': 'test_1', 'user_id': 'test_user_id_1'},
+ {'name': 'test_2', 'user_id': 'test_user_id_1'},
+ {'name': 'test_3', 'user_id': 'test_user_id_2'}
+ ]
+ for p in params:
+ self._create_key_pair(p)
+
+ count_1 = db.key_pair_count_by_user(self.ctxt, 'test_user_id_1')
+ self.assertEqual(count_1, 2)
+
+ count_2 = db.key_pair_count_by_user(self.ctxt, 'test_user_id_2')
+ self.assertEqual(count_2, 1)
+
+ def test_key_pair_destroy(self):
+ param = {'name': 'test_1', 'user_id': 'test_user_id_1'}
+ self._create_key_pair(param)
+
+ db.key_pair_destroy(self.ctxt, param['user_id'], param['name'])
+ self.assertRaises(exception.KeypairNotFound, db.key_pair_get,
+ self.ctxt, param['user_id'], param['name'])
+
+ def test_key_pair_destroy_no_such_key(self):
+ param = {'name': 'test_1', 'user_id': 'test_user_id_1'}
+ self.assertRaises(exception.KeypairNotFound,
+ db.key_pair_destroy, self.ctxt,
+ param['user_id'], param['name'])
+
+
class ArchiveTestCase(test.TestCase):
def setUp(self):
diff --git a/nova/tests/test_instance_types.py b/nova/tests/test_instance_types.py
index 5afa4005f..e20845f1d 100644
--- a/nova/tests/test_instance_types.py
+++ b/nova/tests/test_instance_types.py
@@ -51,119 +51,6 @@ class InstanceTypeTestCase(test.TestCase):
"""return first instance type name."""
return flavors.get_all_types().keys()[0]
- def test_instance_type_create(self):
- # Ensure instance types can be created.
- name = 'Instance create test'
- flavor_id = '512'
-
- original_list = flavors.get_all_types()
-
- # create new type and make sure values stick
- inst_type = flavors.create(name, 256, 1, 120,
- flavorid=flavor_id)
- self.assertEqual(inst_type['flavorid'], flavor_id)
- self.assertEqual(inst_type['name'], name)
- self.assertEqual(inst_type['memory_mb'], 256)
- self.assertEqual(inst_type['vcpus'], 1)
- self.assertEqual(inst_type['root_gb'], 120)
- self.assertEqual(inst_type['ephemeral_gb'], 0)
- self.assertEqual(inst_type['swap'], 0)
- self.assertEqual(inst_type['rxtx_factor'], 1.0)
-
- # make sure new type shows up in list
- new_list = flavors.get_all_types()
- self.assertNotEqual(len(original_list), len(new_list),
- 'instance type was not created')
-
- def test_instance_type_create_then_delete(self):
- # Ensure instance types can be created.
- name = 'Small Flavor'
- flavorid = 'flavor1'
-
- original_list = flavors.get_all_types()
-
- # create new type and make sure values stick
- inst_type = flavors.create(name, 256, 1, 120, 100, flavorid)
- inst_type_id = inst_type['id']
- self.assertEqual(inst_type['flavorid'], flavorid)
- self.assertEqual(inst_type['name'], name)
- self.assertEqual(inst_type['memory_mb'], 256)
- self.assertEqual(inst_type['vcpus'], 1)
- self.assertEqual(inst_type['root_gb'], 120)
- self.assertEqual(inst_type['ephemeral_gb'], 100)
- self.assertEqual(inst_type['swap'], 0)
- self.assertEqual(inst_type['rxtx_factor'], 1.0)
-
- # make sure new type shows up in list
- new_list = flavors.get_all_types()
- self.assertNotEqual(len(original_list), len(new_list),
- 'instance type was not created')
-
- flavors.destroy(name)
- self.assertRaises(exception.InstanceTypeNotFound,
- flavors.get_instance_type, inst_type_id)
-
- # deleted instance should not be in list anymoer
- new_list = flavors.get_all_types()
- self.assertEqual(original_list, new_list)
-
- def test_instance_type_create_without_flavorid(self):
- name = 'Small Flavor'
- inst_type = flavors.create(name, 256, 1, 120, 100)
- self.assertNotEqual(inst_type['flavorid'], None)
- self.assertEqual(inst_type['name'], name)
- self.assertEqual(inst_type['memory_mb'], 256)
- self.assertEqual(inst_type['vcpus'], 1)
- self.assertEqual(inst_type['root_gb'], 120)
- self.assertEqual(inst_type['ephemeral_gb'], 100)
- self.assertEqual(inst_type['swap'], 0)
- self.assertEqual(inst_type['rxtx_factor'], 1.0)
-
- def test_instance_type_create_with_empty_flavorid(self):
- # Ensure that auto-generated uuid is assigned.
- name = 'Empty String ID Flavor'
- flavorid = ''
- inst_type = flavors.create(name, 256, 1, 120, 100, flavorid)
- self.assertEqual(len(inst_type['flavorid']), 36)
- self.assertEqual(inst_type['name'], name)
- self.assertEqual(inst_type['memory_mb'], 256)
- self.assertEqual(inst_type['vcpus'], 1)
- self.assertEqual(inst_type['root_gb'], 120)
- self.assertEqual(inst_type['ephemeral_gb'], 100)
- self.assertEqual(inst_type['swap'], 0)
- self.assertEqual(inst_type['rxtx_factor'], 1.0)
-
- def test_instance_type_create_with_custom_rxtx_factor(self):
- name = 'Custom RXTX Factor'
- inst_type = flavors.create(name, 256, 1, 120, 100,
- rxtx_factor=9.9)
- self.assertNotEqual(inst_type['flavorid'], None)
- self.assertEqual(inst_type['name'], name)
- self.assertEqual(inst_type['memory_mb'], 256)
- self.assertEqual(inst_type['vcpus'], 1)
- self.assertEqual(inst_type['root_gb'], 120)
- self.assertEqual(inst_type['ephemeral_gb'], 100)
- self.assertEqual(inst_type['swap'], 0)
- self.assertEqual(inst_type['rxtx_factor'], 9.9)
-
- def test_instance_type_create_with_special_characters(self):
- # Ensure instance types raises InvalidInput for invalid characters.
- name = "foo.bar!@#$%^-test_name"
- flavorid = "flavor1"
- self.assertRaises(exception.InvalidInput, flavors.create,
- name, 256, 1, 120, 100, flavorid)
-
- def test_instance_type_create_with_long_flavor_name(self):
- # Flavor name with 255 characters or less is valid.
- name = 'a' * 255
- inst_type = flavors.create(name, 64, 1, 120, flavorid=11)
- self.assertEqual(inst_type['name'], name)
-
- # Flavor name which is more than 255 characters will cause error.
- name = 'a' * 256
- self.assertRaises(exception.InvalidInput, flavors.create,
- name, 64, 1, 120, flavorid=11)
-
def test_add_instance_type_access(self):
user_id = 'fake'
project_id = 'fake'
@@ -233,55 +120,12 @@ class InstanceTypeTestCase(test.TestCase):
inst_types = flavors.get_all_types()
self.assertEqual(total_instance_types, len(inst_types))
- def test_invalid_create_args_should_fail(self):
- # Ensures that instance type creation fails with invalid args.
- invalid_sigs = [
- (('Zero memory', 0, 1, 10, 20, 'flavor1'), {}),
- (('Negative memory', -256, 1, 10, 20, 'flavor1'), {}),
- (('Non-integer memory', 'asdf', 1, 10, 20, 'flavor1'), {}),
-
- (('Zero vcpus', 256, 0, 10, 20, 'flavor1'), {}),
- (('Negative vcpus', 256, -1, 10, 20, 'flavor1'), {}),
- (('Non-integer vcpus', 256, 'a', 10, 20, 'flavor1'), {}),
-
- (('Negative storage', 256, 1, -1, 20, 'flavor1'), {}),
- (('Non-integer storage', 256, 1, 'a', 20, 'flavor1'), {}),
-
- (('Negative swap', 256, 1, 10, 20, 'flavor1'), {'swap': -1}),
- (('Non-integer swap', 256, 1, 10, 20, 'flavor1'), {'swap': -1}),
-
- (('Negative rxtx_factor', 256, 1, 10, 20, 'f1'),
- {'rxtx_factor': -1}),
- (('Non-integer rxtx_factor', 256, 1, 10, 20, 'f1'),
- {'rxtx_factor': "d"}),
- ]
-
- for (args, kwargs) in invalid_sigs:
- self.assertRaises(exception.InvalidInput,
- flavors.create, *args, **kwargs)
-
def test_non_existent_inst_type_shouldnt_delete(self):
# Ensures that instance type creation fails with invalid args.
self.assertRaises(exception.InstanceTypeNotFoundByName,
flavors.destroy,
'unknown_flavor')
- def test_duplicate_names_fail(self):
- # Ensures that name duplicates raise InstanceTypeCreateFailed.
- name = 'some_name'
- flavors.create(name, 256, 1, 120, 200, 'flavor1')
- self.assertRaises(exception.InstanceTypeExists,
- flavors.create,
- name, 256, 1, 120, 200, 'flavor2')
-
- def test_duplicate_flavorids_fail(self):
- # Ensures that flavorid duplicates raise InstanceTypeCreateFailed.
- flavorid = 'flavor1'
- flavors.create('name one', 256, 1, 120, 200, flavorid)
- self.assertRaises(exception.InstanceTypeIdExists,
- flavors.create,
- 'name two', 256, 1, 120, 200, flavorid)
-
def test_will_not_destroy_with_no_name(self):
# Ensure destroy said path of no name raises error.
self.assertRaises(exception.InstanceTypeNotFoundByName,
@@ -452,3 +296,143 @@ class InstanceTypeFilteringTest(test.TestCase):
filters = dict(min_memory_mb=16384, min_root_gb=80)
expected = ['m1.xlarge']
self.assertFilterResults(filters, expected)
+
+
+class CreateInstanceTypeTest(test.TestCase):
+
+ def assertInvalidInput(self, *create_args, **create_kwargs):
+ self.assertRaises(exception.InvalidInput, flavors.create,
+ *create_args, **create_kwargs)
+
+ def test_name_with_special_characters(self):
+ # Names can contain [a-zA-Z0-9_.- ]
+ flavors.create('_foo.bar-123', 64, 1, 120)
+
+ # Ensure instance types raises InvalidInput for invalid characters.
+ self.assertInvalidInput('foobar#', 64, 1, 120)
+
+ def test_name_length_checks(self):
+ MAX_LEN = 255
+
+ # Flavor name with 255 characters or less is valid.
+ flavors.create('a' * MAX_LEN, 64, 1, 120)
+
+ # Flavor name which is more than 255 characters will cause error.
+ self.assertInvalidInput('a' * (MAX_LEN + 1), 64, 1, 120)
+
+ # Flavor name which is empty should cause an error
+ self.assertInvalidInput('', 64, 1, 120)
+
+ def test_memory_must_be_positive_integer(self):
+ self.assertInvalidInput('flavor1', 'foo', 1, 120)
+ self.assertInvalidInput('flavor1', -1, 1, 120)
+ self.assertInvalidInput('flavor1', 0, 1, 120)
+ flavors.create('flavor1', 1, 1, 120)
+
+ def test_vcpus_must_be_positive_integer(self):
+ self.assertInvalidInput('flavor`', 64, 'foo', 120)
+ self.assertInvalidInput('flavor1', 64, -1, 120)
+ self.assertInvalidInput('flavor1', 64, 0, 120)
+ flavors.create('flavor1', 64, 1, 120)
+
+ def test_root_gb_must_be_nonnegative_integer(self):
+ self.assertInvalidInput('flavor1', 64, 1, 'foo')
+ self.assertInvalidInput('flavor1', 64, 1, -1)
+ flavors.create('flavor1', 64, 1, 0)
+ flavors.create('flavor2', 64, 1, 120)
+
+ def test_swap_must_be_nonnegative_integer(self):
+ self.assertInvalidInput('flavor1', 64, 1, 120, swap='foo')
+ self.assertInvalidInput('flavor1', 64, 1, 120, swap=-1)
+ flavors.create('flavor1', 64, 1, 120, swap=0)
+ flavors.create('flavor2', 64, 1, 120, swap=1)
+
+ def test_rxtx_factor_must_be_positive_float(self):
+ self.assertInvalidInput('flavor1', 64, 1, 120, rxtx_factor='foo')
+ self.assertInvalidInput('flavor1', 64, 1, 120, rxtx_factor=-1.0)
+ self.assertInvalidInput('flavor1', 64, 1, 120, rxtx_factor=0.0)
+
+ flavor = flavors.create('flavor1', 64, 1, 120, rxtx_factor=1.0)
+ self.assertEqual(1.0, flavor['rxtx_factor'])
+
+ flavor = flavors.create('flavor2', 64, 1, 120, rxtx_factor=1.1)
+ self.assertEqual(1.1, flavor['rxtx_factor'])
+
+ def test_is_public_must_be_valid_bool_string(self):
+ self.assertInvalidInput('flavor1', 64, 1, 120, is_public='foo')
+
+ flavors.create('flavor1', 64, 1, 120, is_public='TRUE')
+ flavors.create('flavor2', 64, 1, 120, is_public='False')
+ flavors.create('flavor3', 64, 1, 120, is_public='Yes')
+ flavors.create('flavor4', 64, 1, 120, is_public='No')
+ flavors.create('flavor5', 64, 1, 120, is_public='Y')
+ flavors.create('flavor6', 64, 1, 120, is_public='N')
+ flavors.create('flavor7', 64, 1, 120, is_public='1')
+ flavors.create('flavor8', 64, 1, 120, is_public='0')
+ flavors.create('flavor9', 64, 1, 120, is_public='true')
+
+ def test_flavorid_populated(self):
+ flavor1 = flavors.create('flavor1', 64, 1, 120)
+ self.assertIsNot(None, flavor1['flavorid'])
+
+ flavor2 = flavors.create('flavor2', 64, 1, 120, flavorid='')
+ self.assertIsNot(None, flavor2['flavorid'])
+
+ flavor3 = flavors.create('flavor3', 64, 1, 120, flavorid='foo')
+ self.assertEqual('foo', flavor3['flavorid'])
+
+ def test_default_values(self):
+ flavor1 = flavors.create('flavor1', 64, 1, 120)
+
+ self.assertIsNot(None, flavor1['flavorid'])
+ self.assertEqual(flavor1['ephemeral_gb'], 0)
+ self.assertEqual(flavor1['swap'], 0)
+ self.assertEqual(flavor1['rxtx_factor'], 1.0)
+
+ def test_basic_create(self):
+ # Ensure instance types can be created.
+ original_list = flavors.get_all_types()
+
+ # Create new type and make sure values stick
+ flavor = flavors.create('flavor', 64, 1, 120)
+ self.assertEqual(flavor['name'], 'flavor')
+ self.assertEqual(flavor['memory_mb'], 64)
+ self.assertEqual(flavor['vcpus'], 1)
+ self.assertEqual(flavor['root_gb'], 120)
+
+ # Ensure new type shows up in list
+ new_list = flavors.get_all_types()
+ self.assertNotEqual(len(original_list), len(new_list),
+ 'flavor was not created')
+
+ def test_create_then_delete(self):
+ original_list = flavors.get_all_types()
+
+ flavor = flavors.create('flavor', 64, 1, 120)
+
+ # Ensure new type shows up in list
+ new_list = flavors.get_all_types()
+ self.assertNotEqual(len(original_list), len(new_list),
+ 'instance type was not created')
+
+ flavors.destroy('flavor')
+ self.assertRaises(exception.InstanceTypeNotFound,
+ flavors.get_instance_type, flavor['id'])
+
+ # Deleted instance should not be in list anymore
+ new_list = flavors.get_all_types()
+ self.assertEqual(original_list, new_list)
+
+ def test_duplicate_names_fail(self):
+ # Ensures that name duplicates raise InstanceTypeCreateFailed.
+ flavors.create('flavor', 256, 1, 120, 200, 'flavor1')
+ self.assertRaises(exception.InstanceTypeExists,
+ flavors.create,
+ 'flavor', 64, 1, 120)
+
+ def test_duplicate_flavorids_fail(self):
+ # Ensures that flavorid duplicates raise InstanceTypeCreateFailed.
+ flavors.create('flavor1', 64, 1, 120, flavorid='flavorid')
+ self.assertRaises(exception.InstanceTypeIdExists,
+ flavors.create,
+ 'flavor2', 64, 1, 120, flavorid='flavorid')
diff --git a/nova/tests/test_utils.py b/nova/tests/test_utils.py
index 6b7af48fc..39db03f3e 100644
--- a/nova/tests/test_utils.py
+++ b/nova/tests/test_utils.py
@@ -276,28 +276,6 @@ class GenericUtilsTestCase(test.TestCase):
hostname = "<}\x1fh\x10e\x08l\x02l\x05o\x12!{>"
self.assertEqual("hello", utils.sanitize_hostname(hostname))
- def test_bool_from_str(self):
- self.assertTrue(utils.bool_from_str('1'))
- self.assertTrue(utils.bool_from_str('2'))
- self.assertTrue(utils.bool_from_str('-1'))
- self.assertTrue(utils.bool_from_str('true'))
- self.assertTrue(utils.bool_from_str('True'))
- self.assertTrue(utils.bool_from_str('tRuE'))
- self.assertTrue(utils.bool_from_str('yes'))
- self.assertTrue(utils.bool_from_str('Yes'))
- self.assertTrue(utils.bool_from_str('YeS'))
- self.assertTrue(utils.bool_from_str('y'))
- self.assertTrue(utils.bool_from_str('Y'))
- self.assertFalse(utils.bool_from_str('False'))
- self.assertFalse(utils.bool_from_str('false'))
- self.assertFalse(utils.bool_from_str('no'))
- self.assertFalse(utils.bool_from_str('No'))
- self.assertFalse(utils.bool_from_str('n'))
- self.assertFalse(utils.bool_from_str('N'))
- self.assertFalse(utils.bool_from_str('0'))
- self.assertFalse(utils.bool_from_str(None))
- self.assertFalse(utils.bool_from_str('junk'))
-
def test_read_cached_file(self):
self.mox.StubOutWithMock(os.path, "getmtime")
os.path.getmtime(mox.IgnoreArg()).AndReturn(1)
diff --git a/nova/utils.py b/nova/utils.py
index 3af79a6df..3020781c8 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -597,19 +597,6 @@ def parse_server_string(server_str):
return ('', '')
-def bool_from_str(val):
- """Convert a string representation of a bool into a bool value."""
-
- if not val:
- return False
- try:
- return True if int(val) else False
- except ValueError:
- return val.lower() == 'true' or \
- val.lower() == 'yes' or \
- val.lower() == 'y'
-
-
def is_int_like(val):
"""Check if a value looks like an int."""
try:
diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py
index 30cee234a..4cd2b2ab5 100644
--- a/nova/virt/xenapi/vm_utils.py
+++ b/nova/virt/xenapi/vm_utils.py
@@ -45,6 +45,7 @@ from nova.image import glance
from nova.openstack.common import excutils
from nova.openstack.common import log as logging
from nova.openstack.common import processutils
+from nova.openstack.common import strutils
from nova import utils
from nova.virt import configdrive
from nova.virt.disk import api as disk
@@ -998,7 +999,7 @@ def _create_image(context, session, instance, name_label, image_id,
elif cache_images == 'some':
sys_meta = utils.metadata_to_dict(instance['system_metadata'])
try:
- cache = utils.bool_from_str(sys_meta['image_cache_in_nova'])
+ cache = strutils.bool_from_string(sys_meta['image_cache_in_nova'])
except KeyError:
cache = False
elif cache_images == 'none':
@@ -1091,7 +1092,8 @@ def _image_uses_bittorrent(context, instance):
elif xenapi_torrent_images == 'some':
sys_meta = utils.metadata_to_dict(instance['system_metadata'])
try:
- bittorrent = utils.bool_from_str(sys_meta['image_bittorrent'])
+ bittorrent = strutils.bool_from_string(
+ sys_meta['image_bittorrent'])
except KeyError:
pass
elif xenapi_torrent_images == 'none':
diff --git a/openstack-common.conf b/openstack-common.conf
index 4412c09ac..ad48a188a 100644
--- a/openstack-common.conf
+++ b/openstack-common.conf
@@ -25,6 +25,7 @@ module=policy
module=processutils
module=rootwrap
module=rpc
+module=strutils
module=timeutils
module=uuidutils
module=version